KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > struts > tiles > TilesPlugin


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 JavaDoc;
22
23 import javax.servlet.ServletContext JavaDoc;
24 import javax.servlet.ServletException JavaDoc;
25 import javax.servlet.UnavailableException JavaDoc;
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 JavaDoc 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 JavaDoc {
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 JavaDoc {
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 JavaDoc ex) {
174                 throw new ServletException JavaDoc(
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 JavaDoc ex) {
182                 throw new ServletException JavaDoc(
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 JavaDoc servletContext,
199         ModuleConfig moduleConfig,
200         DefinitionsFactoryConfig factoryConfig)
201         throws ServletException JavaDoc {
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 JavaDoc(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 JavaDoc {
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 JavaDoc ex) {
274             if (log.isDebugEnabled()){
275                 log.debug("", ex);
276             }
277             ex.printStackTrace();
278             throw new UnavailableException JavaDoc(
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 JavaDoc strutsProperties = findStrutsPlugInConfigProperties(servlet, config);
286             factoryConfig.populate(strutsProperties);
287             
288         } catch (Exception JavaDoc ex) {
289             if (log.isDebugEnabled()) {
290                 log.debug("", ex);
291             }
292                 
293             throw new UnavailableException JavaDoc(
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 JavaDoc findStrutsPlugInConfigProperties(
316         ActionServlet servlet,
317         ModuleConfig config)
318         throws ServletException JavaDoc {
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 JavaDoc {
335             
336         String JavaDoc tilesProcessorClassname = TilesRequestProcessor.class.getName();
337         ControllerConfig ctrlConfig = config.getControllerConfig();
338         String JavaDoc configProcessorClassname = ctrlConfig.getProcessorClass();
339
340         // Check if specified classname exist
341
Class JavaDoc configProcessorClass;
342         try {
343             configProcessorClass =
344                 RequestUtils.applicationClass(configProcessorClassname);
345                 
346         } catch (ClassNotFoundException JavaDoc ex) {
347             log.fatal(
348                 "Can't set TilesRequestProcessor: bad class name '"
349                     + configProcessorClassname
350                     + "'.");
351             throw new ServletException JavaDoc(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 JavaDoc tilesProcessorClass = TilesRequestProcessor.class;
365         if (!tilesProcessorClass.isAssignableFrom(configProcessorClass)) {
366             // Not compatible
367
String JavaDoc msg =
368                 "TilesPlugin : Specified RequestProcessor not compatible with TilesRequestProcessor";
369             if (log.isFatalEnabled()) {
370                 log.fatal(msg);
371             }
372             throw new ServletException JavaDoc(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 JavaDoc 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 JavaDoc 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 }
403
Popular Tags