001: /*
002: * $Id: ReloadableDefinitionsFactory.java 471754 2006-11-06 14:55:09Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: package org.apache.struts.tiles.definition;
023:
024: import java.util.Enumeration;
025: import java.util.HashMap;
026: import java.util.Map;
027:
028: import javax.servlet.ServletConfig;
029: import javax.servlet.ServletContext;
030: import javax.servlet.ServletRequest;
031: import javax.servlet.http.HttpServletRequest;
032:
033: import org.apache.struts.tiles.ComponentDefinition;
034: import org.apache.struts.tiles.ComponentDefinitionsFactory;
035: import org.apache.struts.tiles.DefinitionsFactoryException;
036: import org.apache.struts.tiles.FactoryNotFoundException;
037: import org.apache.struts.tiles.xmlDefinition.I18nFactorySet;
038: import org.apache.struts.util.RequestUtils;
039:
040: /**
041: * A reloadable factory.
042: * This factory is the main entrance to any factory implementation. It takes in
043: * charge real implementation instance, and allows reloading by creating a new
044: * instance.
045: *
046: * @since Struts 1.1
047: * @version $Rev: 471754 $ $Date: 2006-11-06 08:55:09 -0600 (Mon, 06 Nov 2006) $
048: */
049: public class ReloadableDefinitionsFactory implements
050: ComponentDefinitionsFactory {
051:
052: /**
053: * The real factory instance.
054: */
055: protected ComponentDefinitionsFactory factory = null;
056:
057: /**
058: * Initialization parameters.
059: */
060: protected Map properties = null;
061:
062: /**
063: * Name of init property carrying factory class name.
064: */
065: public static final String DEFINITIONS_FACTORY_CLASSNAME = "definitions-factory-class";
066:
067: /**
068: * Constructor.
069: * Create a factory according to servlet settings.
070: * @param servletContext Our servlet context.
071: * @param servletConfig Our servlet config.
072: * @throws DefinitionsFactoryException If factory creation fail.
073: */
074: public ReloadableDefinitionsFactory(ServletContext servletContext,
075: ServletConfig servletConfig)
076: throws DefinitionsFactoryException {
077:
078: properties = new ServletPropertiesMap(servletConfig);
079: factory = createFactory(servletContext, properties);
080: }
081:
082: /**
083: * Constructor.
084: * Create a factory according to servlet settings.
085: * @param servletContext Our servlet context.
086: * @param properties Map containing all properties.
087: * @throws DefinitionsFactoryException If factory creation fail.
088: */
089: public ReloadableDefinitionsFactory(ServletContext servletContext,
090: Map properties) throws DefinitionsFactoryException {
091:
092: this .properties = properties;
093: factory = createFactory(servletContext, properties);
094: }
095:
096: /**
097: * Create Definition factory from provided classname.
098: * If a factory class name is provided, a factory of this class is created. Otherwise,
099: * 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, Map properties,
109: String classname) throws DefinitionsFactoryException {
110:
111: if (classname == null) {
112: return createFactory(servletContext, properties);
113: }
114:
115: // Try to create from classname
116: try {
117: Class factoryClass = RequestUtils
118: .applicationClass(classname);
119: ComponentDefinitionsFactory factory = (ComponentDefinitionsFactory) factoryClass
120: .newInstance();
121: factory.initFactory(servletContext, properties);
122: return factory;
123:
124: } catch (ClassCastException ex) { // Bad classname
125: throw new DefinitionsFactoryException(
126: "Error - createDefinitionsFactory : Factory class '"
127: + classname
128: + " must implements 'ComponentDefinitionsFactory'.",
129: ex);
130:
131: } catch (ClassNotFoundException ex) { // Bad classname
132: throw new DefinitionsFactoryException(
133: "Error - createDefinitionsFactory : Bad class name '"
134: + classname + "'.", ex);
135:
136: } catch (InstantiationException ex) { // Bad constructor or error
137: throw new DefinitionsFactoryException(ex);
138:
139: } catch (IllegalAccessException ex) {
140: throw new DefinitionsFactoryException(ex);
141: }
142:
143: }
144:
145: /**
146: * Create default Definition factory.
147: * Factory must have a constructor taking ServletContext and Map as parameter.
148: * In this implementation, default factory is of class I18nFactorySet
149: * @param servletContext Servlet Context passed to newly created factory.
150: * @param properties Map of name/property passed to newly created factory.
151: * @return newly created factory.
152: * @throws DefinitionsFactoryException If an error occur while initializing factory
153: */
154: public ComponentDefinitionsFactory createDefaultFactory(
155: ServletContext servletContext, Map properties)
156: throws DefinitionsFactoryException {
157:
158: ComponentDefinitionsFactory factory = new I18nFactorySet(
159: servletContext, properties);
160:
161: return factory;
162: }
163:
164: /**
165: * Create Definition factory.
166: * Convenience method. ServletConfig is wrapped into a Map allowing retrieval
167: * of init parameters. Factory classname is also retrieved, as well as debug level.
168: * Finally, approriate createDefinitionsFactory() is called.
169: * @param servletContext Servlet Context passed to newly created factory.
170: * @param properties Map containing all properties.
171: */
172: public ComponentDefinitionsFactory createFactory(
173: ServletContext servletContext, Map properties)
174: throws DefinitionsFactoryException {
175:
176: String classname = (String) properties
177: .get(DEFINITIONS_FACTORY_CLASSNAME);
178:
179: if (classname != null) {
180: return createFactoryFromClassname(servletContext,
181: properties, classname);
182: }
183:
184: return new I18nFactorySet(servletContext, properties);
185: }
186:
187: /**
188: * Get a definition by its name.
189: * Call appropriate method on underlying factory instance.
190: * Throw appropriate exception if definition or definition factory is not found.
191: * @param definitionName Name of requested definition.
192: * @param request Current servlet request.
193: * @param servletContext Current servlet context.
194: * @throws FactoryNotFoundException Can't find definition factory.
195: * @throws DefinitionsFactoryException General error in factory while getting definition.
196: */
197: public ComponentDefinition getDefinition(String definitionName,
198: ServletRequest request, ServletContext servletContext)
199: throws FactoryNotFoundException,
200: DefinitionsFactoryException {
201:
202: return factory.getDefinition(definitionName,
203: (HttpServletRequest) request, servletContext);
204: }
205:
206: /**
207: * Reload underlying factory.
208: * Reload is done by creating a new factory instance, and replacing the old instance
209: * with the new one.
210: * @param servletContext Current servlet context.
211: * @throws DefinitionsFactoryException If factory creation fails.
212: */
213: public void reload(ServletContext servletContext)
214: throws DefinitionsFactoryException {
215:
216: ComponentDefinitionsFactory newInstance = createFactory(
217: servletContext, properties);
218:
219: factory = newInstance;
220: }
221:
222: /**
223: * Get underlying factory instance.
224: * @return ComponentDefinitionsFactory
225: */
226: public ComponentDefinitionsFactory getFactory() {
227: return factory;
228: }
229:
230: /**
231: * Init factory.
232: * This method is required by interface ComponentDefinitionsFactory. It is
233: * not used in this implementation, as it manages itself the underlying creation
234: * and initialization.
235: * @param servletContext Servlet Context passed to newly created factory.
236: * @param properties Map of name/property passed to newly created factory.
237: * Map can contain more properties than requested.
238: * @throws DefinitionsFactoryException An error occur during initialization.
239: */
240: public void initFactory(ServletContext servletContext,
241: Map properties) throws DefinitionsFactoryException {
242: // do nothing
243: }
244:
245: /**
246: * Return String representation.
247: * @return String representation.
248: */
249: public String toString() {
250: return factory.toString();
251: }
252:
253: /**
254: * Inner class.
255: * Wrapper for ServletContext init parameters.
256: * Object of this class is an HashMap containing parameters and values
257: * defined in the servlet config file (web.xml).
258: */
259: class ServletPropertiesMap extends HashMap {
260: /**
261: * Constructor.
262: */
263: ServletPropertiesMap(ServletConfig config) {
264: // This implementation is very simple.
265: // It is possible to avoid creation of a new structure, but this would
266: // imply writing all of the Map interface.
267: Enumeration e = config.getInitParameterNames();
268: while (e.hasMoreElements()) {
269: String key = (String) e.nextElement();
270: put(key, config.getInitParameter(key));
271: }
272: }
273: } // end inner class
274: }
|