View Javadoc

1   package org.apache.velocity.tools.view;
2   
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  import java.util.Map;
23  import javax.servlet.ServletContext;
24  import javax.servlet.ServletRequest;
25  import javax.servlet.http.HttpServletRequest;
26  import javax.servlet.http.HttpSession;
27  import javax.servlet.http.HttpServletResponse;
28  import org.apache.velocity.app.VelocityEngine;
29  import org.apache.velocity.tools.Scope;
30  import org.apache.velocity.tools.Toolbox;
31  import org.apache.velocity.tools.ToolboxFactory;
32  import org.apache.velocity.tools.ToolContext;
33  import org.apache.velocity.tools.ToolManager;
34  import org.apache.velocity.tools.config.ConfigurationUtils;
35  import org.apache.velocity.tools.config.FactoryConfiguration;
36  import org.apache.velocity.tools.view.ServletUtils;
37  import org.apache.velocity.tools.view.ViewContext;
38  import org.apache.velocity.tools.view.ViewToolContext;
39  
40  /**
41   * Manages tools for web applications. This simplifies the process
42   * of getting a tool-populated Velocity context for merging with templates.
43   * It allows for both direct configuration by passing in a {@link FactoryConfiguration}
44   * or having one in the ServletContext attributes under
45   * {@link ServletUtils#CONFIGURATION_KEY}, as well as configuration
46   * via a tools.xml or tools.properties file in
47   * either the classpath or the local file system.
48   *
49   * @author Nathan Bubna
50   * @version $Id: ToolManager.java 511959 2007-02-26 19:24:39Z nbubna $
51   */
52  public class ViewToolManager extends ToolManager
53  {
54      public static final String CREATE_SESSION_PROPERTY = "createSession";
55      public static final String PUBLISH_TOOLBOXES_PROPERTY = "publishToolboxes";
56      public static final String DEFAULT_TOOLBOX_KEY = Toolbox.KEY;
57  
58      protected ServletContext servletContext;
59      private boolean createSession = true;
60      private boolean publishToolboxes = true;
61      private boolean appToolsPublished = false;
62      private String toolboxKey = DEFAULT_TOOLBOX_KEY;
63  
64      /**
65       * Constructs an instance already configured to use the 
66       * {@link ConfigurationUtils#getAutoLoaded()()} configuration
67       * and any configuration specified via a "org.apache.velocity.tools"
68       * system property.
69       */
70      public ViewToolManager(ServletContext app)
71      {
72          this(app, true, true);
73      }
74  
75      public ViewToolManager(ServletContext app, boolean includeDefaults)
76      {
77          this(app, true, includeDefaults);
78      }
79  
80      public ViewToolManager(ServletContext app,
81                             boolean autoConfig, boolean includeDefaults)
82      {
83          super(autoConfig, includeDefaults);
84  
85          if (app == null)
86          {
87              throw new NullPointerException("ServletContext is required");
88          }
89          this.servletContext = app;
90      }
91  
92      @Override
93      public void autoConfigure(boolean includeDefaults)
94      {
95          super.autoConfigure(includeDefaults);
96  
97          // check for a configuration in application attributes
98          FactoryConfiguration injected = ServletUtils.getConfiguration(servletContext);
99          if (injected != null)
100         {
101             configure(injected);
102         }
103     }
104 
105     /**
106      * Sets whether or not the creation of a new {@link ViewToolContext}
107      * should make the various scoped {@link Toolbox} instances available
108      * publically via the HttpServletRequest/HttpSession/ServletContext
109      * attributes or simply add the Toolbox instances directly to the
110      * context. <b>It is important to note that if this is set to false,
111      * session-scoped tools will NOT be stored in the session, but instead
112      * be recreated for each request.</b>
113      * @see #publishToolboxes
114      * @see #setToolboxKey
115      */
116     public void setPublishToolboxes(boolean publish)
117     {
118         if (publish != this.publishToolboxes)
119         {
120             debug("Publish toolboxes setting was changed to %s", publish);
121             this.publishToolboxes = publish;
122         }
123     }
124 
125     public boolean getPublishToolboxes()
126     {
127         return this.publishToolboxes;
128     }
129 
130     /**
131      * Sets a new attribute key to be used for publishing each {@link Toolbox}.
132      * @see #setPublishToolboxes
133      * @see #publishToolboxes
134      */
135     public void setToolboxKey(String key)
136     {
137         if (key == null)
138         {
139             throw new NullPointerException("toolboxKey cannot be null");
140         }
141         if (!key.equals(toolboxKey))
142         {
143             this.toolboxKey = key;
144             unpublishApplicationTools();
145             debug("Toolbox key was changed to %s", key);
146         }
147     }
148 
149     public String getToolboxKey()
150     {
151         return this.toolboxKey;
152     }
153 
154     /**
155      * Sets whether or not a new HttpSession should be created
156      * when there are session scoped tools to be stored in the session,
157      * but no session has been created yet.
158      * @see #publishToolboxes
159      */
160     public void setCreateSession(boolean create)
161     {
162         if (create != this.createSession)
163         {
164             debug("Create session setting was changed to %s", create);
165             this.createSession = create;
166         }
167     }
168 
169     public boolean getCreateSession()
170     {
171         return this.createSession;
172     }
173 
174     /**
175      * Checks the internal {@link ToolboxFactory} for any changes to
176      * the createSession or publishToolboxes settings.
177      */
178     protected void updateGlobalProperties()
179     {
180         // check for a createSession setting
181         Boolean create = 
182             (Boolean)this.factory.getGlobalProperty(CREATE_SESSION_PROPERTY);
183         if (create != null)
184         {
185             setCreateSession(create);
186         }
187 
188         // check for a publishToolboxes setting
189         Boolean publish = 
190             (Boolean)this.factory.getGlobalProperty(PUBLISH_TOOLBOXES_PROPERTY);
191         if (publish != null)
192         {
193             setPublishToolboxes(publish);
194         }
195     }
196 
197     /**
198      * Removes any published {@link Scope#APPLICATION} Toolbox.
199      */
200     protected void unpublishApplicationTools()
201     {
202         if (appToolsPublished)
203         {
204             // clear the published application toolbox
205             servletContext.removeAttribute(this.toolboxKey);
206             appToolsPublished = false;
207         }
208     }
209 
210     @Override
211     public void configure(FactoryConfiguration config)
212     {
213         super.configure(config);
214 
215         // reset things as best we can
216         unpublishApplicationTools();
217         updateGlobalProperties();
218     }
219 
220     @Override
221     protected FactoryConfiguration findConfig(String path)
222     {
223         return ServletUtils.getConfiguration(path, servletContext, false);
224     }
225 
226     @Override
227     protected void addToolboxes(ToolContext context)
228     {
229         super.addToolboxes(context);
230         if (hasSessionTools())
231         {
232             context.addToolbox(getSessionToolbox());
233         }
234     }
235 
236     @Override
237     public ToolContext createContext(Map<String,Object> toolProps)
238     {
239         ToolContext context = super.createContext(toolProps);
240         context.putToolProperty(ViewContext.SERVLET_CONTEXT_KEY, servletContext);
241         debug("Non-ViewToolContext was requested from ViewToolManager.");
242         return context;
243     }
244 
245     public ViewToolContext createContext(HttpServletRequest request,
246                                          HttpServletResponse response)
247     {
248         ViewToolContext context =
249             new ViewToolContext(getVelocityEngine(), request, response, servletContext);
250         prepareContext(context, request);
251         return context;
252     }
253 
254     public void prepareContext(ViewToolContext context, HttpServletRequest request)
255     {
256         context.setToolboxKey(this.toolboxKey);
257         if (this.publishToolboxes)
258         {
259             // put the toolboxes where the ViewToolContext
260             // and others can find them
261             publishToolboxes(request);
262             
263             // these would otherwise be done in super.prepareContext
264             VelocityEngine engine = getVelocityEngine();
265             if (engine != null)
266             {
267                 context.putVelocityEngine(engine);
268             }
269             context.setUserCanOverwriteTools(getUserCanOverwriteTools());
270         }
271         else
272         {
273             // super class takes care of engine
274             // and adds toolboxes directly
275             prepareContext(context);
276         }
277     }
278 
279     protected boolean hasSessionTools()
280     {
281         return hasTools(Scope.SESSION);
282     }
283 
284     protected Toolbox getSessionToolbox()
285     {
286         return createToolbox(Scope.SESSION);
287     }
288 
289     /**
290      * Places the {@link Scope#REQUEST} {@link Toolbox} (if any)
291      * into the {@link ServletRequest} attributes using
292      * {@link Toolbox#KEY} as the key.
293      */
294     public void publishToolboxes(ServletRequest request)
295     {
296         publishToolbox(request);
297     }
298 
299     private void publishToolbox(ServletRequest request)
300     {
301         if (hasRequestTools() &&
302             request.getAttribute(this.toolboxKey) == null)
303         {
304             request.setAttribute(this.toolboxKey, getRequestToolbox());
305         }
306     }
307 
308     /**
309      * Places the {@link Scope#REQUEST} {@link Toolbox} (if any)
310      * into the {@link HttpServletRequest} attributes using
311      * {@link Toolbox#KEY} as the key, places the {@link Scope#SESSION}
312      * Toolbox (if any) into the attributes of the {@link HttpSession} (if any)
313      * then ensures that the {@link Scope#APPLICATION} Toolbox (if any)
314      * has been placed in the {@link ServletContext} attributes.
315      */
316     public void publishToolboxes(HttpServletRequest request)
317     {
318         publishToolbox(request);
319 
320         if (hasSessionTools())
321         {
322             HttpSession session = request.getSession(this.createSession);
323             if (session != null)
324             {
325                 // allow only one thread per session
326                 synchronized(ServletUtils.getMutex(session, "session.mutex", this))
327                 {
328                     if (session.getAttribute(this.toolboxKey) == null)
329                     {
330                         session.setAttribute(this.toolboxKey, getSessionToolbox());
331                     }
332                 }
333             }
334         }
335         if (!appToolsPublished && hasApplicationTools())
336         {
337             servletContext.setAttribute(this.toolboxKey, getApplicationToolbox());
338         }
339     }
340 
341 }