KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > myvietnam > mvncore > configuration > ConfigurationFactory


1 package net.myvietnam.mvncore.configuration;
2 /* ====================================================================
3  * The Apache Software License, Version 1.1
4  *
5  * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution, if
21  * any, must include the following acknowledgement:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgement may appear in the software itself,
25  * if and wherever such third-party acknowledgements normally appear.
26  *
27  * 4. The names "The Jakarta Project", "Commons", and "Apache Software
28  * Foundation" must not be used to endorse or promote products derived
29  * from this software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache"
33  * nor may "Apache" appear in their names without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation. For more
52  * information on the Apache Software Foundation, please see
53  * <http://www.apache.org/>.
54  */

55 import java.io.File JavaDoc;
56 import java.io.InputStream JavaDoc;
57 import java.net.URL JavaDoc;
58 import java.util.Collection JavaDoc;
59 import java.util.Iterator JavaDoc;
60 import java.util.LinkedList JavaDoc;
61 import java.util.Stack JavaDoc;
62
63 import org.apache.commons.digester.AbstractObjectCreationFactory;
64 import org.apache.commons.digester.Digester;
65 import org.apache.commons.digester.ObjectCreationFactory;
66 import org.apache.commons.digester.xmlrules.DigesterLoader;
67 import org.apache.commons.lang.StringUtils;
68 import org.apache.commons.logging.Log;
69 import org.apache.commons.logging.LogFactory;
70 import org.xml.sax.Attributes JavaDoc;
71 import org.xml.sax.SAXException JavaDoc;
72 /**
73  * Factory class to create a CompositeConfiguration from a .xml file using
74  * Digester. By default it can handle the Configurations from commons-
75  * configuration. If you need to add your own, then you can pass in your own
76  * digester rules to use. It is also namespace aware, by providing a
77  * digesterRuleNamespaceURI.
78  *
79  * @author <a HREF="mailto:epugh@upstate.com">Eric Pugh</a>
80  * @author <a HREF="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
81  * @author <a HREF="mailto:oliver.heger@t-online.de">Oliver Heger</a>
82  * @version $Id: ConfigurationFactory.java,v 1.1 2003/12/09 08:25:30 huumai Exp $
83  */

