001: /*
002: * $Id: XmlParser.java 471754 2006-11-06 14:55:09Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: package org.apache.struts.tiles.xmlDefinition;
023:
024: import java.io.BufferedInputStream;
025: import java.io.FileInputStream;
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.net.URL;
029:
030: import org.apache.commons.digester.Digester;
031: import org.xml.sax.SAXException;
032:
033: /**
034: * Parse an XML definitions file.
035: */
036: public class XmlParser {
037:
038: /** Associated digester. */
039: protected Digester digester;
040: /**
041: * Should we use a validating XML parser to read the configuration file.
042: * Default is <code>false</code>.
043: */
044: protected boolean validating = false;
045: /**
046: * The set of public identifiers, and corresponding resource names for
047: * the versions of the configuration file DTDs we know about. There
048: * <strong>MUST</strong> be an even number of Strings in this list!
049: */
050: protected String registrations[] = {
051: "-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN",
052: "/org/apache/struts/resources/tiles-config_1_1.dtd",
053: "-//Apache Software Foundation//DTD Tiles Configuration 1.3//EN",
054: "/org/apache/struts/resources/tiles-config_1_3.dtd" };
055:
056: /**
057: * Constructor.
058: * Creates a digester parser and initializes syntax rules.
059: */
060: public XmlParser() {
061: digester = new Digester();
062: digester.setValidating(validating);
063: digester.setNamespaceAware(true);
064: digester.setUseContextClassLoader(true);
065: // Register our local copy of the DTDs that we can find
066: for (int i = 0; i < registrations.length; i += 2) {
067: URL url = this .getClass().getResource(registrations[i + 1]);
068: if (url != null) {
069: digester.register(registrations[i], url.toString());
070: }
071: }
072: // Init syntax rules
073: initDigester(digester);
074: }
075:
076: /**
077: * Set digester validating flag.
078: */
079: public void setValidating(boolean validating) {
080: digester.setValidating(validating);
081: }
082:
083: /**
084: * Init digester for components syntax.
085: * This is an old set of rules, left for backward compatibility.
086: * @param digester Digester instance to use.
087: */
088: private void initDigesterForComponentsDefinitionsSyntax(
089: Digester digester) {
090: // Common constants
091: String PACKAGE_NAME = "org.apache.struts.tiles.xmlDefinition";
092: String DEFINITION_TAG = "component-definitions/definition";
093: String definitionHandlerClass = PACKAGE_NAME + ".XmlDefinition";
094:
095: String PUT_TAG = DEFINITION_TAG + "/put";
096: String putAttributeHandlerClass = PACKAGE_NAME
097: + ".XmlAttribute";
098:
099: String LIST_TAG = DEFINITION_TAG + "/putList";
100: String listHandlerClass = PACKAGE_NAME + ".XmlListAttribute";
101:
102: String ADD_LIST_ELE_TAG = LIST_TAG + "/add";
103:
104: // syntax rules
105: digester
106: .addObjectCreate(DEFINITION_TAG, definitionHandlerClass);
107: digester.addSetProperties(DEFINITION_TAG);
108: digester.addSetNext(DEFINITION_TAG, "putDefinition",
109: definitionHandlerClass);
110: // put / putAttribute rules
111: digester.addObjectCreate(PUT_TAG, putAttributeHandlerClass);
112: digester.addSetNext(PUT_TAG, "addAttribute",
113: 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",
120: putAttributeHandlerClass);
121: // list elements rules
122: // We use Attribute class to avoid rewriting a new class.
123: // Name part can't be used in listElement attribute.
124: digester.addObjectCreate(ADD_LIST_ELE_TAG,
125: putAttributeHandlerClass);
126: digester.addSetNext(ADD_LIST_ELE_TAG, "add",
127: putAttributeHandlerClass);
128: digester.addSetProperties(ADD_LIST_ELE_TAG);
129: digester.addCallMethod(ADD_LIST_ELE_TAG, "setBody", 0);
130: }
131:
132: /**
133: * Init digester for Tiles syntax.
134: * Same as components, but with first element = tiles-definitions
135: * @param digester Digester instance to use.
136: */
137: private void initDigesterForTilesDefinitionsSyntax(Digester digester) {
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
145: + ".XmlAttribute";
146:
147: //String LIST_TAG = DEFINITION_TAG + "/putList";
148: // List tag value
149: String LIST_TAG = "putList";
150: String DEF_LIST_TAG = DEFINITION_TAG + "/" + LIST_TAG;
151: String listHandlerClass = PACKAGE_NAME + ".XmlListAttribute";
152: // Tag value for adding an element in a list
153: String ADD_LIST_ELE_TAG = "*/" + LIST_TAG + "/add";
154:
155: // syntax rules
156: digester
157: .addObjectCreate(DEFINITION_TAG, definitionHandlerClass);
158: digester.addSetProperties(DEFINITION_TAG);
159: digester.addSetNext(DEFINITION_TAG, "putDefinition",
160: definitionHandlerClass);
161: // put / putAttribute rules
162: // Rules for a same pattern are called in order, but rule.end() are called
163: // in reverse order.
164: // SetNext and CallMethod use rule.end() method. So, placing SetNext in
165: // first position ensure it will be called last (sic).
166: digester.addObjectCreate(PUT_TAG, putAttributeHandlerClass);
167: digester.addSetNext(PUT_TAG, "addAttribute",
168: putAttributeHandlerClass);
169: digester.addSetProperties(PUT_TAG);
170: digester.addCallMethod(PUT_TAG, "setBody", 0);
171: // Definition level list rules
172: // This is rules for lists nested in a definition
173: digester.addObjectCreate(DEF_LIST_TAG, listHandlerClass);
174: digester.addSetProperties(DEF_LIST_TAG);
175: digester.addSetNext(DEF_LIST_TAG, "addAttribute",
176: putAttributeHandlerClass);
177: // list elements rules
178: // We use Attribute class to avoid rewriting a new class.
179: // Name part can't be used in listElement attribute.
180: digester.addObjectCreate(ADD_LIST_ELE_TAG,
181: putAttributeHandlerClass);
182: digester.addSetNext(ADD_LIST_ELE_TAG, "add",
183: putAttributeHandlerClass);
184: digester.addSetProperties(ADD_LIST_ELE_TAG);
185: digester.addCallMethod(ADD_LIST_ELE_TAG, "setBody", 0);
186:
187: // nested list elements rules
188: // Create a list handler, and add it to parent list
189: String NESTED_LIST = "*/" + LIST_TAG + "/" + LIST_TAG;
190: digester.addObjectCreate(NESTED_LIST, listHandlerClass);
191: digester.addSetProperties(NESTED_LIST);
192: digester.addSetNext(NESTED_LIST, "add",
193: putAttributeHandlerClass);
194:
195: // item elements rules
196: // We use Attribute class to avoid rewriting a new class.
197: // Name part can't be used in listElement attribute.
198: //String ADD_WILDCARD = LIST_TAG + "/addItem";
199: // non String ADD_WILDCARD = LIST_TAG + "/addx*";
200: String ADD_WILDCARD = "*/item";
201: String menuItemDefaultClass = "org.apache.struts.tiles.beans.SimpleMenuItem";
202: digester.addObjectCreate(ADD_WILDCARD, menuItemDefaultClass,
203: "classtype");
204: digester.addSetNext(ADD_WILDCARD, "add", "java.lang.Object");
205: digester.addSetProperties(ADD_WILDCARD);
206:
207: // bean elements rules
208: String BEAN_TAG = "*/bean";
209: String beanDefaultClass = "org.apache.struts.tiles.beans.SimpleMenuItem";
210: digester.addObjectCreate(BEAN_TAG, beanDefaultClass,
211: "classtype");
212: digester.addSetNext(BEAN_TAG, "add", "java.lang.Object");
213: digester.addSetProperties(BEAN_TAG);
214:
215: // Set properties to surrounding element
216: digester.addSetProperty(BEAN_TAG + "/set-property", "property",
217: "value");
218: }
219:
220: /**
221: * Init digester in order to parse instances definition file syntax.
222: * Instances is an old name for "definition". This method is left for
223: * backwards compatibility.
224: * @param digester Digester instance to use.
225: */
226: private void initDigesterForInstancesSyntax(Digester digester) {
227: // Build a digester to process our configuration resource
228: String PACKAGE_NAME = "org.apache.struts.tiles.xmlDefinition";
229: String INSTANCE_TAG = "component-instances/instance";
230: String instanceHandlerClass = PACKAGE_NAME + ".XmlDefinition";
231:
232: String PUT_TAG = INSTANCE_TAG + "/put";
233: String PUTATTRIBUTE_TAG = INSTANCE_TAG + "/putAttribute";
234: String putAttributeHandlerClass = PACKAGE_NAME
235: + ".XmlAttribute";
236:
237: String LIST_TAG = INSTANCE_TAG + "/putList";
238: String listHandlerClass = PACKAGE_NAME + ".XmlListAttribute";
239:
240: String ADD_LIST_ELE_TAG = LIST_TAG + "/add";
241:
242: // component instance rules
243: digester.addObjectCreate(INSTANCE_TAG, instanceHandlerClass);
244: digester.addSetProperties(INSTANCE_TAG);
245: digester.addSetNext(INSTANCE_TAG, "putDefinition",
246: instanceHandlerClass);
247: // put / putAttribute rules
248: digester.addObjectCreate(PUTATTRIBUTE_TAG,
249: putAttributeHandlerClass);
250: digester.addSetProperties(PUTATTRIBUTE_TAG);
251: digester.addSetNext(PUTATTRIBUTE_TAG, "addAttribute",
252: putAttributeHandlerClass);
253: // put / putAttribute rules
254: digester.addObjectCreate(PUT_TAG, putAttributeHandlerClass);
255: digester.addSetProperties(PUT_TAG);
256: digester.addSetNext(PUT_TAG, "addAttribute",
257: putAttributeHandlerClass);
258: // list rules
259: digester.addObjectCreate(LIST_TAG, listHandlerClass);
260: digester.addSetProperties(LIST_TAG);
261: digester.addSetNext(LIST_TAG, "addAttribute",
262: putAttributeHandlerClass);
263: // list elements rules
264: // We use Attribute class to avoid rewriting a new class.
265: // Name part can't be used in listElement attribute.
266: digester.addObjectCreate(ADD_LIST_ELE_TAG,
267: putAttributeHandlerClass);
268: digester.addSetProperties(ADD_LIST_ELE_TAG);
269: digester.addSetNext(ADD_LIST_ELE_TAG, "add",
270: putAttributeHandlerClass);
271: }
272:
273: /**
274: * Init digester.
275: * @param digester Digester instance to use.
276: */
277: protected void initDigester(Digester digester) {
278: initDigesterForTilesDefinitionsSyntax(digester);
279: initDigesterForComponentsDefinitionsSyntax(digester);
280: initDigesterForInstancesSyntax(digester);
281: }
282:
283: /**
284: * Parse input reader and add encountered definitions to definitions set.
285: * @param in Input stream.
286: * @param definitions Xml Definitions set to which encountered definition are added.
287: * @throws IOException On errors during file parsing.
288: * @throws SAXException On errors parsing XML.
289: */
290: public void parse(InputStream in, XmlDefinitionsSet definitions)
291: throws IOException, SAXException {
292: try {
293: // set first object in stack
294: //digester.clear();
295: digester.push(definitions);
296: // parse
297: digester.parse(in);
298: in.close();
299: } catch (SAXException e) {
300: //throw new ServletException( "Error while parsing " + mappingConfig, e);
301: throw e;
302: }
303:
304: }
305:
306: /**
307: * Main method to check file syntax.
308: */
309: public static void main(String[] args) {
310: //String filename = "E:/programs/jakarta-tomcat/webapps/wtiles-struts/WEB-INF/tiles-examples-defs.xml";
311: String filename = "E:/programs/jakarta-tomcat-4.0.3/webapps/wtiles-struts/WEB-INF/tiles-examples-defs.xml";
312: //String filename = "E:/programs/jakarta-tomcat/webapps/wtiles-struts/WEB-INF/tilesDefinitions.xml";
313: //String filename = "E:/programs/jakarta-tomcat/webapps/wtiles-channel/WEB-INF/componentDefinitions.xml";
314: //String filename2 = "E:/programs/jakarta-tomcat/webapps/wtiles-tutorial/WEB-INF/componentDefinitions.xml";
315:
316: if (args.length > 1) {
317: filename = args[1];
318: } // end if
319:
320: System.out.println("Read file '" + filename + "'");
321:
322: InputStream input = null;
323: // InputStream input2 = null;
324: // Open file
325: try {
326: input = new BufferedInputStream(new FileInputStream(
327: filename));
328: // input2 = new BufferedInputStream(
329: // new FileInputStream( filename2) );
330: } catch (IOException ex) {
331: System.out.println("can't open file '" + filename + "' : "
332: + ex.getMessage());
333: }
334: // Check file syntax
335: try {
336: XmlParser parser = new XmlParser();
337: parser.setValidating(true);
338: XmlDefinitionsSet definitions = new XmlDefinitionsSet();
339: System.out.println(" Parse file");
340: parser.parse(input, definitions);
341: // System.out.println( " Check file 2" );
342: //parser.parse( input2, definitions);
343: System.out.println(" done.");
344: System.out.println(" Result : " + definitions.toString());
345: } catch (Exception ex) {
346: System.out.println("Error during parsing '" + filename
347: + "' : " + ex.getMessage());
348: ex.printStackTrace();
349: }
350: }
351:
352: }
|