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.ivy.util;
019:
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.net.URL;
023:
024: import javax.xml.parsers.DocumentBuilder;
025: import javax.xml.parsers.DocumentBuilderFactory;
026: import javax.xml.parsers.ParserConfigurationException;
027: import javax.xml.parsers.SAXParser;
028: import javax.xml.parsers.SAXParserFactory;
029:
030: import org.apache.ivy.plugins.repository.Resource;
031: import org.apache.ivy.util.url.URLHandlerRegistry;
032: import org.w3c.dom.Document;
033: import org.xml.sax.SAXException;
034: import org.xml.sax.SAXNotRecognizedException;
035: import org.xml.sax.ext.LexicalHandler;
036: import org.xml.sax.helpers.DefaultHandler;
037:
038: public abstract class XMLHelper {
039: private static final SAXParserFactory VALIDATING_FACTORY = SAXParserFactory
040: .newInstance();
041:
042: private static final SAXParserFactory FACTORY = SAXParserFactory
043: .newInstance();
044:
045: static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
046:
047: static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
048:
049: static final String XML_NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes";
050:
051: static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
052:
053: private static boolean canUseSchemaValidation = true;
054:
055: private static DocumentBuilder docBuilder;
056:
057: static {
058: VALIDATING_FACTORY.setNamespaceAware(true);
059: VALIDATING_FACTORY.setValidating(true);
060: }
061:
062: private static SAXParser newSAXParser(URL schema,
063: InputStream schemaStream)
064: throws ParserConfigurationException, SAXException {
065: if (!canUseSchemaValidation || schema == null) {
066: return FACTORY.newSAXParser();
067: }
068: try {
069: SAXParser parser = VALIDATING_FACTORY.newSAXParser();
070: parser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
071: parser.setProperty(JAXP_SCHEMA_SOURCE, schemaStream);
072: parser.getXMLReader().setFeature(XML_NAMESPACE_PREFIXES,
073: true);
074: return parser;
075: } catch (SAXNotRecognizedException ex) {
076: System.err
077: .println("WARNING: problem while setting JAXP validating property on SAXParser... "
078: + "XML validation will not be done: "
079: + ex.getMessage());
080: canUseSchemaValidation = false;
081: return FACTORY.newSAXParser();
082: }
083: }
084:
085: // IMPORTANT: validation errors are only notified to the given handler, and
086: // do not cause exception
087: // implement warning error and fatalError methods in handler to be informed
088: // of validation errors
089: public static void parse(URL xmlURL, URL schema,
090: DefaultHandler handler) throws SAXException, IOException,
091: ParserConfigurationException {
092: parse(xmlURL, schema, handler, null);
093: }
094:
095: public static void parse(URL xmlURL, URL schema,
096: DefaultHandler handler, LexicalHandler lHandler)
097: throws SAXException, IOException,
098: ParserConfigurationException {
099: InputStream xmlStream = URLHandlerRegistry.getDefault()
100: .openStream(xmlURL);
101: try {
102: parse(xmlStream, schema, handler, lHandler);
103: } finally {
104: try {
105: xmlStream.close();
106: } catch (IOException e) {
107: // ignored
108: }
109: }
110: }
111:
112: public static void parse(InputStream xmlStream, URL schema,
113: DefaultHandler handler, LexicalHandler lHandler)
114: throws SAXException, IOException,
115: ParserConfigurationException {
116: InputStream schemaStream = null;
117: try {
118: if (schema != null) {
119: schemaStream = URLHandlerRegistry.getDefault()
120: .openStream(schema);
121: }
122: SAXParser parser = XMLHelper.newSAXParser(schema,
123: schemaStream);
124:
125: if (lHandler != null) {
126: try {
127: parser
128: .setProperty(
129: "http://xml.org/sax/properties/lexical-handler",
130: lHandler);
131: } catch (SAXException ex) {
132: System.err
133: .println("WARNING: problem while setting the lexical handler property on SAXParser: "
134: + ex.getMessage());
135: // continue without the lexical handler
136: }
137: }
138:
139: parser.parse(xmlStream, handler);
140: } finally {
141: if (schemaStream != null) {
142: try {
143: schemaStream.close();
144: } catch (IOException ex) {
145: // ignored
146: }
147: }
148: }
149: }
150:
151: public static boolean canUseSchemaValidation() {
152: return canUseSchemaValidation;
153: }
154:
155: /**
156: * Escapes invalid XML characters in the given character data using XML entities.
157: * For the moment, only the following characters are being escaped: (<), (&), (')
158: * and (").
159: *
160: * Remark: we don't escape the (>) character to keep the readability of the
161: * configuration mapping! The XML spec only requires that the (&) and (<)
162: * characters are being escaped inside character data.
163: *
164: * @param text the character data to escape
165: * @return the escaped character data
166: */
167: public static String escape(String text) {
168: if (text == null) {
169: return null;
170: }
171:
172: StringBuffer result = new StringBuffer(text.length());
173:
174: char[] chars = text.toCharArray();
175: for (int i = 0; i < chars.length; i++) {
176: switch (chars[i]) {
177: case '&':
178: result.append("&");
179: break;
180: case '<':
181: result.append("<");
182: break;
183: case '\'':
184: result.append("'");
185: break;
186: case '\"':
187: result.append(""");
188: break;
189: default:
190: result.append(chars[i]);
191: }
192: }
193:
194: return result.toString();
195: }
196:
197: public static Document parseToDom(URL descriptorURL, Resource res)
198: throws IOException, SAXException {
199: DocumentBuilder docBuilder = getDocBuilder();
200: InputStream pomStream = res.openStream();
201: Document pomDomDoc;
202: try {
203: pomDomDoc = docBuilder.parse(pomStream, res.getName());
204: } finally {
205: pomStream.close();
206: }
207: return pomDomDoc;
208: }
209:
210: public static DocumentBuilder getDocBuilder() {
211: if (docBuilder == null) {
212: try {
213: docBuilder = DocumentBuilderFactory.newInstance()
214: .newDocumentBuilder();
215: } catch (ParserConfigurationException e) {
216: throw new RuntimeException(e);
217: }
218: }
219: return docBuilder;
220: }
221:
222: private XMLHelper() {
223: }
224:
225: }
|