001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nicolas Chapurlat <nchapurlat@nuxeo.com>
016 */
017
018package org.nuxeo.ecm.core.io.registry.context;
019
020import java.io.Closeable;
021import java.io.IOException;
022import java.util.List;
023import java.util.Locale;
024import java.util.Map;
025import java.util.Set;
026
027import org.nuxeo.ecm.core.api.CoreSession;
028import org.nuxeo.ecm.core.api.DocumentModel;
029import org.nuxeo.ecm.core.io.registry.MarshallingException;
030import org.nuxeo.ecm.core.io.registry.context.RenderingContextImpl.RenderingContextBuilder;
031
032/**
033 * A context used to deliver parameter to marshallers during a marshalling request.
034 * <p>
035 * Use {@link CtxBuilder} to create your context.
036 * </p>
037 * <p>
038 * When a {@link RenderingContext} is automatically provided from an HttpServletRequest, it contains request parameters,
039 * headers and request attribute.
040 * </p>
041 * <p>
042 * To get/set parameter values, use:
043 * <ul>
044 * <li>{@link RenderingContext#getParameter(String)}</li>
045 * <li>{@link RenderingContext#getParameters(String)}</li>
046 * <li>{@link RenderingContext#getBooleanParameter(String)}</li>
047 * <li>{@link RenderingContext#getAllParameters()}</li>
048 * <li>{@link RenderingContext#addParameterValues(String, Object...)}</li>
049 * <li>{@link RenderingContext#addParameterListValues(String, List)}</li>
050 * <li>{@link RenderingContext#setParameterValues(String, Object...)}</li>
051 * <li>{@link RenderingContext#setParameterListValues(String, List)}</li>
052 * </ul>
053 * </p>
054 * <p>
055 * To manage document properties, entity enrichers or properties fetching, use:
056 * <ul>
057 * <li>{@link RenderingContext#getProperties()}</li>
058 * <li>{@link RenderingContext#getEnrichers(String)}</li>
059 * <li>{@link RenderingContext#getFetched(String)}</li>
060 * </ul>
061 * </p>
062 * <p>
063 * To manage infinite loop when calling a marshaller from another marshaller, use:
064 * <ul>
065 * <li>{@link RenderingContext#wrap()} -> {@link WrappedContext#controlDepth()}</li>
066 * </ul>
067 * Example:
068 *
069 * <pre>
070 * // This will control infinite loop in this marshaller
071 * try (Closeable resource = ctx.wrap().controlDepth().open()) {
072 *     // call another marshaller to fetch the desired property here
073 * } catch (MaxDepthReachedException mdre) {
074 *     // do not call the other marshaller
075 * }
076 * </pre>
077 *
078 * </p>
079 *
080 * @since 7.2.
081 */
082public interface RenderingContext {
083
084    public static final Locale DEFAULT_LOCALE = Locale.ENGLISH;
085
086    public static final String DEFAULT_URL = "http://fake-url.nuxeo.com/";
087
088    /**
089     * Gets the requested {@link Locale}.
090     *
091     * @since 7.2
092     */
093    public Locale getLocale();
094
095    /**
096     * Gets the current base url.
097     *
098     * @since 7.2
099     */
100    public String getBaseUrl();
101
102    /**
103     * Gets the current {@link CoreSession} or try to create one.
104     *
105     * @param document may be null, if present, this method search for a session in the document.
106     * @return The current {@link CoreSession} if it exists. null otherwise.
107     * @throws MarshallingException if no session could be created or found.
108     * @since 7.2
109     */
110    public SessionWrapper getSession(DocumentModel document) throws MarshallingException;
111
112    /**
113     * Provides a {@link CoreSession} to marshallers.
114     * <p>
115     * For example: a {@link CoreSession} from the request context.
116     * </p>
117     *
118     * @param session The existing {@link CoreSession} which lifecycle is managed outside the marshalling context.
119     * @since 7.2
120     */
121    public void setExistingSession(CoreSession session);
122
123    /**
124     * Get all document properties. This will aggregate all values from parameters "properties", "X-NXproperties" and
125     * "X-NXDocumentProperties". This supports value separated by comma.
126     *
127     * @return All document properties.
128     * @since 7.2
129     */
130    public Set<String> getProperties();
131
132    /**
133     * Get all properties to fetch for a given entity type. This will aggregate all values from parameters
134     * "fetch.entity" and "X-NXfetch.entity". This supports value separated by comma.
135     *
136     * @param entity The type of the entity on which you want to fetch properties.
137     * @return All properties to fetch.
138     * @since 7.2
139     */
140    public Set<String> getFetched(String entity);
141
142    /**
143     * Get all properties to translate for a given entity type. This will aggregate all values from parameters
144     * "translate.entity" and "X-NXtranslate.entity". This supports value separated by comma.
145     *
146     * @param entity The type of the entity on which you want to fetch properties.
147     * @return All properties to fetch.
148     * @since 7.2
149     */
150    public Set<String> getTranslated(String entity);
151
152    /**
153     * Get all enrichers to activate on the given entity type. This will aggregate all values from parameters
154     * "enrichers.entity", "X-NXenrichers.entity" and "X-NXContext-Category". This supports value separated by comma.
155     *
156     * @param entity The type of the entity on which you want to activate enrichers.
157     * @return All enrichers to activate.
158     * @since 7.2
159     */
160    public Set<String> getEnrichers(String entity);
161
162    /**
163     * see {@link WrappedContext}
164     *
165     * @return A new {@link WrappedContext}
166     * @since 7.2
167     */
168    public WrappedContext wrap();
169
170    /**
171     * Get the casted parameter value for a given name. If multiple are available, the first found is returned.
172     *
173     * @param name The parameter name.
174     * @return The first parameter value, null if no parameter are availble.
175     * @since 7.2
176     */
177    public <T> T getParameter(String name);
178
179    /**
180     * see {@link #getParameter(String)}
181     *
182     * @return true is the parameter exists and if it's Boolean.TRUE or "true", false otherwise.
183     */
184    public boolean getBooleanParameter(String name);
185
186    /**
187     * Get the casted parameter values for a given name.
188     *
189     * @param name The parameter name.
190     * @return The parameter values.
191     * @since 7.2
192     */
193    public <T> List<T> getParameters(String name);
194
195    /**
196     * Get all parameter in this context except wrapped parameters.
197     *
198     * @return All parameter's names and their values.
199     * @since 7.2
200     */
201    public Map<String, List<Object>> getAllParameters();
202
203    /**
204     * @see #setParameterListValues(String, List)
205     * @since 7.2
206     */
207    public void setParameterValues(String name, Object... values);
208
209    /**
210     * Push values in the context with a given name. Please note that this method remove any value for the given name.
211     *
212     * @param name The parameter name.
213     * @param values The parameter values.
214     * @since 7.2
215     */
216    public void setParameterListValues(String name, List<Object> values);
217
218    /**
219     * @see #addParameterListValues(String, List)
220     * @since 7.2
221     */
222    public void addParameterValues(String name, Object... values);
223
224    /**
225     * Add values in the context with a given name. Please note that this method keep current values for the given name.
226     *
227     * @param name The parameter name.
228     * @param values The parameter values.
229     * @since 7.2
230     */
231    public void addParameterListValues(String name, List<Object> values);
232
233    /**
234     * {@link RenderingContext} builder.
235     * <p>
236     * RenderingContext ctx = CtxBuilder.base("http://mine.nuxeo.com/nuxeo").locale(Locale.ENGLISH).param("name",
237     * "value1", "value2").get();
238     * </p>
239     *
240     * @since 7.2
241     */
242    public static final class CtxBuilder {
243        private CtxBuilder() {
244        }
245
246        public static RenderingContextBuilder builder() {
247            return new RenderingContextBuilder();
248        }
249
250        public static RenderingContextBuilder base(String url) {
251            RenderingContextBuilder builder = new RenderingContextBuilder();
252            return builder.base(url);
253        }
254
255        public static RenderingContextBuilder locale(Locale locale) {
256            RenderingContextBuilder builder = new RenderingContextBuilder();
257            return builder.locale(locale);
258        }
259
260        public static RenderingContextBuilder session(CoreSession session) {
261            RenderingContextBuilder builder = new RenderingContextBuilder();
262            return builder.session(session);
263        }
264
265        public static RenderingContextBuilder param(String name, Object value) {
266            RenderingContextBuilder builder = new RenderingContextBuilder();
267            return builder.param(name, value);
268        }
269
270        public static RenderingContextBuilder paramValues(String name, Object... values) {
271            RenderingContextBuilder builder = new RenderingContextBuilder();
272            return builder.paramValues(name, values);
273        }
274
275        public static RenderingContextBuilder paramList(String name, List<Object> values) {
276            RenderingContextBuilder builder = new RenderingContextBuilder();
277            return builder.paramList(name, values);
278        }
279
280        public static RenderingContextBuilder properties(String... schemaName) {
281            RenderingContextBuilder builder = new RenderingContextBuilder();
282            return builder.properties(schemaName);
283        }
284
285        public static RenderingContextBuilder fetch(String entityType, String... propertyName) {
286            RenderingContextBuilder builder = new RenderingContextBuilder();
287            return builder.fetch(entityType, propertyName);
288        }
289
290        public static RenderingContextBuilder fetchInDoc(String... propertyName) {
291            RenderingContextBuilder builder = new RenderingContextBuilder();
292            return builder.fetchInDoc(propertyName);
293        }
294
295        public static RenderingContextBuilder translate(String entityType, String... propertyName) {
296            RenderingContextBuilder builder = new RenderingContextBuilder();
297            return builder.translate(entityType, propertyName);
298        }
299
300        public static RenderingContextBuilder enrich(String entityType, String... enricherName) {
301            RenderingContextBuilder builder = new RenderingContextBuilder();
302            return builder.enrich(entityType, enricherName);
303        }
304
305        public static RenderingContextBuilder enrichDoc(String... enricherName) {
306            RenderingContextBuilder builder = new RenderingContextBuilder();
307            return builder.enrichDoc(enricherName);
308        }
309
310        public static RenderingContextBuilder depth(DepthValues value) {
311            RenderingContextBuilder builder = new RenderingContextBuilder();
312            return builder.depth(value);
313        }
314
315        public static RenderingContext get() {
316            RenderingContextBuilder builder = new RenderingContextBuilder();
317            return builder.get();
318        }
319    }
320
321    /**
322     * Session wrapper that manage the closing of new created session and preserve request scoped or document scoped
323     * session.
324     *
325     * @since 7.2
326     */
327    public class SessionWrapper implements Closeable {
328
329        private CoreSession session;
330
331        private boolean shouldBeClosed;
332
333        public SessionWrapper(CoreSession session, boolean shouldBeClosed) {
334            super();
335            this.session = session;
336            this.shouldBeClosed = shouldBeClosed;
337        }
338
339        public CoreSession getSession() {
340            return session;
341        }
342
343        public boolean shouldBeClosed() {
344            return shouldBeClosed;
345        }
346
347        @Override
348        public void close() throws IOException {
349            if (shouldBeClosed) {
350                session.close();
351            }
352        }
353
354    }
355
356}