KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > struts > webapp > tiles > channel > ChannelFactorySet


1 /*
2  * $Id: ChannelFactorySet.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.webapp.tiles.channel;
20
21 import java.io.FileNotFoundException JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Map JavaDoc;
26 import javax.servlet.ServletContext JavaDoc;
27 import javax.servlet.ServletRequest JavaDoc;
28 import javax.servlet.http.HttpServletRequest JavaDoc;
29 import javax.servlet.http.HttpSession JavaDoc;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.struts.tiles.DefinitionsFactoryException;
33 import org.apache.struts.tiles.FactoryNotFoundException;
34 import org.apache.struts.tiles.xmlDefinition.DefinitionsFactory;
35 import org.apache.struts.tiles.xmlDefinition.FactorySet;
36 import org.apache.struts.tiles.xmlDefinition.XmlDefinitionsSet;
37 import org.apache.struts.tiles.xmlDefinition.XmlParser;
38 import org.xml.sax.SAXException JavaDoc;
39
40 /**
41  * Component Definitions factory.
42  * This implementation of Component Definitions factory allows i18n
43  * Component definitions factory allowing i18n definition.
44  * A definition is retrieved by its name, and using locale setted in appropriate
45  * session context. Definitions are defined in different files, one for each locale.
46  * A definition file is loaded using common name extended with locale code
47  * (ex : templateDefinitions_fr.xml). If no file is found under this name, use default
48  * file.
49  */

