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