Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/struts/tiles/TilesPlugin.java


1   /*
2    * $Id: TilesPlugin.java 54929 2004-10-16 16:38:42Z germuska $ 
3    *
4    * Copyright 1999-2004 The Apache Software Foundation.
5    * 
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    * 
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.struts.tiles;
20  
21  import java.util.Map;
22  
23  import javax.servlet.ServletContext;
24  import javax.servlet.ServletException;
25  import javax.servlet.UnavailableException;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.struts.action.ActionServlet;
30  import org.apache.struts.action.PlugIn;
31  import org.apache.struts.action.RequestProcessor;
32  import org.apache.struts.config.ControllerConfig;
33  import org.apache.struts.config.ModuleConfig;
34  import org.apache.struts.config.PlugInConfig;
35  import org.apache.struts.util.RequestUtils;
36  
37  /**
38   * Tiles Plugin used to initialize Tiles.
39   * This plugin is to be used with Struts 1.1 in association with
40   * {@link TilesRequestProcessor}.
41   * <br>
42   * This plugin creates one definition factory for each Struts-module. The definition factory
43   * configuration is read first from 'web.xml' (backward compatibility), then it is
44   * overloaded with values found in the plugin property values.
45   * <br>
46   * The plugin changes the Struts configuration by specifying a {@link TilesRequestProcessor} as
47   * request processor. If you want to use your own RequestProcessor,
48   * it should subclass TilesRequestProcessor.
49   * <br>
50   * This plugin can also be used to create one single factory for all modules.
51   * This behavior is enabled by specifying <code>moduleAware=false</code> in each
52   * plugin properties. In this case, the definition factory
53   * configuration file is read by the first Tiles plugin to be initialized. The order is
54   * determined by the order of modules declaration in web.xml. The first module
55   * is always the default one if it exists.
56   * The plugin should be declared in each struts-config.xml file in order to
57   * properly initialize the request processor.
58   * @since Struts 1.1
59   */
60  public class TilesPlugin implements PlugIn {
61  
62      /** 
63       * Commons Logging instance. 
64       */
65      protected static Log log = LogFactory.getLog(TilesPlugin.class);
66  
67      /** 
68       * Is the factory module aware? 
69       */
70      protected boolean moduleAware = false;
71  
72      /** 
73       * Tiles util implementation classname. This property can be set
74       * by user in the plugin declaration.
75       */
76      protected String tilesUtilImplClassname = null;
77  
78      /** 
79       * Associated definition factory. 
80       */
81      protected DefinitionsFactory definitionFactory = null;
82  
83      /** 
84       * The plugin config object provided by the ActionServlet initializing
85       * this plugin.
86       */
87      protected PlugInConfig currentPlugInConfigObject=null;
88  
89      /**
90       * Get the module aware flag.
91       * @return <code>true</code>: user wants a single factory instance,
92       * <code>false:</code> user wants multiple factory instances (one per module with Struts)
93       */
94      public boolean isModuleAware() {
95          return moduleAware;
96      }
97  
98      /**
99       * Set the module aware flag.
100      * This flag is only meaningful if the property <code>tilesUtilImplClassname</code> is not
101      * set.
102      * @param moduleAware <code>true</code>: user wants a single factory instance,
103      * <code>false:</code> user wants multiple factory instances (one per module with Struts)
104      */
105     public void setModuleAware(boolean moduleAware) {
106         this.moduleAware = moduleAware;
107     }
108 
109     /**
110      * <p>Receive notification that the specified module is being
111      * started up.</p>
112      *
113      * @param servlet ActionServlet that is managing all the modules
114      *  in this web application.
115      * @param moduleConfig ModuleConfig for the module with which
116      *  this plugin is associated.
117      *
118      * @exception ServletException if this <code>PlugIn</code> cannot
119      *  be successfully initialized.
120      */
121     public void init(ActionServlet servlet, ModuleConfig moduleConfig)
122         throws ServletException {
123             
124         // Create factory config object
125         DefinitionsFactoryConfig factoryConfig =
126             readFactoryConfig(servlet, moduleConfig);
127             
128         // Set the module name in the config. This name will be used to compute
129         // the name under which the factory is stored.
130         factoryConfig.setFactoryName(moduleConfig.getPrefix());
131         
132         // Set RequestProcessor class
133         this.initRequestProcessorClass(moduleConfig);
134 
135         this.initTilesUtil();
136 
137         this.initDefinitionsFactory(servlet.getServletContext(), moduleConfig, factoryConfig);
138     }
139 
140     /**
141      * Set TilesUtil implementation according to properties 'tilesUtilImplClassname' 
142      * and 'moduleAware'.  These properties are taken into account only once. A
143      * side effect is that only the values set in the first initialized plugin are 
144      * effectively taken into account.
145      * @throws ServletException
146      */
147     private void initTilesUtil() throws ServletException {
148 
149         if (TilesUtil.isTilesUtilImplSet()) {
150             return;
151         }
152 
153         // Check if user has specified a TilesUtil implementation classname or not.
154         // If no implementation is specified, check if user has specified one
155         // shared single factory for all module, or one factory for each module.
156 
157         if (this.getTilesUtilImplClassname() == null) {
158 
159             if (isModuleAware()) {
160                 TilesUtil.setTilesUtil(new TilesUtilStrutsModulesImpl());
161             } else {
162                 TilesUtil.setTilesUtil(new TilesUtilStrutsImpl());
163             }
164 
165         } else { // A classname is specified for the tilesUtilImp, use it.
166             try {
167                 TilesUtilStrutsImpl impl =
168                     (TilesUtilStrutsImpl) RequestUtils
169                         .applicationClass(getTilesUtilImplClassname())
170                         .newInstance();
171                 TilesUtil.setTilesUtil(impl);
172 
173             } catch (ClassCastException ex) {
174                 throw new ServletException(
175                     "Can't set TilesUtil implementation to '"
176                         + getTilesUtilImplClassname()
177                         + "'. TilesUtil implementation should be a subclass of '"
178                         + TilesUtilStrutsImpl.class.getName()
179                         + "'");
180 
181             } catch (Exception ex) {
182                 throw new ServletException(
183                     "Can't set TilesUtil implementation.",
184                     ex);
185             }
186         }
187 
188     }
189 
190     /**
191      * Initialize the DefinitionsFactory this module will use.
192      * @param servletContext
193      * @param moduleConfig
194      * @param factoryConfig
195      * @throws ServletException
196      */
197     private void initDefinitionsFactory(
198         ServletContext servletContext,
199         ModuleConfig moduleConfig,
200         DefinitionsFactoryConfig factoryConfig)
201         throws ServletException {
202             
203         // Check if a factory already exist for this module
204         definitionFactory =
205             ((TilesUtilStrutsImpl) TilesUtil.getTilesUtil()).getDefinitionsFactory(
206                 servletContext,
207                 moduleConfig);
208                 
209         if (definitionFactory != null) {
210             log.info(
211                 "Factory already exists for module '"
212                     + moduleConfig.getPrefix()
213                     + "'. The factory found is from module '"
214                     + definitionFactory.getConfig().getFactoryName()
215                     + "'. No new creation.");
216                     
217             return;
218         }
219         
220         // Create configurable factory
221         try {
222             definitionFactory =
223                 TilesUtil.createDefinitionsFactory(
224                     servletContext,
225                     factoryConfig);
226                     
227         } catch (DefinitionsFactoryException ex) {
228             log.error(
229                 "Can't create Tiles definition factory for module '"
230                     + moduleConfig.getPrefix()
231                     + "'.");
232                     
233             throw new ServletException(ex);
234         }
235         
236         log.info(
237             "Tiles definition factory loaded for module '"
238                 + moduleConfig.getPrefix()
239                 + "'.");
240     }
241 
242     /**
243      * End plugin.
244      */
245     public void destroy() {
246         definitionFactory.destroy();
247         definitionFactory = null;
248     }
249 
250     /**
251      * Create FactoryConfig and initialize it from web.xml and struts-config.xml.
252      *
253      * @param servlet ActionServlet that is managing all the modules
254      *  in this web application.
255      * @param config ModuleConfig for the module with which
256      *  this plugin is associated.
257      * @exception ServletException if this <code>PlugIn</code> cannot
258      *  be successfully initialized.
259      */
260     protected DefinitionsFactoryConfig readFactoryConfig(
261         ActionServlet servlet,
262         ModuleConfig config)
263         throws ServletException {
264             
265         // Create tiles definitions config object
266         DefinitionsFactoryConfig factoryConfig = new DefinitionsFactoryConfig();
267         // Get init parameters from web.xml files
268         try {
269             DefinitionsUtil.populateDefinitionsFactoryConfig(
270                 factoryConfig,
271                 servlet.getServletConfig());
272                 
273         } catch (Exception ex) {
274             if (log.isDebugEnabled()){
275                 log.debug("", ex);
276             }
277             ex.printStackTrace();
278             throw new UnavailableException(
279                 "Can't populate DefinitionsFactoryConfig class from 'web.xml': "
280                     + ex.getMessage());
281         }
282         
283         // Get init parameters from struts-config.xml
284         try {
285             Map strutsProperties = findStrutsPlugInConfigProperties(servlet, config);
286             factoryConfig.populate(strutsProperties);
287             
288         } catch (Exception ex) {
289             if (log.isDebugEnabled()) {
290                 log.debug("", ex);
291             }
292                 
293             throw new UnavailableException(
294                 "Can't populate DefinitionsFactoryConfig class from '"
295                     + config.getPrefix()
296                     + "/struts-config.xml':"
297                     + ex.getMessage());
298         }
299         
300         return factoryConfig;
301     }
302 
303     /**
304      * Find original properties set in the Struts PlugInConfig object.
305      * First, we need to find the index of this plugin. Then we retrieve the array of configs
306      * and then the object for this plugin.
307      * @param servlet ActionServlet that is managing all the modules
308      *  in this web application.
309      * @param config ModuleConfig for the module with which
310      *  this plug in is associated.
311      *
312      * @exception ServletException if this <code>PlugIn</code> cannot
313      *  be successfully initialized.
314      */
315     protected Map findStrutsPlugInConfigProperties(
316         ActionServlet servlet,
317         ModuleConfig config)
318         throws ServletException {
319             
320         return currentPlugInConfigObject.getProperties();
321     }
322 
323     /**
324      * Set RequestProcessor to appropriate Tiles {@link RequestProcessor}.
325      * First, check if a RequestProcessor is specified. If yes, check if it extends
326      * the appropriate {@link TilesRequestProcessor} class. If not, set processor class to
327      * TilesRequestProcessor.
328      *
329      * @param config ModuleConfig for the module with which
330      *  this plugin is associated.
331      * @throws ServletException On errors.
332      */
333     protected void initRequestProcessorClass(ModuleConfig config)
334         throws ServletException {
335             
336         String tilesProcessorClassname = TilesRequestProcessor.class.getName();
337         ControllerConfig ctrlConfig = config.getControllerConfig();
338         String configProcessorClassname = ctrlConfig.getProcessorClass();
339 
340         // Check if specified classname exist
341         Class configProcessorClass;
342         try {
343             configProcessorClass =
344                 RequestUtils.applicationClass(configProcessorClassname);
345                 
346         } catch (ClassNotFoundException ex) {
347             log.fatal(
348                 "Can't set TilesRequestProcessor: bad class name '"
349                     + configProcessorClassname
350                     + "'.");
351             throw new ServletException(ex);
352         }
353 
354         // Check if it is the default request processor or Tiles one.
355         // If true, replace by Tiles' one.
356         if (configProcessorClassname.equals(RequestProcessor.class.getName())
357             || configProcessorClassname.endsWith(tilesProcessorClassname)) {
358                 
359             ctrlConfig.setProcessorClass(tilesProcessorClassname);
360             return;
361         }
362 
363         // Check if specified request processor is compatible with Tiles.
364         Class tilesProcessorClass = TilesRequestProcessor.class;
365         if (!tilesProcessorClass.isAssignableFrom(configProcessorClass)) {
366             // Not compatible
367             String msg =
368                 "TilesPlugin : Specified RequestProcessor not compatible with TilesRequestProcessor";
369             if (log.isFatalEnabled()) {
370                 log.fatal(msg);
371             }
372             throw new ServletException(msg);
373         }
374     }
375 
376     /**
377      * Set Tiles util implemention classname.
378      * If this property is set, the flag <code>moduleAware</code> will not be used anymore.
379      * @param tilesUtilImplClassname Classname.
380      */
381     public void setTilesUtilImplClassname(String tilesUtilImplClassname) {
382         this.tilesUtilImplClassname = tilesUtilImplClassname;
383     }
384     
385     /**
386      * Get Tiles util implemention classname.
387      * @return The classname or <code>null</code> if none is set.
388      */
389     public String getTilesUtilImplClassname() {
390         return tilesUtilImplClassname;
391     }
392 
393     /**
394      * Method used by the ActionServlet initializing this plugin.
395      * Set the plugin config object read from module config.
396      * @param plugInConfigObject PlugInConfig.
397      */
398     public void setCurrentPlugInConfigObject(PlugInConfig plugInConfigObject) {
399         this.currentPlugInConfigObject = plugInConfigObject;
400     }
401 
402 }