50 public class ChannelFactorySet extends FactorySet {
51
52     private static final Log log = LogFactory.getLog(ChannelFactorySet.class);
53
54     /**
55      * Debug flag.
56      * @deprecated This will be removed in a release after Struts 1.2.
57      */

58     public static final boolean debug = false;
59
60     /**
61      * Default name.
62      */

63     public static final String JavaDoc DEFAULT_DEFINITIONS_FILE_NAME =
64         "/WEB-INF/templateDefinitions.xml";
65
66     /**
67      * Config file parameter name.
68      */

69     public static final String JavaDoc DEFINITIONS_CONFIG_PARAMETER_NAME =
70         "definitions-config";
71
72     /**
73      * Config file parameter name.
74      */

75     public static final String JavaDoc FACTORY_SELECTOR_KEY =
76         "ChannelFactorySet.factorySelectorKey";
77
78     /**
79      * Default filenames extension.
80      */

81     public static final String JavaDoc FILENAME_EXTENSION = ".xml";
82
83     /**
84      * Default factory.
85      */

86     protected DefinitionsFactory defaultFactory = null;
87
88     /**
89      * Xml parser used.
90      */

91     protected XmlParser xmlParser = null;
92
93     /**
94      * Names of default file containing definition descriptions.
95      */

96     private String JavaDoc filename = null;
97
98     /**
99      * Collection of already loaded definitions set, referenced by their suffix.
100      */

101     private Map JavaDoc loaded = null;
102
103     /**
104      * Parameterless Constructor.
105      * Method initFactory must be called prior to any use of created factory.
106      */

107     public ChannelFactorySet() {
108         super();
109     }
110
111     /**
112      * Constructor.
113      * Init the factory by reading appropriate configuration file.
114      * @throws FactoryNotFoundException Can't find factory configuration file.
115      */

116     public ChannelFactorySet(ServletContext JavaDoc servletContext, Map JavaDoc properties)
117         throws DefinitionsFactoryException {
118
119         initFactory(servletContext, properties);
120     }
121
122     /**
123      * Initialization method.
124      * Init the factory by reading appropriate configuration file.
125      * This method is called exactly once immediately after factory creation in
126      * case of internal creation (by DefinitionUtil).
127      * @param servletContext Servlet Context passed to newly created factory.
128      * @param properties Map of name/property passed to newly created factory. Map can contains
129      * more properties than requested.
130      * @throws DefinitionsFactoryException An error occur during initialization.
131      */

132     public void initFactory(ServletContext JavaDoc servletContext, Map JavaDoc properties)
133         throws DefinitionsFactoryException {
134
135         // read properties values
136
String JavaDoc proposedFilename =
137             (String JavaDoc) properties.get(DEFINITIONS_CONFIG_PARAMETER_NAME);
138
139         // Compute filenames to use
140
boolean isFileSpecified = true;
141         if (proposedFilename == null) {
142             proposedFilename = DEFAULT_DEFINITIONS_FILE_NAME;
143             isFileSpecified = false;
144         }
145
146         try {
147             initFactory(servletContext, proposedFilename);
148             return;
149
150         } catch (FileNotFoundException JavaDoc ex) {
151             // If a filename is specified, throw appropriate error.
152
if (isFileSpecified) {
153                 throw new FactoryNotFoundException(
154                     ex.getMessage()
155                         + " : Can't find file '"
156                         + proposedFilename
157                         + "'");
158             }
159         }
160
161     }
162
163     /**
164      * Initialization method.
165      * Init the factory by reading appropriate configuration file.
166      * This method is called exactly once immediately after factory creation in
167      * case of internal creation (by DefinitionUtil).
168      * @param servletContext Servlet Context passed to newly created factory.
169      * @param proposedFilename File names, comma separated, to use as base file names.
170      * @throws DefinitionsFactoryException An error occur during initialization.
171      */

172     protected void initFactory(
173         ServletContext JavaDoc servletContext,
174         String JavaDoc proposedFilename)
175         throws DefinitionsFactoryException, FileNotFoundException JavaDoc {
176
177         filename = proposedFilename;
178         loaded = new HashMap JavaDoc();
179         defaultFactory = createDefaultFactory(servletContext);
180     }
181
182     /**
183      * Get default factory.
184      * @return Default factory
185      */

186     protected DefinitionsFactory getDefaultFactory() {
187         return defaultFactory;
188     }
189
190     /**
191      * Create default factory .
192      * @param servletContext Current servlet context. Used to open file.
193      * @return Created default definition factory.
194      * @throws DefinitionsFactoryException If an error occur while creating factory.
195      * @throws FileNotFoundException if factory can't be loaded from filenames.
196      */

197     protected DefinitionsFactory createDefaultFactory(ServletContext JavaDoc servletContext)
198         throws DefinitionsFactoryException, FileNotFoundException JavaDoc {
199
200         XmlDefinitionsSet rootXmlConfig = parseXmlKeyFile(servletContext, "", null);
201
202         if (rootXmlConfig == null) {
203             throw new FileNotFoundException JavaDoc();
204         }
205
206         rootXmlConfig.resolveInheritances();
207         return new DefinitionsFactory(rootXmlConfig);
208     }
209
210     /**
211      * Extract key that will be used to get the sub factory.
212      * @param name Name of requested definition
213      * @param request Current servlet request.
214      * @param servletContext Current servlet context
215      * @return the key or null if not found.
216      * @roseuid 3AF6F887018A
217      */

218     protected Object JavaDoc getDefinitionsFactoryKey(
219         String JavaDoc name,
220         ServletRequest JavaDoc request,
221         ServletContext JavaDoc servletContext) {
222         Object JavaDoc key = null;
223
224         HttpSession JavaDoc session = ((HttpServletRequest JavaDoc) request).getSession(false);
225         if (session != null) {
226             key = session.getAttribute(FACTORY_SELECTOR_KEY);
227         }
228
229         return key;
230     }
231
232     /**
233      * Create a factory for specified key.
234      * If creation failed, return default factory, and output an error message in
235      * console.
236      * @param key
237      * @return Definition factory for specified key.
238      * @throws DefinitionsFactoryException If an error occur while creating factory.
239      */

240     protected DefinitionsFactory createFactory(
241         Object JavaDoc key,
242         ServletRequest JavaDoc request,
243         ServletContext JavaDoc servletContext)
244         throws DefinitionsFactoryException {
245
246         if (key == null) {
247             return getDefaultFactory();
248         }
249
250         // Already loaded ?
251
DefinitionsFactory factory = (DefinitionsFactory) loaded.get(key);
252         if (factory != null) { // yes, stop loading
253
return factory;
254         }
255
256         // Try to load file associated to key. If fail, stop and return default factory.
257
XmlDefinitionsSet lastXmlFile =
258             parseXmlKeyFile(servletContext, "_" + (String JavaDoc) key, null);
259
260         if (lastXmlFile == null) {
261             log.warn(
262                 "No definition factory associated to key '"
263                     + key
264                     + "'. Use default factory instead.");
265
266             factory = getDefaultFactory();
267             loaded.put(key, factory);
268             return factory;
269         }
270
271         // Parse default file, and add key file.
272
XmlDefinitionsSet rootXmlConfig = parseXmlKeyFile(servletContext, "", null);
273
274         rootXmlConfig.extend(lastXmlFile);
275         rootXmlConfig.resolveInheritances();
276
277         factory = new DefinitionsFactory(rootXmlConfig);
278         loaded.put(key, factory);
279
280         log.info(factory);
281
282         // return last available found !
283
return factory;
284     }
285
286     /**
287      * Parse files associated to postix if they exist.
288      * For each name in filenames, append postfix before file extension,
289      * then try to load the corresponding file.
290      * If file doesn't exist, try next one. Each file description is added to
291      * the XmlDefinitionsSet description.
292      * The XmlDefinitionsSet description is created only if there is a definition file.
293      * Inheritance is not resolved in the returned XmlDefinitionsSet.
294      * If no description file can be opened, and no definiion set is provided, return null.
295      * @param postfix Postfix to add to each description file.
296      * @param xmlDefinitions Definitions set to which definitions will be added. If null, a definitions
297      * set is created on request.
298      * @return XmlDefinitionsSet The definitions set created or passed as parameter.
299      * @throws DefinitionsFactoryException If an error happen during file parsing.
300      */

301     private XmlDefinitionsSet parseXmlKeyFile(
302         ServletContext JavaDoc servletContext,
303         String JavaDoc postfix,
304         XmlDefinitionsSet xmlDefinitions)
305         throws DefinitionsFactoryException {
306         if (postfix != null && postfix.length() == 0)
307             postfix = null;
308
309         String JavaDoc fullName = concatPostfix(filename, postfix);
310         return parseXmlFile(servletContext, fullName, xmlDefinitions);
311     }
312
313     /**
314      * Parse specified xml file and add definition to specified definitions set.
315      * This method is used to load several description files in one instances list.
316      * If filename exist and definition set is null, create a new set. Otherwise, return
317      * passed definition set (can be null).
318      * @param servletContext Current servlet context. Used to open file.
319      * @param filename Name of file to parse.
320      * @param xmlDefinitions Definitions set to which definitions will be added. If null, a definitions
321      * set is created on request.
322      * @return XmlDefinitionsSet The definitions set created or passed as parameter.
323      * @throws DefinitionsFactoryException If an error happen during file parsing.
324      */

325     private XmlDefinitionsSet parseXmlFile(
326         ServletContext JavaDoc servletContext,
327         String JavaDoc filename,
328         XmlDefinitionsSet xmlDefinitions)
329         throws DefinitionsFactoryException {
330
331         try {
332             log.debug("Trying to load '" + filename + "'.");
333
334             InputStream JavaDoc input = servletContext.getResourceAsStream(filename);
335             if (input == null) {
336                 return xmlDefinitions;
337             }
338
339             xmlParser = new XmlParser();
340
341             // Check if definition set already exist.
342
if (xmlDefinitions == null) {
343                 xmlDefinitions = new XmlDefinitionsSet();
344             }
345
346             xmlParser.parse(input, xmlDefinitions);
347
348         } catch (SAXException JavaDoc ex) {
349             log.debug("Error while parsing file '" + filename + "'.", ex);
350
351             throw new DefinitionsFactoryException(
352                 "Error while parsing file '" + filename + "'. " + ex.getMessage(),
353                 ex);
354
355         } catch (IOException JavaDoc ex) {
356             throw new DefinitionsFactoryException(
357                 "IO Error while parsing file '" + filename + "'. " + ex.getMessage(),
358                 ex);
359         }
360
361         return xmlDefinitions;
362     }
363
364     /**
365      * Concat postfix to the name. Take care of existing filename extension.
366      * Transform the given name "name.ext" to have "name" + "postfix" + "ext".
367      * If there is no ext, return "name" + "postfix".
368      */

369     private String JavaDoc concatPostfix(String JavaDoc name, String JavaDoc postfix) {
370         if (postfix == null) {
371             return name;
372         }
373
374         //postfix = "_" + postfix;
375
// Search file name extension.
376
// take care of Unix files starting with .
377
int dotIndex = name.lastIndexOf(".");
378         int lastNameStart = name.lastIndexOf(java.io.File.pathSeparator);
379         if (dotIndex < 1 || dotIndex < lastNameStart)
380             return name + postfix;
381
382         String JavaDoc ext = name.substring(dotIndex);
383         name = name.substring(0, dotIndex);
384         return name + postfix + ext;
385     }
386
387 }
388
Popular Tags