View Javadoc

1   package org.apache.commons.digester3.xmlrules;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import static java.util.Collections.unmodifiableSet;
23  import static org.apache.commons.digester3.binder.DigesterLoader.newLoader;
24  
25  import java.io.File;
26  import java.io.InputStream;
27  import java.io.Reader;
28  import java.io.StringReader;
29  import java.net.MalformedURLException;
30  import java.net.URL;
31  import java.net.URLConnection;
32  import java.util.HashSet;
33  import java.util.Set;
34  
35  import org.apache.commons.digester3.Digester;
36  import org.apache.commons.digester3.binder.AbstractRulesModule;
37  import org.xml.sax.InputSource;
38  
39  /**
40   * {@link org.apache.commons.digester3.binder.RulesModule} implementation that allows loading rules from
41   * XML files.
42   *
43   * @since 3.0
44   */
45  public abstract class FromXmlRulesModule
46      extends AbstractRulesModule
47  {
48  
49      private static final String DIGESTER_PUBLIC_ID = "-//Apache Commons //DTD digester-rules XML V1.0//EN";
50  
51      private static final String DIGESTER_DTD_PATH = "digester-rules.dtd";
52  
53      private final URL xmlRulesDtdUrl = FromXmlRulesModule.class.getResource( DIGESTER_DTD_PATH );
54  
55      private final Set<String> systemIds = new HashSet<String>();
56  
57      private String rootPath;
58  
59      /**
60       * {@inheritDoc}
61       */
62      @Override
63      protected void configure()
64      {
65          if ( !systemIds.isEmpty() )
66          {
67              throw new IllegalStateException( "Re-entry is not allowed." );
68          }
69  
70          try
71          {
72              loadRules();
73          }
74          finally
75          {
76              systemIds.clear();
77          }
78      }
79  
80      /**
81       *
82       */
83      protected abstract void loadRules();
84  
85      /**
86       * Reads the XML rules from the given {@code org.xml.sax.InputSource}.
87       *
88       * @param inputSource The {@code org.xml.sax.InputSource} where reading the XML rules from.
89       */
90      protected final void loadXMLRules( InputSource inputSource )
91      {
92          if ( inputSource == null )
93          {
94              throw new IllegalArgumentException( "Argument 'inputSource' must be not null" );
95          }
96  
97          String systemId = inputSource.getSystemId();
98          if ( systemId != null && !systemIds.add( systemId ) )
99          {
100             addError( "XML rules file '%s' already bound", systemId );
101         }
102 
103         XmlRulesModule xmlRulesModule = new XmlRulesModule( new NameSpaceURIRulesBinder( rulesBinder() ),
104                                                             getSystemIds(), rootPath );
105         Digester digester = newLoader( xmlRulesModule )
106                 .register( DIGESTER_PUBLIC_ID, xmlRulesDtdUrl.toString() )
107                 .setXIncludeAware( true )
108                 .setValidating( true )
109                 .newDigester();
110 
111         try
112         {
113             digester.parse( inputSource );
114         }
115         catch ( Exception e )
116         {
117             addError( "Impossible to load XML defined in the InputSource '%s': %s", inputSource.getSystemId(),
118                       e.getMessage() );
119         }
120     }
121 
122     /**
123      * Opens a new {@code org.xml.sax.InputSource} given a {@code java.io.InputStream}.
124      *
125      * @param input The {@code java.io.InputStream} where reading the XML rules from.
126      */
127     protected final void loadXMLRules( InputStream input )
128     {
129         if ( input == null )
130         {
131             throw new IllegalArgumentException( "Argument 'input' must be not null" );
132         }
133 
134         loadXMLRules( new InputSource( input ) );
135     }
136 
137     /**
138      * Opens a new {@code org.xml.sax.InputSource} given a {@code java.io.Reader}.
139      *
140      * @param reader The {@code java.io.Reader} where reading the XML rules from.
141      */
142     protected final void loadXMLRules( Reader reader )
143     {
144         if ( reader == null )
145         {
146             throw new IllegalArgumentException( "Argument 'input' must be not null" );
147         }
148 
149         loadXMLRules( new InputSource( reader ) );
150     }
151 
152     /**
153      * Opens a new {@code org.xml.sax.InputSource} given a {@code java.io.File}.
154      *
155      * @param file The {@code java.io.File} where reading the XML rules from.
156      */
157     protected final void loadXMLRules( File file )
158     {
159         if ( file == null )
160         {
161             throw new IllegalArgumentException( "Argument 'input' must be not null" );
162         }
163 
164         try
165         {
166             loadXMLRules( file.toURI().toURL() );
167         }
168         catch ( MalformedURLException e )
169         {
170             rulesBinder().addError( e );
171         }
172     }
173 
174     /**
175      * Opens a new {@code org.xml.sax.InputSource} given a URI in String representation.
176      *
177      * @param uri The URI in String representation where reading the XML rules from.
178      */
179     protected final void loadXMLRules( String uri )
180     {
181         if ( uri == null )
182         {
183             throw new IllegalArgumentException( "Argument 'uri' must be not null" );
184         }
185 
186         try
187         {
188             loadXMLRules( new URL( uri ) );
189         }
190         catch ( MalformedURLException e )
191         {
192             rulesBinder().addError( e );
193         }
194     }
195 
196     /**
197      * Opens a new {@code org.xml.sax.InputSource} given a {@code java.net.URL}.
198      *
199      * @param url The {@code java.net.URL} where reading the XML rules from.
200      */
201     protected final void loadXMLRules( URL url )
202     {
203         if ( url == null )
204         {
205             throw new IllegalArgumentException( "Argument 'url' must be not null" );
206         }
207 
208         try
209         {
210             URLConnection connection = url.openConnection();
211             connection.setUseCaches( false );
212             InputStream stream = connection.getInputStream();
213             InputSource source = new InputSource( stream );
214             source.setSystemId( url.toExternalForm() );
215 
216             loadXMLRules( source );
217         }
218         catch ( Exception e )
219         {
220             rulesBinder().addError( e );
221         }
222     }
223 
224     /**
225      * Opens a new {@code org.xml.sax.InputSource} given an XML document in textual form.
226      *
227      * @param xmlText The XML document in textual form where reading the XML rules from.
228      */
229     protected final void loadXMLRulesFromText( String xmlText )
230     {
231         if ( xmlText == null )
232         {
233             throw new IllegalArgumentException( "Argument 'xmlText' must be not null" );
234         }
235 
236         loadXMLRules( new StringReader( xmlText ) );
237     }
238 
239     /**
240      * Set the root path (will be used when composing modules).
241      *
242      * @param rootPath The root path
243      */
244     protected final void useRootPath( String rootPath )
245     {
246         this.rootPath = rootPath;
247     }
248 
249     /**
250      * Returns the XML source SystemIds load by this module.
251      *
252      * @return The XML source SystemIds load by this module
253      */
254     public final Set<String> getSystemIds()
255     {
256         return unmodifiableSet( systemIds );
257     }
258 
259 }