View Javadoc

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