View Javadoc
1   /*
2    * $Id$
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.tiles.servlet.context;
23  
24  import java.io.IOException;
25  
26  import javax.servlet.ServletContext;
27  import javax.servlet.ServletException;
28  import javax.servlet.ServletRequest;
29  import javax.servlet.http.HttpServletRequest;
30  
31  import org.apache.tiles.ArrayStack;
32  import org.apache.tiles.TilesApplicationContext;
33  import org.apache.tiles.TilesContainer;
34  import org.apache.tiles.access.TilesAccess;
35  import org.apache.tiles.context.TilesRequestContext;
36  import org.apache.tiles.context.TilesRequestContextWrapper;
37  import org.apache.tiles.impl.NoSuchContainerException;
38  import org.apache.tiles.util.TilesIOException;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  
43  /**
44   * Utilities for Tiles servlet support.
45   *
46   * @version $Rev$ $Date$
47   * @since 2.0.6
48   */
49  public final class ServletUtil {
50  
51      /**
52       * The name of the attribute that will contain the compose stack.
53       */
54      public static final String COMPOSE_STACK_ATTRIBUTE_NAME = "org.apache.tiles.template.COMPOSE_STACK";
55  
56      /**
57       * Name of the attribute used to store the force-include option.
58       * @since 2.0.6
59       */
60      public static final String FORCE_INCLUDE_ATTRIBUTE_NAME =
61          "org.apache.tiles.servlet.context.ServletTilesRequestContext.FORCE_INCLUDE";
62  
63      /**
64       * Name of the attribute used to store the current used container.
65       */
66      public static final String CURRENT_CONTAINER_ATTRIBUTE_NAME =
67          "org.apache.tiles.servlet.context.ServletTilesRequestContext.CURRENT_CONTAINER_KEY";
68  
69      /**
70       * Private constructor to avoid instantiation.
71       */
72      private ServletUtil() {
73      }
74  
75      /**
76       * Returns true if forced include of the result is needed.
77       *
78       * @param request The HTTP request.
79       * @return If <code>true</code> the include operation must be forced.
80       * @since 2.0.6
81       */
82      public static boolean isForceInclude(HttpServletRequest request) {
83          Boolean retValue = (Boolean) request
84                  .getAttribute(ServletUtil.FORCE_INCLUDE_ATTRIBUTE_NAME);
85          return retValue != null && retValue.booleanValue();
86      }
87  
88      /**
89       * Sets the option that enables the forced include of the response.
90       *
91       * @param request The HTTP request.
92       * @param forceInclude If <code>true</code> the include operation must be
93       * forced.
94       * @since 2.0.6
95       */
96      public static void setForceInclude(HttpServletRequest request,
97              boolean forceInclude) {
98          Boolean retValue = Boolean.valueOf(forceInclude);
99          request.setAttribute(
100                 ServletUtil.FORCE_INCLUDE_ATTRIBUTE_NAME,
101                 retValue);
102     }
103 
104     /**
105      * Returns the default Tiles container.
106      *
107      * @param context The servlet context to use.
108      * @return The default Tiles container.
109      * @since 2.1.2
110      */
111     public static TilesContainer getContainer(ServletContext context) {
112         return getContainer(context, TilesAccess.CONTAINER_ATTRIBUTE);
113     }
114 
115     /**
116      * Returns a specific Tiles container.
117      *
118      * @param context The servlet context to use.
119      * @param key The key under which the container is stored. If null, the
120      * default container will be returned.
121      * @return The requested Tiles container.
122      * @since 2.1.2
123      */
124     public static TilesContainer getContainer(ServletContext context, String key) {
125         if (key == null) {
126             key = TilesAccess.CONTAINER_ATTRIBUTE;
127         }
128         return (TilesContainer) context.getAttribute(key);
129     }
130 
131     /**
132      * Configures the default container to be used in the application.
133      *
134      * @param context The servlet context object to use.
135      * @param container The container object to set.
136      * @since 2.1.2
137      */
138     public static void setContainer(ServletContext context,
139             TilesContainer container) {
140         setContainer(context, container, TilesAccess.CONTAINER_ATTRIBUTE);
141     }
142 
143     /**
144      * Configures the container to be used in the application.
145      *
146      * @param context The servlet context object to use.
147      * @param container The container object to set.
148      * @param key The key under which the container will be stored.
149      * @since 2.1.2
150      */
151     public static void setContainer(ServletContext context,
152             TilesContainer container, String key) {
153         Logger log = LoggerFactory.getLogger(ServletUtil.class);
154         if (key == null) {
155             key = TilesAccess.CONTAINER_ATTRIBUTE;
156         }
157 
158         if (container == null) {
159             if (log.isInfoEnabled()) {
160                 log.info("Removing TilesContext for context: " + context.getClass().getName());
161             }
162             context.removeAttribute(key);
163         }
164         if (container != null && log.isInfoEnabled()) {
165             log.info("Publishing TilesContext for context: " + context.getClass().getName());
166         }
167         context.setAttribute(key, container);
168     }
169 
170     /**
171      * Sets the current container to use in web pages.
172      *
173      * @param request The request to use.
174      * @param context The servlet context to use.
175      * @param key The key under which the container is stored.
176      * @since 2.1.0
177      */
178     public static void setCurrentContainer(ServletRequest request,
179             ServletContext context, String key) {
180         TilesContainer container = getContainer(context, key);
181         if (container != null) {
182             request.setAttribute(CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
183         } else {
184             throw new NoSuchContainerException("The container with the key '"
185                     + key + "' cannot be found");
186         }
187     }
188 
189     /**
190      * Sets the current container to use in web pages.
191      *
192      * @param request The request to use.
193      * @param context The servlet context to use.
194      * @param container The container to use as the current container.
195      * @since 2.1.0
196      */
197     public static void setCurrentContainer(ServletRequest request,
198             ServletContext context, TilesContainer container) {
199         if (container != null) {
200             request.setAttribute(CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
201         } else {
202             throw new NoSuchContainerException("The container cannot be null");
203         }
204     }
205 
206     /**
207      * Returns the current container that has been set, or the default one.
208      *
209      * @param request The request to use.
210      * @param context The servlet context to use.
211      * @return The current Tiles container to use in web pages.
212      * @since 2.1.0
213      */
214     public static TilesContainer getCurrentContainer(ServletRequest request,
215             ServletContext context) {
216         TilesContainer container = (TilesContainer) request
217                 .getAttribute(CURRENT_CONTAINER_ATTRIBUTE_NAME);
218         if (container == null) {
219             container = getContainer(context);
220             request.setAttribute(CURRENT_CONTAINER_ATTRIBUTE_NAME, container);
221         }
222 
223         return container;
224     }
225 
226     /**
227      * Wraps a ServletException to create an IOException with the root cause if present.
228      *
229      * @param ex The exception to wrap.
230      * @param message The message of the exception.
231      * @return The wrapped exception.
232      * @since 2.1.1
233      */
234     public static IOException wrapServletException(ServletException ex,
235             String message) {
236         IOException retValue;
237         Throwable rootCause = ex.getRootCause();
238         if (rootCause != null) {
239             // Replace the ServletException with an IOException, with the root
240             // cause of the first as the cause of the latter.
241             retValue = new TilesIOException(message, rootCause);
242         } else {
243             retValue = new TilesIOException(message, ex);
244         }
245 
246         return retValue;
247     }
248 
249     /**
250      * Returns the compose stack, that is used by the tags to compose
251      * definitions, attributes, etc.
252      *
253      * @param request The HTTP request.
254      * @return The compose stack.
255      * @since 2.2.0
256      */
257     @SuppressWarnings("unchecked")
258     public static ArrayStack<Object> getComposeStack(HttpServletRequest request) {
259         ArrayStack<Object> composeStack = (ArrayStack<Object>) request.getAttribute(
260                 COMPOSE_STACK_ATTRIBUTE_NAME);
261         if (composeStack == null) {
262             composeStack = new ArrayStack<Object>();
263             request.setAttribute(COMPOSE_STACK_ATTRIBUTE_NAME, composeStack);
264         }
265         return composeStack;
266     }
267 
268     /**
269      * Opens a TilesRequestContext until it finds a ServletTilesRequestContext.
270      *
271      * @param request The request to open.
272      * @return The servlet-based request context.
273      * @throws NotAServletEnvironmentException If a servlet-based request
274      * context could not be found.
275      * @since 2.2.0
276      */
277     public static ServletTilesRequestContext getServletRequest(TilesRequestContext request) {
278         TilesRequestContext currentRequest = request;
279         while (true) {
280             if (currentRequest == null) {
281                 throw new NotAServletEnvironmentException("Last Tiles request context is null");
282             }
283 
284             if (currentRequest instanceof ServletTilesRequestContext) {
285                 return (ServletTilesRequestContext) currentRequest;
286             }
287             if (!(currentRequest instanceof TilesRequestContextWrapper)) {
288                 throw new NotAServletEnvironmentException("Not a Servlet environment, not supported");
289             }
290             currentRequest = ((TilesRequestContextWrapper) currentRequest).getWrappedRequest();
291         }
292     }
293 
294     /**
295      * Gets a servlet context from a TilesApplicationContext.
296      *
297      * @param applicationContext The application context to analyze.
298      * @return The servlet context.
299      * @throws NotAServletEnvironmentException If the application context is not
300      * servlet-based.
301      * @since 2.2.0
302      */
303     public static ServletContext getServletContext(TilesApplicationContext applicationContext) {
304         if (applicationContext instanceof ServletTilesApplicationContext) {
305             return (ServletContext) ((ServletTilesApplicationContext) applicationContext).getContext();
306         }
307 
308         throw new NotAServletEnvironmentException("Not a Servlet-based environment");
309     }
310 }