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