View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.chain.config;
18  
19  import java.net.URL;
20  
21  import org.apache.commons.chain.Catalog;
22  import org.apache.commons.digester.Digester;
23  import org.apache.commons.digester.RuleSet;
24  
25  /**
26   * Class to parse the contents of an XML configuration file (using
27   * Commons Digester) that defines and configures commands and command chains
28   * to be registered in a {@link Catalog}. Advanced users can configure the
29   * detailed parsing behavior by configuring the properties of an instance
30   * of this class prior to calling the {@code parse()} method. It
31   * is legal to call the {@code parse()} method more than once, in order
32   * to parse more than one configuration document.
33   *
34   * @author Craig R. McClanahan
35   * @version $Revision$ $Date$
36   */
37  public class ConfigParser {
38  
39      // ----------------------------------------------------- Instance Variables
40  
41      /**
42       * The {@code Digester} to be used for parsing.
43       */
44      private Digester digester = null;
45  
46      /**
47       * The {@code RuleSet} to be used for configuring our Digester
48       * parsing rules.
49       */
50      private RuleSet ruleSet = null;
51  
52      /**
53       * Should Digester use the context class loader?
54       */
55      private boolean useContextClassLoader = true;
56  
57      // ----------------------------------------------------------- Constructors
58  
59      /**
60       * The Default-Constructor for this class.
61       */
62      public ConfigParser() {
63      }
64  
65      // ------------------------------------------------------------- Properties
66  
67      /**
68       * Return the {@code Digester} instance to be used for
69       * parsing, creating one if necessary.
70       *
71       * @return A Digester instance.
72       */
73      public Digester getDigester() {
74          if (digester == null) {
75              digester = new Digester();
76              RuleSet ruleSet = getRuleSet();
77              digester.setNamespaceAware(ruleSet.getNamespaceURI() != null);
78              digester.setUseContextClassLoader(getUseContextClassLoader());
79              digester.setValidating(false);
80              digester.addRuleSet(ruleSet);
81          }
82          return digester;
83      }
84  
85      /**
86       * Return the {@code RuleSet} to be used for configuring
87       * our {@code Digester} parsing rules, creating one if necessary.
88       *
89       * @return The RuleSet for configuring a Digester instance.
90       */
91      public RuleSet getRuleSet() {
92          if (ruleSet == null) {
93              ruleSet = new ConfigRuleSet();
94          }
95          return ruleSet;
96      }
97  
98      /**
99       * Set the {@code RuleSet} to be used for configuring
100      * our {@code Digester} parsing rules.
101      *
102      * @param ruleSet The new RuleSet to use
103      */
104     public void setRuleSet(RuleSet ruleSet) {
105         this.digester = null;
106         this.ruleSet = ruleSet;
107     }
108 
109     /**
110      * Return the "use context class loader" flag. If set to
111      * {@code true}, Digester will attempt to instantiate new
112      * command and chain instances from the context class loader.
113      *
114      * @return {@code true} if Digester should use the context class loader.
115      */
116     public boolean getUseContextClassLoader() {
117         return this.useContextClassLoader;
118     }
119 
120     /**
121      * Set the "use context class loader" flag.
122      *
123      * @param useContextClassLoader The new flag value
124      */
125     public void setUseContextClassLoader(boolean useContextClassLoader) {
126         this.useContextClassLoader = useContextClassLoader;
127     }
128 
129     // --------------------------------------------------------- Public Methods
130 
131     /**
132      * Parse the XML document at the specified URL, using the configured
133      * {@code RuleSet}, registering top level commands into the specified
134      * {@link Catalog}. Use this method <strong>only</strong> if you have
135      * <strong>NOT</strong> included any {@code factory} element in your
136      * configuration resource, and wish to supply the catalog explicitly.
137      *
138      * @param catalog {@link Catalog} into which configured chains are
139      *        to be registered
140      * @param url {@code URL} of the XML document to be parsed
141      *
142      * @throws Exception if a parsing error occurs
143      *
144      * @deprecated Use parse(URL) on a configuration resource with "factory"
145      *  element(s) embedded
146      */
147     @Deprecated
148     public void parse(Catalog<?> catalog, URL url) throws Exception {
149         // Prepare our Digester instance
150         Digester digester = getDigester();
151         digester.clear();
152         digester.push(catalog);
153 
154         // Parse the configuration document
155         digester.parse(url);
156     }
157 
158     /**
159      * Parse the XML document at the specified URL using the configured
160      * {@code RuleSet}, registering catalogs with nested chains and
161      * commands as they are encountered. Use this method <strong>only</strong>
162      * if you have included one or more {@code factory} elements in your
163      * configuration resource.
164      *
165      * @param url {@code URL} of the XML document to be parsed
166      *
167      * @throws Exception if a parsing error occurs
168      */
169     public void parse(URL url) throws Exception {
170         // Prepare our Digester instance
171         Digester digester = getDigester();
172         digester.clear();
173 
174         // Parse the configuration document
175         digester.parse(url);
176     }
177 }