001    /* $Id: FromXmlRuleSet.java 471661 2006-11-06 08:09:25Z skitching $
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    
020    package org.apache.commons.digester.xmlrules;
021    
022    
023    import java.net.URL;
024    
025    import org.apache.commons.digester.Digester;
026    import org.apache.commons.digester.RuleSetBase;
027    
028    import 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     */
035    public 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        public void addRuleInstances(org.apache.commons.digester.Digester digester) throws XmlLoadException {
141            addRuleInstances(digester, null);
142        }
143        
144        /**
145         * Adds to the digester the set of Rule instances defined in the
146         * XML file for this rule set.
147         * <p>
148         * Note that this method doesn't have a matching one on the DigesterLoader
149         * class, because it is not expected to be widely used, and DigesterLoader's
150         * load method is already heavily overloaded.
151         *
152         * @param digester is the digester that rules will be added to.
153         * @param basePath is a path that will be prefixed to every
154         * pattern string defined in the xmlrules input file.
155         *
156         * @see org.apache.commons.digester.RuleSetBase
157         * @since 1.6
158         */
159        public void addRuleInstances(
160        org.apache.commons.digester.Digester digester,
161        String basePath) 
162        throws XmlLoadException {
163            
164            URL dtdURL = getClass().getClassLoader().getResource(DIGESTER_DTD_PATH);
165            if (dtdURL == null) {
166                throw new XmlLoadException("Cannot find resource \"" +
167                        DIGESTER_DTD_PATH + "\"");
168            }
169            parser.setDigesterRulesDTD(dtdURL.toString());
170            parser.setTarget(digester);
171            parser.setBasePath(basePath);
172    
173            rulesDigester.addRuleSet(parser);
174            rulesDigester.push(parser);
175    
176            rulesLoader.loadRules();
177        }
178        
179        /** 
180         * Worker class encapsulates loading mechanisms.
181         * Private until some reason is found to make it public.
182         */
183        private abstract static class XMLRulesLoader {
184            /** Load rules now */
185            public abstract void loadRules()  throws XmlLoadException;
186        }
187        
188        /** Loads XMLRules from an URL */
189        private class URLXMLRulesLoader extends XMLRulesLoader {
190            private URL url;
191            public URLXMLRulesLoader(URL url) {
192                this.url = url;
193            }
194            
195            public void loadRules() throws XmlLoadException {
196                try {
197                    rulesDigester.parse(url.openStream());
198                } catch (Exception ex) {
199                    throw new XmlLoadException(ex);
200                }
201            }
202        }
203    
204        /** Loads XMLRules from an InputSource */
205        private class InputSourceXMLRulesLoader extends XMLRulesLoader {
206            private InputSource inputSource;
207            public InputSourceXMLRulesLoader(InputSource inputSource) {
208                this.inputSource = inputSource;
209            }
210            
211            public void loadRules() throws XmlLoadException {
212                try {
213                    rulesDigester.parse(inputSource);
214                } catch (Exception ex) {
215                    throw new XmlLoadException(ex);
216                }
217            }
218        }
219    }
220