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