001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.jasper.xmlparser;
019:
020: import java.io.IOException;
021: import java.io.InputStream;
022:
023: import javax.xml.parsers.DocumentBuilder;
024: import javax.xml.parsers.DocumentBuilderFactory;
025: import javax.xml.parsers.ParserConfigurationException;
026:
027: import org.apache.jasper.Constants;
028: import org.apache.jasper.JasperException;
029: import org.apache.jasper.compiler.Localizer;
030: import org.apache.juli.logging.Log;
031: import org.apache.juli.logging.LogFactory;
032: import org.w3c.dom.Comment;
033: import org.w3c.dom.Document;
034: import org.w3c.dom.NamedNodeMap;
035: import org.w3c.dom.Node;
036: import org.w3c.dom.NodeList;
037: import org.w3c.dom.Text;
038: import org.xml.sax.EntityResolver;
039: import org.xml.sax.ErrorHandler;
040: import org.xml.sax.InputSource;
041: import org.xml.sax.SAXException;
042: import org.xml.sax.SAXParseException;
043:
044: /**
045: * XML parsing utilities for processing web application deployment
046: * descriptor and tag library descriptor files. FIXME - make these
047: * use a separate class loader for the parser to be used.
048: *
049: * @author Craig R. McClanahan
050: * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
051: */
052:
053: public class ParserUtils {
054:
055: /**
056: * An error handler for use when parsing XML documents.
057: */
058: static ErrorHandler errorHandler = new MyErrorHandler();
059:
060: /**
061: * An entity resolver for use when parsing XML documents.
062: */
063: static EntityResolver entityResolver = new MyEntityResolver();
064:
065: // Turn off for JSP 2.0 until switch over to using xschema.
066: public static boolean validating = false;
067:
068: // --------------------------------------------------------- Public Methods
069:
070: /**
071: * Parse the specified XML document, and return a <code>TreeNode</code>
072: * that corresponds to the root node of the document tree.
073: *
074: * @param uri URI of the XML document being parsed
075: * @param is Input source containing the deployment descriptor
076: *
077: * @exception JasperException if an input/output error occurs
078: * @exception JasperException if a parsing error occurs
079: */
080: public TreeNode parseXMLDocument(String uri, InputSource is)
081: throws JasperException {
082:
083: Document document = null;
084:
085: // Perform an XML parse of this document, via JAXP
086: try {
087: DocumentBuilderFactory factory = DocumentBuilderFactory
088: .newInstance();
089: factory.setNamespaceAware(true);
090: factory.setValidating(validating);
091: DocumentBuilder builder = factory.newDocumentBuilder();
092: builder.setEntityResolver(entityResolver);
093: builder.setErrorHandler(errorHandler);
094: document = builder.parse(is);
095: } catch (ParserConfigurationException ex) {
096: throw new JasperException(Localizer.getMessage(
097: "jsp.error.parse.xml", uri), ex);
098: } catch (SAXParseException ex) {
099: throw new JasperException(Localizer.getMessage(
100: "jsp.error.parse.xml.line", uri, Integer
101: .toString(ex.getLineNumber()), Integer
102: .toString(ex.getColumnNumber())), ex);
103: } catch (SAXException sx) {
104: throw new JasperException(Localizer.getMessage(
105: "jsp.error.parse.xml", uri), sx);
106: } catch (IOException io) {
107: throw new JasperException(Localizer.getMessage(
108: "jsp.error.parse.xml", uri), io);
109: }
110:
111: // Convert the resulting document to a graph of TreeNodes
112: return (convert(null, document.getDocumentElement()));
113: }
114:
115: /**
116: * Parse the specified XML document, and return a <code>TreeNode</code>
117: * that corresponds to the root node of the document tree.
118: *
119: * @param uri URI of the XML document being parsed
120: * @param is Input stream containing the deployment descriptor
121: *
122: * @exception JasperException if an input/output error occurs
123: * @exception JasperException if a parsing error occurs
124: */
125: public TreeNode parseXMLDocument(String uri, InputStream is)
126: throws JasperException {
127:
128: return (parseXMLDocument(uri, new InputSource(is)));
129: }
130:
131: // ------------------------------------------------------ Protected Methods
132:
133: /**
134: * Create and return a TreeNode that corresponds to the specified Node,
135: * including processing all of the attributes and children nodes.
136: *
137: * @param parent The parent TreeNode (if any) for the new TreeNode
138: * @param node The XML document Node to be converted
139: */
140: protected TreeNode convert(TreeNode parent, Node node) {
141:
142: // Construct a new TreeNode for this node
143: TreeNode treeNode = new TreeNode(node.getNodeName(), parent);
144:
145: // Convert all attributes of this node
146: NamedNodeMap attributes = node.getAttributes();
147: if (attributes != null) {
148: int n = attributes.getLength();
149: for (int i = 0; i < n; i++) {
150: Node attribute = attributes.item(i);
151: treeNode.addAttribute(attribute.getNodeName(),
152: attribute.getNodeValue());
153: }
154: }
155:
156: // Create and attach all children of this node
157: NodeList children = node.getChildNodes();
158: if (children != null) {
159: int n = children.getLength();
160: for (int i = 0; i < n; i++) {
161: Node child = children.item(i);
162: if (child instanceof Comment)
163: continue;
164: if (child instanceof Text) {
165: String body = ((Text) child).getData();
166: if (body != null) {
167: body = body.trim();
168: if (body.length() > 0)
169: treeNode.setBody(body);
170: }
171: } else {
172: TreeNode treeChild = convert(treeNode, child);
173: }
174: }
175: }
176:
177: // Return the completed TreeNode graph
178: return (treeNode);
179: }
180: }
181:
182: // ------------------------------------------------------------ Private Classes
183:
184: class MyEntityResolver implements EntityResolver {
185:
186: // Logger
187: private Log log = LogFactory.getLog(MyEntityResolver.class);
188:
189: public InputSource resolveEntity(String publicId, String systemId)
190: throws SAXException {
191: for (int i = 0; i < Constants.CACHED_DTD_PUBLIC_IDS.length; i++) {
192: String cachedDtdPublicId = Constants.CACHED_DTD_PUBLIC_IDS[i];
193: if (cachedDtdPublicId.equals(publicId)) {
194: String resourcePath = Constants.CACHED_DTD_RESOURCE_PATHS[i];
195: InputStream input = this .getClass()
196: .getResourceAsStream(resourcePath);
197: if (input == null) {
198: throw new SAXException(Localizer.getMessage(
199: "jsp.error.internal.filenotfound",
200: resourcePath));
201: }
202: InputSource isrc = new InputSource(input);
203: return isrc;
204: }
205: }
206: if (log.isDebugEnabled())
207: log.debug("Resolve entity failed" + publicId + " "
208: + systemId);
209: log.error(Localizer.getMessage(
210: "jsp.error.parse.xml.invalidPublicId", publicId));
211: return null;
212: }
213: }
214:
215: class MyErrorHandler implements ErrorHandler {
216:
217: // Logger
218: private Log log = LogFactory.getLog(MyErrorHandler.class);
219:
220: public void warning(SAXParseException ex) throws SAXException {
221: if (log.isDebugEnabled())
222: log.debug("ParserUtils: warning ", ex);
223: // We ignore warnings
224: }
225:
226: public void error(SAXParseException ex) throws SAXException {
227: throw ex;
228: }
229:
230: public void fatalError(SAXParseException ex) throws SAXException {
231: throw ex;
232: }
233: }
|