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    
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        @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