001/* $Id: FromXmlRuleSet.java 992060 2010-09-02 19:09:47Z simonetripodi $
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements.  See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019
020package org.apache.commons.digester.xmlrules;
021
022
023import java.net.URL;
024
025import org.apache.commons.digester.Digester;
026import org.apache.commons.digester.RuleSetBase;
027
028import org.xml.sax.InputSource;
029
030/**
031 * A Digester rule set where the rules come from an XML file.
032 *
033 * @since 1.2
034 */
035public class FromXmlRuleSet extends RuleSetBase {
036
037    public static final String DIGESTER_DTD_PATH = "org/apache/commons/digester/xmlrules/digester-rules.dtd";
038
039    /**
040     * The file containing the Digester rules, in XML.
041     */
042    private XMLRulesLoader rulesLoader;
043
044    /**
045     * The rule set for parsing the Digester rules
046     */
047    private DigesterRuleParser parser;
048
049    /**
050        * The digester for loading the rules xml.
051        */
052    private Digester rulesDigester;
053
054    /**
055     * Constructs a FromXmlRuleSet using the default DigesterRuleParser and
056     * rulesDigester.
057     * @param rulesXml the path to the XML document defining the Digester rules
058     */
059    public FromXmlRuleSet(URL rulesXml) {
060        this(rulesXml, new DigesterRuleParser(), new Digester());
061    }
062
063    /**
064     * Constructs a FromXmlRuleSet using the default DigesterRuleParser and
065     * a ruleDigester for loading the rules xml.
066     * @param rulesXml the path to the XML document defining the Digester rules
067     * @param rulesDigester the digester to read the rules xml.
068     */
069    public FromXmlRuleSet(URL rulesXml, Digester rulesDigester) {
070        this(rulesXml, new DigesterRuleParser(), rulesDigester);
071    }
072
073    /**
074     * @param rulesXml the path to the XML document defining the Digester rules
075     * @param parser an instance of DigesterRuleParser, for parsing the rules from XML
076     */
077    public FromXmlRuleSet(URL rulesXml, DigesterRuleParser parser) {
078        this(rulesXml, parser, new Digester());
079    }
080
081    /**
082     * @param rulesXml the path to the XML document defining the Digester rules
083     * @param parser an instance of DigesterRuleParser, for parsing the rules from XML
084     * @param rulesDigester the digester used to load the Xml rules.
085     */
086    public FromXmlRuleSet(URL rulesXml, DigesterRuleParser parser, Digester rulesDigester) {
087        init(new URLXMLRulesLoader(rulesXml), parser, rulesDigester);
088    }
089
090    /**
091     * Constructs a FromXmlRuleSet using the default DigesterRuleParser and
092     * rulesDigester.
093     * @param inputSource load the xml rules from this InputSource
094     */
095    public FromXmlRuleSet(InputSource inputSource) {
096        this(inputSource, new DigesterRuleParser(), new Digester());
097    }
098    
099    /**
100     * Constructs a FromXmlRuleSet using the default DigesterRuleParser and
101     * a ruleDigester for loading the rules xml.
102     * @param inputSource load the xml rules from this InputSource
103     * @param rulesDigester the digester to read the rules xml.
104     */
105    public FromXmlRuleSet(InputSource inputSource, Digester rulesDigester) {
106        this(inputSource, new DigesterRuleParser(), rulesDigester);
107    }
108
109    /**
110     * @param inputSource load the xml rules from this InputSource
111     * @param parser an instance of DigesterRuleParser, for parsing the rules from XML
112     */
113    public FromXmlRuleSet(InputSource inputSource, DigesterRuleParser parser) {
114        this(inputSource, parser, new Digester());
115    }
116
117    /**
118     * @param inputSource load the xml rules from this InputSource
119     * @param parser an instance of DigesterRuleParser, for parsing the rules from XML
120     * @param rulesDigester the digester used to load the Xml rules.
121     */
122    public FromXmlRuleSet(InputSource inputSource, DigesterRuleParser parser, Digester rulesDigester) {
123        init(new InputSourceXMLRulesLoader(inputSource), parser, rulesDigester);
124    }
125    
126    /**
127     * Base constructor
128     */
129    private void init(XMLRulesLoader rulesLoader, DigesterRuleParser parser, Digester rulesDigester) {
130        this.rulesLoader = rulesLoader;
131        this.parser = parser;
132        this.rulesDigester = rulesDigester;
133    }
134    
135    /**
136     * Adds to the digester the set of Rule instances defined in the
137     * XML file for this rule set.
138     * @see org.apache.commons.digester.RuleSetBase
139     */
140    @Override
141    public void addRuleInstances(org.apache.commons.digester.Digester digester) throws XmlLoadException {
142        addRuleInstances(digester, null);
143    }
144    
145    /**
146     * Adds to the digester the set of Rule instances defined in the
147     * XML file for this rule set.
148     * <p>
149     * Note that this method doesn't have a matching one on the DigesterLoader
150     * class, because it is not expected to be widely used, and DigesterLoader's
151     * load method is already heavily overloaded.
152     *
153     * @param digester is the digester that rules will be added to.
154     * @param basePath is a path that will be prefixed to every
155     * pattern string defined in the xmlrules input file.
156     *
157     * @see org.apache.commons.digester.RuleSetBase
158     * @since 1.6
159     */
160    public void addRuleInstances(
161    org.apache.commons.digester.Digester digester,
162    String basePath) 
163    throws XmlLoadException {
164        
165        URL dtdURL = getClass().getClassLoader().getResource(DIGESTER_DTD_PATH);
166        if (dtdURL == null) {
167            throw new XmlLoadException("Cannot find resource \"" +
168                    DIGESTER_DTD_PATH + "\"");
169        }
170        parser.setDigesterRulesDTD(dtdURL.toString());
171        parser.setTarget(digester);
172        parser.setBasePath(basePath);
173
174        rulesDigester.addRuleSet(parser);
175        rulesDigester.push(parser);
176
177        rulesLoader.loadRules();
178    }
179    
180    /** 
181     * Worker class encapsulates loading mechanisms.
182     * Private until some reason is found to make it public.
183     */
184    private abstract static class XMLRulesLoader {
185        /** Load rules now */
186        public abstract void loadRules()  throws XmlLoadException;
187    }
188    
189    /** Loads XMLRules from an URL */
190    private class URLXMLRulesLoader extends XMLRulesLoader {
191        private URL url;
192        public URLXMLRulesLoader(URL url) {
193            this.url = url;
194        }
195        
196        @Override
197        public void loadRules() throws XmlLoadException {
198            try {
199                rulesDigester.parse(url.openStream());
200            } catch (Exception ex) {
201                throw new XmlLoadException(ex);
202            }
203        }
204    }
205
206    /** Loads XMLRules from an InputSource */
207    private class InputSourceXMLRulesLoader extends XMLRulesLoader {
208        private InputSource inputSource;
209        public InputSourceXMLRulesLoader(InputSource inputSource) {
210            this.inputSource = inputSource;
211        }
212        
213        @Override
214        public void loadRules() throws XmlLoadException {
215            try {
216                rulesDigester.parse(inputSource);
217            } catch (Exception ex) {
218                throw new XmlLoadException(ex);
219            }
220        }
221    }
222}
223