View Javadoc

1   /*
2    * $Id: XmlParser.java 471754 2006-11-06 14:55:09Z husted $
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  package org.apache.struts.tiles.xmlDefinition;
23  
24  import java.io.BufferedInputStream;
25  import java.io.FileInputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.net.URL;
29  
30  import org.apache.commons.digester.Digester;
31  import org.xml.sax.SAXException;
32  
33  /**
34   * Parse an XML definitions file.
35   */
36  public class XmlParser
37  {
38  
39      /** Associated digester. */
40    protected Digester digester;
41      /**
42       * Should we use a validating XML parser to read the configuration file.
43       * Default is <code>false</code>.
44       */
45      protected boolean validating = false;
46      /**
47       * The set of public identifiers, and corresponding resource names for
48       * the versions of the configuration file DTDs we know about.  There
49       * <strong>MUST</strong> be an even number of Strings in this list!
50       */
51      protected String registrations[] = {
52          "-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN",
53          "/org/apache/struts/resources/tiles-config_1_1.dtd",
54          "-//Apache Software Foundation//DTD Tiles Configuration 1.3//EN",
55          "/org/apache/struts/resources/tiles-config_1_3.dtd"
56      };
57  
58       /**
59        * Constructor.
60        * Creates a digester parser and initializes syntax rules.
61        */
62    public XmlParser()
63    {
64      digester = new Digester();
65      digester.setValidating(validating);
66      digester.setNamespaceAware(true);
67      digester.setUseContextClassLoader(true);
68      // Register our local copy of the DTDs that we can find
69    for (int i = 0; i < registrations.length; i += 2) {
70        URL url = this.getClass().getResource(registrations[i+1]);
71        if (url != null)
72            {
73            digester.register(registrations[i], url.toString());
74            }
75    }
76      // Init syntax rules
77    initDigester( digester );
78    }
79  
80      /**
81       * Set digester validating flag.
82       */
83    public void setValidating( boolean validating )
84      {
85      digester.setValidating( validating);
86      }
87  
88  
89     /**
90      * Init digester for components syntax.
91      * This is an old set of rules, left for backward compatibility.
92      * @param digester Digester instance to use.
93      */
94    private void initDigesterForComponentsDefinitionsSyntax( Digester digester )
95    {
96       // Common constants
97    String PACKAGE_NAME = "org.apache.struts.tiles.xmlDefinition";
98    String DEFINITION_TAG = "component-definitions/definition";
99    String definitionHandlerClass = PACKAGE_NAME + ".XmlDefinition";
100 
101   String PUT_TAG  = DEFINITION_TAG + "/put";
102   String putAttributeHandlerClass = PACKAGE_NAME + ".XmlAttribute";
103 
104   String LIST_TAG = DEFINITION_TAG + "/putList";
105   String listHandlerClass     = PACKAGE_NAME + ".XmlListAttribute";
106 
107   String ADD_LIST_ELE_TAG = LIST_TAG + "/add";
108 
109     // syntax rules
110     digester.addObjectCreate(  DEFINITION_TAG, definitionHandlerClass );
111     digester.addSetProperties( DEFINITION_TAG);
112     digester.addSetNext(       DEFINITION_TAG, "putDefinition", definitionHandlerClass);
113     // put / putAttribute rules
114     digester.addObjectCreate(  PUT_TAG, putAttributeHandlerClass);
115     digester.addSetNext(       PUT_TAG, "addAttribute", putAttributeHandlerClass);
116     digester.addSetProperties( PUT_TAG);
117     digester.addCallMethod(    PUT_TAG, "setBody", 0);
118     // list rules
119     digester.addObjectCreate(  LIST_TAG, listHandlerClass);
120     digester.addSetProperties( LIST_TAG);
121     digester.addSetNext(       LIST_TAG, "addAttribute", putAttributeHandlerClass);
122     // list elements rules
123     // We use Attribute class to avoid rewriting a new class.
124     // Name part can't be used in listElement attribute.
125     digester.addObjectCreate(  ADD_LIST_ELE_TAG, putAttributeHandlerClass);
126     digester.addSetNext(       ADD_LIST_ELE_TAG, "add", putAttributeHandlerClass);
127     digester.addSetProperties( ADD_LIST_ELE_TAG);
128     digester.addCallMethod(    ADD_LIST_ELE_TAG, "setBody", 0);
129   }
130 
131    /**
132     * Init digester for Tiles syntax.
133     * Same as components, but with first element = tiles-definitions
134     * @param digester Digester instance to use.
135     */
136   private void initDigesterForTilesDefinitionsSyntax( Digester digester )
137   {
138      // Common constants
139   String PACKAGE_NAME = "org.apache.struts.tiles.xmlDefinition";
140   String DEFINITION_TAG = "tiles-definitions/definition";
141   String definitionHandlerClass = PACKAGE_NAME + ".XmlDefinition";
142 
143   String PUT_TAG  = DEFINITION_TAG + "/put";
144   String putAttributeHandlerClass = PACKAGE_NAME + ".XmlAttribute";
145 
146   //String LIST_TAG = DEFINITION_TAG + "/putList";
147     // List tag value
148   String LIST_TAG = "putList";
149   String DEF_LIST_TAG = DEFINITION_TAG + "/" + LIST_TAG;
150   String listHandlerClass     = PACKAGE_NAME + ".XmlListAttribute";
151     // Tag value for adding an element in a list
152   String ADD_LIST_ELE_TAG = "*/" + LIST_TAG + "/add";
153 
154     // syntax rules
155     digester.addObjectCreate(  DEFINITION_TAG, definitionHandlerClass );
156     digester.addSetProperties( DEFINITION_TAG);
157     digester.addSetNext(       DEFINITION_TAG, "putDefinition", definitionHandlerClass);
158     // put / putAttribute rules
159     // Rules for a same pattern are called in order, but rule.end() are called
160     // in reverse order.
161     // SetNext and CallMethod use rule.end() method. So, placing SetNext in
162     // first position ensure it will be called last (sic).
163     digester.addObjectCreate(  PUT_TAG, putAttributeHandlerClass);
164     digester.addSetNext(       PUT_TAG, "addAttribute", putAttributeHandlerClass);
165     digester.addSetProperties( PUT_TAG);
166     digester.addCallMethod(    PUT_TAG, "setBody", 0);
167     // Definition level list rules
168     // This is rules for lists nested in a definition
169     digester.addObjectCreate(  DEF_LIST_TAG, listHandlerClass);
170     digester.addSetProperties( DEF_LIST_TAG);
171     digester.addSetNext(       DEF_LIST_TAG, "addAttribute", putAttributeHandlerClass);
172     // list elements rules
173     // We use Attribute class to avoid rewriting a new class.
174     // Name part can't be used in listElement attribute.
175     digester.addObjectCreate(  ADD_LIST_ELE_TAG, putAttributeHandlerClass);
176     digester.addSetNext(       ADD_LIST_ELE_TAG, "add", putAttributeHandlerClass);
177     digester.addSetProperties( ADD_LIST_ELE_TAG);
178     digester.addCallMethod(    ADD_LIST_ELE_TAG, "setBody", 0);
179 
180     // nested list elements rules
181     // Create a list handler, and add it to parent list
182   String NESTED_LIST = "*/" + LIST_TAG + "/" + LIST_TAG;
183     digester.addObjectCreate(  NESTED_LIST, listHandlerClass);
184     digester.addSetProperties( NESTED_LIST);
185     digester.addSetNext(       NESTED_LIST, "add", putAttributeHandlerClass);
186 
187     // item elements rules
188     // We use Attribute class to avoid rewriting a new class.
189     // Name part can't be used in listElement attribute.
190   //String ADD_WILDCARD = LIST_TAG + "/addItem";
191   // non String ADD_WILDCARD = LIST_TAG + "/addx*";
192   String ADD_WILDCARD = "*/item";
193   String menuItemDefaultClass = "org.apache.struts.tiles.beans.SimpleMenuItem";
194     digester.addObjectCreate(  ADD_WILDCARD, menuItemDefaultClass, "classtype");
195     digester.addSetNext(       ADD_WILDCARD, "add", "java.lang.Object");
196     digester.addSetProperties( ADD_WILDCARD);
197 
198     // bean elements rules
199   String BEAN_TAG = "*/bean";
200   String beanDefaultClass = "org.apache.struts.tiles.beans.SimpleMenuItem";
201     digester.addObjectCreate(  BEAN_TAG, beanDefaultClass, "classtype");
202     digester.addSetNext(       BEAN_TAG, "add", "java.lang.Object");
203     digester.addSetProperties( BEAN_TAG);
204 
205     // Set properties to surrounding element
206   digester.addSetProperty(BEAN_TAG+ "/set-property", "property", "value");
207   }
208 
209    /**
210     * Init digester in order to parse instances definition file syntax.
211     * Instances is an old name for "definition". This method is left for
212     * backwards compatibility.
213     * @param digester Digester instance to use.
214     */
215   private void initDigesterForInstancesSyntax( Digester digester )
216   {
217         // Build a digester to process our configuration resource
218   String PACKAGE_NAME = "org.apache.struts.tiles.xmlDefinition";
219   String INSTANCE_TAG = "component-instances/instance";
220   String instanceHandlerClass = PACKAGE_NAME + ".XmlDefinition";
221 
222   String PUT_TAG = INSTANCE_TAG + "/put";
223   String PUTATTRIBUTE_TAG = INSTANCE_TAG + "/putAttribute";
224   String putAttributeHandlerClass = PACKAGE_NAME + ".XmlAttribute";
225 
226   String LIST_TAG     = INSTANCE_TAG + "/putList";
227   String listHandlerClass     = PACKAGE_NAME + ".XmlListAttribute";
228 
229   String ADD_LIST_ELE_TAG = LIST_TAG + "/add";
230 
231     // component instance rules
232     digester.addObjectCreate(  INSTANCE_TAG, instanceHandlerClass );
233     digester.addSetProperties( INSTANCE_TAG);
234     digester.addSetNext(       INSTANCE_TAG, "putDefinition", instanceHandlerClass);
235     // put / putAttribute rules
236     digester.addObjectCreate(  PUTATTRIBUTE_TAG, putAttributeHandlerClass);
237     digester.addSetProperties( PUTATTRIBUTE_TAG);
238     digester.addSetNext(       PUTATTRIBUTE_TAG, "addAttribute", putAttributeHandlerClass);
239     // put / putAttribute rules
240     digester.addObjectCreate(  PUT_TAG, putAttributeHandlerClass);
241     digester.addSetProperties( PUT_TAG);
242     digester.addSetNext(       PUT_TAG, "addAttribute", putAttributeHandlerClass);
243     // list rules
244     digester.addObjectCreate(  LIST_TAG, listHandlerClass);
245     digester.addSetProperties( LIST_TAG);
246     digester.addSetNext(       LIST_TAG, "addAttribute", putAttributeHandlerClass);
247     // list elements rules
248     // We use Attribute class to avoid rewriting a new class.
249     // Name part can't be used in listElement attribute.
250     digester.addObjectCreate(  ADD_LIST_ELE_TAG, putAttributeHandlerClass);
251     digester.addSetProperties( ADD_LIST_ELE_TAG);
252     digester.addSetNext(       ADD_LIST_ELE_TAG, "add", putAttributeHandlerClass);
253   }
254 
255    /**
256     * Init digester.
257     * @param digester Digester instance to use.
258     */
259   protected void initDigester( Digester digester )
260   {
261   initDigesterForTilesDefinitionsSyntax( digester );
262   initDigesterForComponentsDefinitionsSyntax( digester );
263   initDigesterForInstancesSyntax( digester );
264   }
265 
266   /**
267    * Parse input reader and add encountered definitions to definitions set.
268    * @param in Input stream.
269    * @param definitions Xml Definitions set to which encountered definition are added.
270    * @throws IOException On errors during file parsing.
271    * @throws SAXException On errors parsing XML.
272    */
273   public void parse( InputStream in, XmlDefinitionsSet definitions ) throws IOException, SAXException
274   {
275     try
276     {
277       // set first object in stack
278     //digester.clear();
279     digester.push(definitions);
280       // parse
281       digester.parse(in);
282       in.close();
283       }
284   catch (SAXException e)
285     {
286       //throw new ServletException( "Error while parsing " + mappingConfig, e);
287     throw e;
288       }
289 
290   }
291 
292     /**
293      * Main method to check file syntax.
294      */
295   public static void main(String[] args)
296   {
297   //String filename = "E:/programs/jakarta-tomcat/webapps/wtiles-struts/WEB-INF/tiles-examples-defs.xml";
298   String filename = "E:/programs/jakarta-tomcat-4.0.3/webapps/wtiles-struts/WEB-INF/tiles-examples-defs.xml";
299   //String filename = "E:/programs/jakarta-tomcat/webapps/wtiles-struts/WEB-INF/tilesDefinitions.xml";
300   //String filename = "E:/programs/jakarta-tomcat/webapps/wtiles-channel/WEB-INF/componentDefinitions.xml";
301   //String filename2 = "E:/programs/jakarta-tomcat/webapps/wtiles-tutorial/WEB-INF/componentDefinitions.xml";
302 
303 
304     if( args.length > 1 )
305       {
306       filename = args[1];
307       } // end if
308 
309   System.out.println( "Read file '" + filename  +"'" );
310 
311   InputStream input = null;
312   // InputStream input2 = null;
313     // Open file
314     try
315       {
316         input = new BufferedInputStream(
317                              new FileInputStream( filename) );
318     //    input2 = new BufferedInputStream(
319           //                   new FileInputStream( filename2) );
320       }
321      catch( IOException ex )
322       {
323       System.out.println( "can't open file '" + filename + "' : " + ex.getMessage() );
324       }
325     // Check file syntax
326     try
327       {
328         XmlParser parser = new XmlParser();
329       parser.setValidating(true);
330       XmlDefinitionsSet definitions = new XmlDefinitionsSet();
331         System.out.println( "  Parse file" );
332       parser.parse( input, definitions);
333       //  System.out.println( "  Check file 2" );
334       //parser.parse( input2, definitions);
335         System.out.println( "  done." );
336       System.out.println( "  Result : " + definitions.toString() );
337       }
338      catch( Exception ex )
339       {
340       System.out.println( "Error during parsing '" + filename + "' : " + ex.getMessage() );
341       ex.printStackTrace();
342       }
343   }
344 
345 }