View Javadoc

1   /*
2    * $Id: ReloadableDefinitionsFactory.java 421151 2006-07-12 06:07:14Z wsmoak $
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.definition;
20  
21  import java.util.Enumeration;
22  import java.util.HashMap;
23  import java.util.Map;
24  
25  import javax.servlet.ServletConfig;
26  import javax.servlet.ServletContext;
27  import javax.servlet.ServletRequest;
28  import javax.servlet.http.HttpServletRequest;
29  
30  import org.apache.struts.tiles.ComponentDefinition;
31  import org.apache.struts.tiles.ComponentDefinitionsFactory;
32  import org.apache.struts.tiles.DefinitionsFactoryException;
33  import org.apache.struts.tiles.FactoryNotFoundException;
34  import org.apache.struts.tiles.xmlDefinition.I18nFactorySet;
35  import org.apache.struts.util.RequestUtils;
36  
37  /***
38   * A reloadable factory.
39   * This factory is the main entrance to any factory implementation. It takes in
40   * charge real implementation instance, and allows reloading by creating a new
41   * instance.
42   *
43   * @since Struts 1.1
44   * @version $Rev: 421151 $ $Date: 2006-07-11 23:07:14 -0700 (Tue, 11 Jul 2006) $
45   */
46  public class ReloadableDefinitionsFactory implements ComponentDefinitionsFactory {
47  
48      /***
49       * The real factory instance.
50       */
51      protected ComponentDefinitionsFactory factory = null;
52  
53      /***
54       * Initialization parameters.
55       */
56      protected Map properties = null;
57  
58      /***
59       * Name of init property carrying factory class name.
60       */
61      public static final String DEFINITIONS_FACTORY_CLASSNAME =
62          "definitions-factory-class";
63  
64      /***
65       * Constructor.
66       * Create a factory according to servlet settings.
67       * @param servletContext Our servlet context.
68       * @param servletConfig Our servlet config.
69       * @throws DefinitionsFactoryException If factory creation fail.
70       */
71      public ReloadableDefinitionsFactory(
72          ServletContext servletContext,
73          ServletConfig servletConfig)
74          throws DefinitionsFactoryException {
75  
76          properties = new ServletPropertiesMap(servletConfig);
77          factory = createFactory(servletContext, properties);
78      }
79  
80      /***
81       * Constructor.
82       * Create a factory according to servlet settings.
83       * @param servletContext Our servlet context.
84       * @param properties Map containing all properties.
85       * @throws DefinitionsFactoryException If factory creation fail.
86       */
87      public ReloadableDefinitionsFactory(
88          ServletContext servletContext,
89          Map properties)
90          throws DefinitionsFactoryException {
91  
92          this.properties = properties;
93          factory = createFactory(servletContext, properties);
94      }
95  
96      /***
97      * Create Definition factory from provided classname.
98      * If a factory class name is provided, a factory of this class is created. Otherwise,
99      * a default factory is created.
100     * Factory must have a constructor taking ServletContext and Map as parameter.
101     * @param classname Class name of the factory to create.
102     * @param servletContext Servlet Context passed to newly created factory.
103     * @param properties Map of name/property passed to newly created factory.
104     * @return newly created factory.
105     * @throws DefinitionsFactoryException If an error occur while initializing factory
106     */
107     public ComponentDefinitionsFactory createFactoryFromClassname(
108         ServletContext servletContext,
109         Map properties,
110         String classname)
111         throws DefinitionsFactoryException {
112 
113         if (classname == null) {
114             return createFactory(servletContext, properties);
115         }
116 
117         // Try to create from classname
118         try {
119             Class factoryClass = RequestUtils.applicationClass(classname);
120             ComponentDefinitionsFactory factory =
121                 (ComponentDefinitionsFactory) factoryClass.newInstance();
122             factory.initFactory(servletContext, properties);
123             return factory;
124 
125         } catch (ClassCastException ex) { // Bad classname
126             throw new DefinitionsFactoryException(
127                 "Error - createDefinitionsFactory : Factory class '"
128                     + classname
129                     + " must implements 'ComponentDefinitionsFactory'.",
130                 ex);
131 
132         } catch (ClassNotFoundException ex) { // Bad classname
133             throw new DefinitionsFactoryException(
134                 "Error - createDefinitionsFactory : Bad class name '"
135                     + classname
136                     + "'.",
137                 ex);
138 
139         } catch (InstantiationException ex) { // Bad constructor or error
140             throw new DefinitionsFactoryException(ex);
141 
142         } catch (IllegalAccessException ex) {
143             throw new DefinitionsFactoryException(ex);
144         }
145 
146     }
147 
148     /***
149     * Create default Definition factory.
150     * Factory must have a constructor taking ServletContext and Map as parameter.
151     * In this implementation, default factory is of class I18nFactorySet
152     * @param servletContext Servlet Context passed to newly created factory.
153     * @param properties Map of name/property passed to newly created factory.
154     * @return newly created factory.
155     * @throws DefinitionsFactoryException If an error occur while initializing factory
156     */
157     public ComponentDefinitionsFactory createDefaultFactory(
158         ServletContext servletContext,
159         Map properties)
160         throws DefinitionsFactoryException {
161 
162         ComponentDefinitionsFactory factory =
163             new I18nFactorySet(servletContext, properties);
164 
165         return factory;
166     }
167 
168     /***
169     * Create Definition factory.
170     * Convenience method. ServletConfig is wrapped into a Map allowing retrieval
171     * of init parameters. Factory classname is also retrieved, as well as debug level.
172     * Finally, approriate createDefinitionsFactory() is called.
173     * @param servletContext Servlet Context passed to newly created factory.
174     * @param properties Map containing all properties.
175     */
176     public ComponentDefinitionsFactory createFactory(
177         ServletContext servletContext,
178         Map properties)
179         throws DefinitionsFactoryException {
180 
181         String classname = (String) properties.get(DEFINITIONS_FACTORY_CLASSNAME);
182 
183         if (classname != null) {
184             return createFactoryFromClassname(servletContext, properties, classname);
185         }
186 
187         return new I18nFactorySet(servletContext, properties);
188     }
189 
190     /***
191      * Get a definition by its name.
192      * Call appropriate method on underlying factory instance.
193      * Throw appropriate exception if definition or definition factory is not found.
194      * @param definitionName Name of requested definition.
195      * @param request Current servlet request.
196      * @param servletContext Current servlet context.
197      * @throws FactoryNotFoundException Can't find definition factory.
198      * @throws DefinitionsFactoryException General error in factory while getting definition.
199      */
200     public ComponentDefinition getDefinition(
201         String definitionName,
202         ServletRequest request,
203         ServletContext servletContext)
204         throws FactoryNotFoundException, DefinitionsFactoryException {
205 
206         return factory.getDefinition(
207             definitionName,
208             (HttpServletRequest) request,
209             servletContext);
210     }
211 
212     /***
213      * Reload underlying factory.
214      * Reload is done by creating a new factory instance, and replacing the old instance
215      * with the new one.
216      * @param servletContext Current servlet context.
217      * @throws DefinitionsFactoryException If factory creation fails.
218      */
219     public void reload(ServletContext servletContext)
220         throws DefinitionsFactoryException {
221 
222         ComponentDefinitionsFactory newInstance =
223             createFactory(servletContext, properties);
224 
225         factory = newInstance;
226     }
227 
228     /***
229      * Get underlying factory instance.
230      * @return ComponentDefinitionsFactory
231      */
232     public ComponentDefinitionsFactory getFactory() {
233         return factory;
234     }
235 
236     /***
237       * Init factory.
238       * This method is required by interface ComponentDefinitionsFactory. It is
239       * not used in this implementation, as it manages itself the underlying creation
240       * and initialization.
241       * @param servletContext Servlet Context passed to newly created factory.
242       * @param properties Map of name/property passed to newly created factory.
243       * Map can contain more properties than requested.
244       * @throws DefinitionsFactoryException An error occur during initialization.
245     */
246     public void initFactory(ServletContext servletContext, Map properties)
247         throws DefinitionsFactoryException {
248         // do nothing
249     }
250 
251     /***
252      * Return String representation.
253      * @return String representation.
254      */
255     public String toString() {
256         return factory.toString();
257     }
258 
259     /***
260      * Inner class.
261      * Wrapper for ServletContext init parameters.
262      * Object of this class is an HashMap containing parameters and values
263      * defined in the servlet config file (web.xml).
264      */
265     class ServletPropertiesMap extends HashMap {
266         /***
267          * Constructor.
268          */
269         ServletPropertiesMap(ServletConfig config) {
270             // This implementation is very simple.
271             // It is possible to avoid creation of a new structure, but this would
272             // imply writing all of the Map interface.
273             Enumeration e = config.getInitParameterNames();
274             while (e.hasMoreElements()) {
275                 String key = (String) e.nextElement();
276                 put(key, config.getInitParameter(key));
277             }
278         }
279     } // end inner class
280 }