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 * When a {@link RenderingContext} is automatically provided from an HttpServletRequest, it contains request parameters,
040 * headers and request attribute.
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 * To manage document properties, entity enrichers or properties fetching, use:
055 * <ul>
056 * <li>{@link RenderingContext#getProperties()}</li>
057 * <li>{@link RenderingContext#getEnrichers(String)}</li>
058 * <li>{@link RenderingContext#getFetched(String)}</li>
059 * </ul>
060 * <p>
061 * To manage infinite loop when calling a marshaller from another marshaller, use:
062 * <ul>
063 * <li>{@link RenderingContext#wrap()} -&gt; {@link WrappedContext#controlDepth()}</li>
064 * </ul>
065 * Example:
066 *
067 * <pre>
068 * // This will control infinite loop in this marshaller
069 * try (Closeable resource = ctx.wrap().controlDepth().open()) {
070 *     // call another marshaller to fetch the desired property here
071 * } catch (MaxDepthReachedException mdre) {
072 *     // do not call the other marshaller
073 * }
074 * </pre>
075 *
076 * @since 7.2.
077 */
078public interface RenderingContext {
079
080    Locale DEFAULT_LOCALE = Locale.ENGLISH;
081
082    String DEFAULT_URL = "http://fake-url.nuxeo.com/";
083
084    String RESPONSE_HEADER_ENTITY_TYPE_KEY = "ENTITY_TYPE";
085
086    /**
087     * @since 10.2
088     */
089    String REPOSITORY_NAME_REQUEST_HEADER = "X-NXRepository";
090
091    /**
092     * @since 10.2
093     */
094    String REPOSITORY_NAME_REQUEST_PARAMETER = "nxrepository";
095
096    /**
097     * Gets the requested {@link Locale}.
098     *
099     * @since 7.2
100     */
101    Locale getLocale();
102
103    /**
104     * Gets the current base url.
105     *
106     * @since 7.2
107     */
108    String getBaseUrl();
109
110    /**
111     * Gets the current {@link CoreSession} or try to create one.
112     *
113     * @param document may be null, if present, this method search for a session in the document.
114     * @return The current {@link CoreSession} if it exists. null otherwise.
115     * @throws MarshallingException if no session could be created or found.
116     * @since 7.2
117     */
118    SessionWrapper getSession(DocumentModel document) throws MarshallingException;
119
120    /**
121     * Provides a {@link CoreSession} to marshallers.
122     * <p>
123     * For example: a {@link CoreSession} from the request context.
124     * </p>
125     *
126     * @param session The existing {@link CoreSession} which lifecycle is managed outside the marshalling context.
127     * @since 7.2
128     */
129    void setExistingSession(CoreSession session);
130
131    /**
132     * Get all document properties. This will aggregate all values from parameters "properties", "X-NXproperties" and
133     * "X-NXDocumentProperties". This supports value separated by comma.
134     *
135     * @return All document properties.
136     * @since 7.2
137     */
138    Set<String> getProperties();
139
140    /**
141     * Get all properties to fetch for a given entity type. This will aggregate all values from parameters
142     * "fetch.entity" and "X-NXfetch.entity". This supports value separated by comma.
143     *
144     * @param entity The type of the entity on which you want to fetch properties.
145     * @return All properties to fetch.
146     * @since 7.2
147     */
148    Set<String> getFetched(String entity);
149
150    /**
151     * Get all properties to translate for a given entity type. This will aggregate all values from parameters
152     * "translate.entity" and "X-NXtranslate.entity". This supports value separated by comma.
153     *
154     * @param entity The type of the entity on which you want to fetch properties.
155     * @return All properties to fetch.
156     * @since 7.2
157     */
158    Set<String> getTranslated(String entity);
159
160    /**
161     * Get all enrichers to activate on the given entity type. This will aggregate all values from parameters
162     * "enrichers.entity", "X-NXenrichers.entity" and "X-NXContext-Category". This supports value separated by comma.
163     *
164     * @param entity The type of the entity on which you want to activate enrichers.
165     * @return All enrichers to activate.
166     * @since 7.2
167     */
168    Set<String> getEnrichers(String entity);
169
170    /**
171     * see {@link WrappedContext}
172     *
173     * @return A new {@link WrappedContext}
174     * @since 7.2
175     */
176    WrappedContext wrap();
177
178    /**
179     * Get the casted parameter value for a given name. If multiple are available, the first found is returned.
180     *
181     * @param name The parameter name.
182     * @return The first parameter value, null if no parameter are availble.
183     * @since 7.2
184     */
185    <T> T getParameter(String name);
186
187    /**
188     * see {@link #getParameter(String)}
189     *
190     * @return true is the parameter exists and if it's Boolean.TRUE or "true", false otherwise.
191     */
192    boolean getBooleanParameter(String name);
193
194    /**
195     * Get the casted parameter values for a given name.
196     *
197     * @param name The parameter name.
198     * @return The parameter values.
199     * @since 7.2
200     */
201    <T> List<T> getParameters(String name);
202
203    /**
204     * Get all parameter in this context except wrapped parameters.
205     *
206     * @return All parameter's names and their values.
207     * @since 7.2
208     */
209    Map<String, List<Object>> getAllParameters();
210
211    /**
212     * @see #setParameterListValues(String, List)
213     * @since 7.2
214     */
215    void setParameterValues(String name, Object... values);
216
217    /**
218     * Push values in the context with a given name. Please note that this method remove any value for the given name.
219     *
220     * @param name The parameter name.
221     * @param values The parameter values.
222     * @since 7.2
223     */
224    void setParameterListValues(String name, List<Object> values);
225
226    /**
227     * @see #addParameterListValues(String, List)
228     * @since 7.2
229     */
230    void addParameterValues(String name, Object... values);
231
232    /**
233     * Add values in the context with a given name. Please note that this method keep current values for the given name.
234     *
235     * @param name The parameter name.
236     * @param values The parameter values.
237     * @since 7.2
238     */
239    void addParameterListValues(String name, List<?> values);
240
241    /**
242     * {@link RenderingContext} builder.
243     * <p>
244     * RenderingContext ctx = CtxBuilder.base("http://mine.nuxeo.com/nuxeo").locale(Locale.ENGLISH).param("name",
245     * "value1", "value2").get();
246     * </p>
247     *
248     * @since 7.2
249     */
250    public static final class CtxBuilder {
251        private CtxBuilder() {
252        }
253
254        public static RenderingContextBuilder builder() {
255            return new RenderingContextBuilder();
256        }
257
258        public static RenderingContextBuilder base(String url) {
259            RenderingContextBuilder builder = new RenderingContextBuilder();
260            return builder.base(url);
261        }
262
263        public static RenderingContextBuilder locale(Locale locale) {
264            RenderingContextBuilder builder = new RenderingContextBuilder();
265            return builder.locale(locale);
266        }
267
268        public static RenderingContextBuilder session(CoreSession session) {
269            RenderingContextBuilder builder = new RenderingContextBuilder();
270            return builder.session(session);
271        }
272
273        public static RenderingContextBuilder param(String name, Object value) {
274            RenderingContextBuilder builder = new RenderingContextBuilder();
275            return builder.param(name, value);
276        }
277
278        public static RenderingContextBuilder paramValues(String name, Object... values) {
279            RenderingContextBuilder builder = new RenderingContextBuilder();
280            return builder.paramValues(name, values);
281        }
282
283        public static RenderingContextBuilder paramList(String name, List<?> values) {
284            RenderingContextBuilder builder = new RenderingContextBuilder();
285            return builder.paramList(name, values);
286        }
287
288        public static RenderingContextBuilder properties(String... schemaName) {
289            RenderingContextBuilder builder = new RenderingContextBuilder();
290            return builder.properties(schemaName);
291        }
292
293        public static RenderingContextBuilder fetch(String entityType, String... propertyName) {
294            RenderingContextBuilder builder = new RenderingContextBuilder();
295            return builder.fetch(entityType, propertyName);
296        }
297
298        public static RenderingContextBuilder fetchInDoc(String... propertyName) {
299            RenderingContextBuilder builder = new RenderingContextBuilder();
300            return builder.fetchInDoc(propertyName);
301        }
302
303        public static RenderingContextBuilder translate(String entityType, String... propertyName) {
304            RenderingContextBuilder builder = new RenderingContextBuilder();
305            return builder.translate(entityType, propertyName);
306        }
307
308        public static RenderingContextBuilder enrich(String entityType, String... enricherName) {
309            RenderingContextBuilder builder = new RenderingContextBuilder();
310            return builder.enrich(entityType, enricherName);
311        }
312
313        public static RenderingContextBuilder enrichDoc(String... enricherName) {
314            RenderingContextBuilder builder = new RenderingContextBuilder();
315            return builder.enrichDoc(enricherName);
316        }
317
318        public static RenderingContextBuilder depth(DepthValues value) {
319            RenderingContextBuilder builder = new RenderingContextBuilder();
320            return builder.depth(value);
321        }
322
323        public static RenderingContext get() {
324            RenderingContextBuilder builder = new RenderingContextBuilder();
325            return builder.get();
326        }
327    }
328
329    /**
330     * Session wrapper. This used to be needed to close session, which isn't needed anymore.
331     *
332     * @since 7.2
333     */
334    public class SessionWrapper implements Closeable {
335
336        private CoreSession session;
337
338        public SessionWrapper(CoreSession session) {
339            super();
340            this.session = session;
341        }
342
343        public CoreSession getSession() {
344            return session;
345        }
346
347        @Override
348        public void close() throws IOException {
349        }
350
351    }
352
353}