84 public class ConfigurationFactory implements BasePathLoader
85 {
86     /** Constant for the root element in the info file.*/
87     private static final String JavaDoc SEC_ROOT = "configuration/";
88
89     /** Constant for the override section.*/
90     private static final String JavaDoc SEC_OVERRIDE = SEC_ROOT + "override/";
91
92     /** Constant for the additional section.*/
93     private static final String JavaDoc SEC_ADDITIONAL = SEC_ROOT + "additional/";
94
95     /** Constant for the name of the load method.*/
96     private static final String JavaDoc METH_LOAD = "load";
97
98     /** Constant for the default base path (points to actual directory).*/
99     private static final String JavaDoc DEF_BASE_PATH = ".";
100
101     /** The XML file with the details about the configuration to load */
102     private String JavaDoc configurationFileName;
103     /** The URL to the XML file with the details about the configuration to
104      * load.
105      */

106     private URL JavaDoc configurationURL;
107     /**
108      * The implicit base path for included files. This path is determined by
109      * the configuration to load and used unless no other base path was
110      * explicitely specified.
111      */

112     private String JavaDoc impliciteBasePath;
113     /** The basePath to prefix file paths for file based property files. */
114     private String JavaDoc basePath;
115     /** static logger */
116     private static Log log = LogFactory.getLog(ConfigurationFactory.class);
117     /** URL for xml digester rules file */
118     private URL JavaDoc digesterRules;
119     /** The digester namespace to parse */
120     private String JavaDoc digesterRuleNamespaceURI;
121     /**
122      * C'tor
123      */

124     public ConfigurationFactory()
125     {
126         setBasePath(DEF_BASE_PATH);
127     }
128     /**
129      * C'tor with ConfigurationFile Name passed
130      *
131      * @param configurationFileName The path to the configuration file
132      */

133     public ConfigurationFactory(String JavaDoc configurationFileName)
134     {
135         this.configurationFileName = configurationFileName;
136     }
137     /**
138      * Return the configuration provided by this factory. It
139      * loads the configuration file which is a XML description of
140      * the actual configurations to load. It can contain various
141      * different types of configuration, currently Properties, XML and JNDI.
142      *
143      * @return A Configuration object
144      * @throws Exception A generic exception that we had trouble during the
145      * loading of the configuration data.
146      */

147     public Configuration getConfiguration() throws Exception JavaDoc
148     {
149         Digester digester;
150         ConfigurationBuilder builder = new ConfigurationBuilder();
151         URL JavaDoc url = getConfigurationURL();
152         if(url == null)
153         {
154             url = ConfigurationUtils.getURL(impliciteBasePath,
155             getConfigurationFileName());
156         } /* if */
157         InputStream JavaDoc input = url.openStream();
158
159         if (getDigesterRules() == null)
160         {
161             digester = new Digester();
162             configureNamespace(digester);
163             initDefaultDigesterRules(digester);
164         }
165         else
166         {
167             digester = DigesterLoader.createDigester(getDigesterRules());
168             // This might already be too late. As far as I can see, the namespace
169
// awareness must be configured before the digester rules are loaded.
170
configureNamespace(digester);
171         }
172         // Put the composite builder object below all of the other objects.
173
digester.push(builder);
174         // Parse the input stream to configure our mappings
175
try
176         {
177             digester.parse(input);
178             input.close();
179         }
180         catch (SAXException JavaDoc e)
181         {
182             log.error("SAX Exception caught", e);
183             throw e;
184         }
185         return builder.getConfiguration();
186     }
187     /**
188      * Returns the configurationFile.
189      *
190      * @return The name of the configuration file. Can be null.
191      */

192     public String JavaDoc getConfigurationFileName()
193     {
194         return configurationFileName;
195     }
196     /**
197      * Sets the configurationFile.
198      * @param configurationFileName The name of the configurationFile to use.
199      */

200     public void setConfigurationFileName(String JavaDoc configurationFileName)
201     {
202         File JavaDoc file = new File JavaDoc(configurationFileName).getAbsoluteFile();
203         this.configurationFileName = file.getName();
204         impliciteBasePath = file.getParent();
205     }
206
207     /**
208      * Returns the URL of the configuration file to be loaded.
209      * @return the URL of the configuration to load
210      */

211     public URL JavaDoc getConfigurationURL()
212     {
213         return configurationURL;
214     }
215
216     /**
217      * Sets the URL of the configuration to load. This configuration can be
218      * either specified by a file name or by a URL.
219      * @param url the URL of the configuration to load
220      */

221     public void setConfigurationURL(URL JavaDoc url)
222     {
223         configurationURL = url;
224         impliciteBasePath = url.toString();
225
226         // The following is a hack caused by the need to keep backwards
227
// compatibility: Per default the base path is set to the current
228
// directory. For loading from a URL this makes no sense. So
229
// unless no specific base path was set we clear it.
230
if(DEF_BASE_PATH.equals(getBasePath()))
231         {
232             setBasePath(null);
233         } /* if */
234     }
235
236     /**
237      * Returns the digesterRules.
238      * @return URL
239      */

240     public URL JavaDoc getDigesterRules()
241     {
242         return digesterRules;
243     }
244     /**
245      * Sets the digesterRules.
246      * @param digesterRules The digesterRules to set
247      */

248     public void setDigesterRules(URL JavaDoc digesterRules)
249     {
250         this.digesterRules = digesterRules;
251     }
252     /**
253      * Initializes the parsing rules for the default digester
254      *
255      * This allows the Configuration Factory to understand the
256      * default types: Properties, XML and JNDI. Two special sections are
257      * introduced: <code>&lt;override&gt;</code> and
258      * <code>&lt;additional&gt;</code>.
259      *
260      * @param digester The digester to configure
261      */

262     protected void initDefaultDigesterRules(Digester digester)
263     {
264         initDigesterSectionRules(digester, SEC_ROOT, false);
265         initDigesterSectionRules(digester, SEC_OVERRIDE, false);
266         initDigesterSectionRules(digester, SEC_ADDITIONAL, true);
267     }
268
269     /**
270      * Sets up digester rules for a specified section of the configuration
271      * info file.
272      * @param digester the current digester instance
273      * @param matchString specifies the section
274      * @param additional a flag if rules for the additional section are to be
275      * added
276      */

277     protected void initDigesterSectionRules(Digester digester,
278     String JavaDoc matchString, boolean additional)
279     {
280         setupDigesterInstance(
281             digester,
282             matchString + "properties",
283             new BasePathConfigurationFactory(PropertiesConfiguration.class),
284             METH_LOAD,
285             additional);
286         setupDigesterInstance(
287             digester,
288             matchString + "dom4j",
289             new BasePathConfigurationFactory(DOM4JConfiguration.class),
290             METH_LOAD,
291             additional);
292         setupDigesterInstance(
293             digester,
294             matchString + "hierarchicalDom4j",
295             new BasePathConfigurationFactory(HierarchicalDOM4JConfiguration.class),
296             METH_LOAD,
297             additional);
298         setupDigesterInstance(
299             digester,
300             matchString + "jndi",
301             new JNDIConfigurationFactory(),
302             null,
303             additional);
304     }
305
306     /**
307      * Sets up digester rules for a configuration to be loaded.
308      * @param digester the current digester
309      * @param matchString the pattern to match with this rule
310      * @param factory an ObjectCreationFactory instance to use for creating new
311      * objects
312      * @param method the name of a method to be called or <b>null</b> for none
313      * @param additional a flag if rules for the additional section are to be
314      * added
315      */

316     protected void setupDigesterInstance(
317         Digester digester,
318         String JavaDoc matchString,
319         ObjectCreationFactory factory,
320         String JavaDoc method,
321         boolean additional)
322     {
323         if(additional)
324         {
325             setupUnionRules(digester, matchString);
326         } /* if */
327         digester.addFactoryCreate(matchString, factory);
328         digester.addSetProperties(matchString);
329         if(method != null)
330         {
331             digester.addCallMethod(matchString, method);
332         } /* if */
333         digester.addSetNext(
334             matchString,
335             "addConfiguration",
336             Configuration.class.getName());
337     }
338
339     /**
340      * Sets up rules for configurations in the additional section.
341      * @param digester the current digester
342      * @param matchString the pattern to match with this rule
343      */

344     protected void setupUnionRules(Digester digester, String JavaDoc matchString)
345     {
346         digester.addObjectCreate(matchString,
347         AdditionalConfigurationData.class);
348         digester.addSetProperties(matchString);
349         digester.addSetNext(matchString, "addAdditionalConfig",
350         AdditionalConfigurationData.class.getName());
351     }
352     /**
353      * Returns the digesterRuleNamespaceURI.
354      *
355      * @return A String with the digesterRuleNamespaceURI.
356      */

357     public String JavaDoc getDigesterRuleNamespaceURI()
358     {
359         return digesterRuleNamespaceURI;
360     }
361     /**
362      * Sets the digesterRuleNamespaceURI.
363      *
364      * @param digesterRuleNamespaceURI The new digesterRuleNamespaceURI to use
365      */

366     public void setDigesterRuleNamespaceURI(String JavaDoc digesterRuleNamespaceURI)
367     {
368         this.digesterRuleNamespaceURI = digesterRuleNamespaceURI;
369     }
370     /**
371      * Configure the current digester to be namespace aware and to have
372      * a Configuration object to which all of the other configurations
373      * should be added
374      *
375      * @param digester The Digester to configure
376      */

377     private void configureNamespace(Digester digester)
378     {
379         if (getDigesterRuleNamespaceURI() != null)
380         {
381             digester.setNamespaceAware(true);
382             digester.setRuleNamespaceURI(getDigesterRuleNamespaceURI());
383         }
384         else
385         {
386             digester.setNamespaceAware(false);
387         }
388         digester.setValidating(false);
389     }
390     /**
391      * Returns the Base path from which this Configuration Factory operates.
392      * This is never null. If you set the BasePath to null, then a base path
393      * according to the configuration to load is returned.
394      *
395      * @return The base Path of this configuration factory.
396      */

397     public String JavaDoc getBasePath()
398     {
399         String JavaDoc path = StringUtils.isEmpty(basePath) ?
400         impliciteBasePath : basePath;
401         return StringUtils.isEmpty(path) ? "." : path;
402     }
403     /**
404      * Sets the basePath for all file references from this Configuration Factory.
405      * Normally a base path need not to be set because it is determined by
406      * the location of the configuration file to load. All relative pathes in
407      * this file are resolved relative to this file. Setting a base path makes
408      * sense if such relative pathes should be otherwise resolved, e.g. if
409      * the configuration file is loaded from the class path and all sub
410      * configurations it refers to are stored in a special config directory.
411      *
412      * @param basePath The new basePath to set.
413      */

414     public void setBasePath(String JavaDoc basePath)
415     {
416         this.basePath = basePath;
417     }
418
419     /**
420      * A base class for digester factory classes. This base class maintains
421      * a default class for the objects to be created.
422      * There will be sub classes for specific configuration implementations.
423      */

424     public class DigesterConfigurationFactory
425         extends AbstractObjectCreationFactory
426         implements ObjectCreationFactory
427     {
428         /** Actual class to use. */
429         private Class JavaDoc clazz;
430
431         /**
432          * Creates a new instance of <code>DigesterConfigurationFactory</code>.
433          * @param clazz the class which we should instantiate
434          */

435         public DigesterConfigurationFactory(Class JavaDoc clazz)
436         {
437             this.clazz = clazz;
438         }
439
440         /**
441          * Creates an instance of the specified class.
442          * @param attribs the attributes (ignored)
443          * @return the new object
444          * @exception Exception if object creation fails
445          */

446         public Object JavaDoc createObject(Attributes JavaDoc attribs) throws Exception JavaDoc
447         {
448             return clazz.newInstance();
449         }
450     }
451
452     /**
453      * A tiny inner class that allows the Configuration Factory to
454      * let the digester construct BasePathConfiguration objects
455      * that already have the correct base Path set.
456      *
457      */

458     public class BasePathConfigurationFactory
459         extends DigesterConfigurationFactory
460     {
461         /**
462          * C'tor
463          *
464          * @param clazz The class which we should instantiate.
465          */

466         public BasePathConfigurationFactory(Class JavaDoc clazz)
467         {
468             super(clazz);
469         }
470
471         /**
472          * Gets called by the digester.
473          *
474          * @param attributes the actual attributes
475          * @return the new object
476          * @throws Exception Couldn't instantiate the requested object.
477          */

478         public Object JavaDoc createObject(Attributes JavaDoc attributes) throws Exception JavaDoc
479         {
480             BasePathLoader bpl =
481                 (BasePathLoader) super.createObject(attributes);
482             bpl.setBasePath(getBasePath());
483             return bpl;
484         }
485     }
486
487     /**
488      * A tiny inner class that allows the Configuration Factory to
489      * let the digester construct JNDIPathConfiguration objects.
490      *
491      */

492     public class JNDIConfigurationFactory
493         extends DigesterConfigurationFactory
494     {
495         /**
496          * C'tor
497          */

498         public JNDIConfigurationFactory()
499         {
500             super(JNDIConfiguration.class);
501         }
502     }
503
504     /**
505      * A simple data class that holds all information about a configuration
506      * from the <code>&lt;additional&gt;</code> section.
507      */

508     public static class AdditionalConfigurationData
509     {
510         /** Stores the configuration object.*/
511         private Configuration configuration;
512
513         /** Stores the location of this configuration in the global tree.*/
514         private String JavaDoc at;
515
516         /**
517          * Returns the value of the <code>at</code> attribute.
518          * @return the at attribute
519          */

520         public String JavaDoc getAt()
521         {
522             return at;
523         }
524
525         /**
526          * Sets the value of the <code>at</code> attribute.
527          * @param string the attribute value
528          */

529         public void setAt(String JavaDoc string)
530         {
531             at = string;
532         }
533
534         /**
535          * Returns the configuration object.
536          * @return the configuration
537          */

538         public Configuration getConfiguration()
539         {
540             return configuration;
541         }
542
543         /**
544          * Sets the configuration object. Note: Normally this method should be
545          * named <code>setConfiguration()</code>, but the name
546          * <code>addConfiguration()</code> is required by some of the digester
547          * rules.
548          * @param config the configuration to set
549          */

550         public void addConfiguration(Configuration config)
551         {
552             configuration = config;
553         }
554     }
555
556     /**
557      * An internally used helper class for constructing the composite
558      * configuration object.
559      */

560     public static class ConfigurationBuilder
561     {
562         /** Stores the composite configuration.*/
563         private CompositeConfiguration config;
564
565         /** Stores a collection with the configs from the additional section.*/
566         private Collection JavaDoc additionalConfigs;
567
568         /**
569          * Creates a new instance of <code>ConfigurationBuilder</code>.
570          */

571         public ConfigurationBuilder()
572         {
573             config = new CompositeConfiguration();
574             additionalConfigs = new LinkedList JavaDoc();
575         }
576
577         /**
578          * Adds a new configuration to this object. This method is called by
579          * Digester.
580          * @param conf the configuration to be added
581          */

582         public void addConfiguration(Configuration conf)
583         {
584             config.addConfiguration(conf);
585         }
586
587         /**
588          * Adds information about an additional configuration. This method is
589          * called by Digester.
590          * @param data the data about the additional configuration
591          */

592         public void addAdditionalConfig(AdditionalConfigurationData data)
593         {
594             additionalConfigs.add(data);
595         }
596
597         /**
598          * Returns the final composite configuration.
599          * @return the final configuration object
600          */

601         public CompositeConfiguration getConfiguration()
602         {
603             if(!additionalConfigs.isEmpty())
604             {
605                 Configuration unionConfig =
606                 createAdditionalConfiguration(additionalConfigs);
607                 if(unionConfig != null)
608                 {
609                     addConfiguration(unionConfig);
610                 } /* if */
611                 additionalConfigs.clear();
612             } /* if */
613
614             return config;
615         }
616
617         /**
618          * Creates a configuration object with the union of all properties
619          * defined in the <code>&lt;additional&gt;</code> section. This
620          * implementation returns a <code>HierarchicalConfiguration</code>
621          * object.
622          * @param configs a collection with
623          * <code>AdditionalConfigurationData</code> objects
624          * @return the union configuration (can be <b>null</b>)
625          */

626         protected Configuration createAdditionalConfiguration(
627         Collection JavaDoc configs)
628         {
629             HierarchicalConfiguration result = new HierarchicalConfiguration();
630
631             for(Iterator JavaDoc it = configs.iterator(); it.hasNext();)
632             {
633                 AdditionalConfigurationData cdata =
634                 (AdditionalConfigurationData) it.next();
635                 result.addNodes(cdata.getAt(),
636                 createRootNode(cdata).getChildren().asVector());
637             } /* for */
638
639             return (result.isEmpty()) ? null : result;
640         }
641
642         /**
643          * Creates a configuration root node for the specified configuration.
644          * @param cdata the configuration data object
645          * @return a root node for this configuration
646          */

647         private HierarchicalConfiguration.Node createRootNode(
648         AdditionalConfigurationData cdata)
649         {
650             if(cdata.getConfiguration() instanceof HierarchicalConfiguration)
651             {
652                 // we can directly use this configuration's root node
653
return ((HierarchicalConfiguration) cdata.getConfiguration())
654                 .getRoot();
655             } /* if */
656
657             else
658             {
659                 // transform configuration to a hierarchical root node
660
HierarchicalConfigurationNodeConverter conv =
661                 new HierarchicalConfigurationNodeConverter();
662                 conv.process(cdata.getConfiguration());
663                 return conv.getRootNode();
664             } /* else */
665         }
666     }
667
668     /**
669      * A specialized <code>HierarchicalConfigurationConverter</code> class
670      * that creates a <code>HierarchicalConfiguration</code> root node from
671      * an arbitrary <code>Configuration</code> object. This class is used to
672      * add additional configuration objects to the hierarchical configuration
673      * managed by the <code>ConfigurationBuilder</code>.
674      */

675     static class HierarchicalConfigurationNodeConverter
676     extends HierarchicalConfigurationConverter
677     {
678         /** A stack for constructing the hierarchy.*/
679         private Stack JavaDoc nodes;
680
681         /** Stores the root node.*/
682         private HierarchicalConfiguration.Node root;
683
684         /**
685          * Default constructor.
686          */

687         public HierarchicalConfigurationNodeConverter()
688         {
689             nodes = new Stack JavaDoc();
690             root = new HierarchicalConfiguration.Node();
691             nodes.push(root);
692         }
693
694         /**
695          * Callback for an element start event. Creates a new node and adds
696          * it to the actual parent.
697          * @param name the name of the new node
698          * @param value the node's value
699          */

700         protected void elementStart(String JavaDoc name, Object JavaDoc value)
701         {
702             HierarchicalConfiguration.Node parent =
703             (HierarchicalConfiguration.Node) nodes.peek();
704             HierarchicalConfiguration.Node child =
705             new HierarchicalConfiguration.Node(name);
706             if(value != null)
707             {
708                 child.setValue(value);
709             } /* if */
710             parent.addChild(child);
711             nodes.push(child);
712         }
713
714         /**
715          * Callback for an element end event. Clears the stack.
716          * @param name the name of the element
717          */

718         protected void elementEnd(String JavaDoc name)
719         {
720             nodes.pop();
721         }
722
723         /**
724          * Returns the constructed root node.
725          * @return the root node
726          */

727         public HierarchicalConfiguration.Node getRootNode()
728         {
729             return root;
730         }
731     }
732 }
733
Popular Tags