1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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) {
126 throw new DefinitionsFactoryException(
127 "Error - createDefinitionsFactory : Factory class '"
128 + classname
129 + " must implements 'ComponentDefinitionsFactory'.",
130 ex);
131
132 } catch (ClassNotFoundException ex) {
133 throw new DefinitionsFactoryException(
134 "Error - createDefinitionsFactory : Bad class name '"
135 + classname
136 + "'.",
137 ex);
138
139 } catch (InstantiationException ex) {
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
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
271
272
273 Enumeration e = config.getInitParameterNames();
274 while (e.hasMoreElements()) {
275 String key = (String) e.nextElement();
276 put(key, config.getInitParameter(key));
277 }
278 }
279 }
280 }