001: /*
002: * JBoss, Home of Professional Open Source
003: * Copyright 2005, JBoss Inc., and individual contributors as indicated
004: * by the @authors tag. See the copyright.txt in the distribution for a
005: * full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jbpm.jpdl.xml;
023:
024: import java.io.IOException;
025: import java.io.Serializable;
026:
027: import javax.xml.parsers.SAXParser;
028: import javax.xml.parsers.SAXParserFactory;
029:
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032: import org.dom4j.Document;
033: import org.dom4j.io.SAXReader;
034: import org.xml.sax.EntityResolver;
035: import org.xml.sax.ErrorHandler;
036: import org.xml.sax.InputSource;
037: import org.xml.sax.SAXException;
038: import org.xml.sax.SAXParseException;
039: import org.xml.sax.XMLReader;
040:
041: /**
042: * Validate an XML document using JAXP techniques and an XML Schema. This helper
043: * class wraps the processing of a schema to aid in schema validation throughout
044: * the product.
045: *
046: * @author Tom Baeyens
047: * @author Jim Rigsbee
048: */
049: public class JpdlParser implements Serializable {
050:
051: private static final long serialVersionUID = 1L;
052: static final EntityResolver JPDL_ENTITY_RESOLVER = new JpdlEntityResolver();
053: static SAXParserFactory saxParserFactory = createSaxParserFactory();
054:
055: public static Document parse(InputSource inputSource,
056: ProblemListener problemListener) throws Exception {
057: Document document = null;
058: SAXReader saxReader = createSaxReader(problemListener);
059: document = saxReader.read(inputSource);
060: return document;
061: }
062:
063: public static SAXReader createSaxReader(
064: ProblemListener problemListener) throws Exception {
065: XMLReader xmlReader = createXmlReader();
066: SAXReader saxReader = new SAXReader(xmlReader);
067: saxReader
068: .setErrorHandler(new JpdlErrorHandler(problemListener));
069: saxReader.setEntityResolver(JPDL_ENTITY_RESOLVER);
070: return saxReader;
071: }
072:
073: public static XMLReader createXmlReader() throws Exception {
074: SAXParser saxParser = saxParserFactory.newSAXParser();
075: XMLReader xmlReader = saxParser.getXMLReader();
076:
077: try {
078: saxParser
079: .setProperty(
080: "http://java.sun.com/xml/jaxp/properties/schemaLanguage",
081: "http://www.w3.org/2001/XMLSchema");
082: } catch (SAXException e) {
083: log
084: .warn(
085: "couldn't set xml parser property 'http://java.sun.com/xml/jaxp/properties/schemaLanguage' to 'http://www.w3.org/2001/XMLSchema'",
086: e);
087: }
088:
089: try {
090: saxParser
091: .setProperty(
092: "http://apache.org/xml/properties/schema/external-schemaLocation",
093: "http://jbpm.org/3/jpdl http://jbpm.org/jpdl-3.0.xsd "
094: + "urn:jbpm.org:jpdl-3.0 http://jbpm.org/jpdl-3.0.xsd "
095: + "urn:jbpm.org:jpdl-3.1 http://jbpm.org/jpdl-3.1.xsd "
096: + "urn:jbpm.org:jpdl-3.2 http://jbpm.org/jpdl-3.2.xsd");
097: } catch (SAXException e) {
098: log
099: .warn(
100: "couldn't set xml parser property 'http://apache.org/xml/properties/schema/external-schemaLocation'",
101: e);
102: }
103:
104: try {
105: xmlReader
106: .setFeature(
107: "http://apache.org/xml/features/validation/dynamic",
108: true);
109: } catch (SAXException e) {
110: log
111: .warn(
112: "couldn't set xml parser feature 'http://apache.org/xml/features/validation/dynamic'",
113: e);
114: }
115: return xmlReader;
116: }
117:
118: static class JpdlErrorHandler implements ErrorHandler, Serializable {
119: private static final long serialVersionUID = 1L;
120: ProblemListener problemListener = null;
121:
122: JpdlErrorHandler(ProblemListener problemListener) {
123: this .problemListener = problemListener;
124: }
125:
126: public void warning(SAXParseException pe) {
127: addProblem(Problem.LEVEL_WARNING, "line "
128: + pe.getLineNumber() + ": " + pe.getMessage(), pe);
129: }
130:
131: public void error(SAXParseException pe) {
132: addProblem(Problem.LEVEL_ERROR, "line "
133: + pe.getLineNumber() + ": " + pe.getMessage(), pe);
134: }
135:
136: public void fatalError(SAXParseException pe) {
137: addProblem(Problem.LEVEL_FATAL, "line "
138: + pe.getLineNumber() + ": " + pe.getMessage(), pe);
139: }
140:
141: void addProblem(int level, String description,
142: Throwable exception) {
143: problemListener.addProblem(new Problem(level, description,
144: exception));
145: }
146: }
147:
148: static class JpdlEntityResolver implements EntityResolver,
149: Serializable {
150: private static final long serialVersionUID = 1L;
151:
152: public InputSource resolveEntity(String publicId,
153: String systemId) throws SAXException, IOException {
154: InputSource inputSource = null;
155: log.debug("resolving schema reference publicId(" + publicId
156: + ") systemId(" + systemId + ")");
157:
158: if ("http://jbpm.org/jpdl-3.2.xsd".equals(systemId)) {
159: log
160: .debug("providing input source to local 'jpdl-3.2.xsd' resource");
161: inputSource = new InputSource(this .getClass()
162: .getResourceAsStream("jpdl-3.2.xsd"));
163:
164: } else if ("http://jbpm.org/jpdl-3.1.xsd".equals(systemId)) {
165: log
166: .debug("providing input source to local 'jpdl-3.1.xsd' resource");
167: inputSource = new InputSource(this .getClass()
168: .getResourceAsStream("jpdl-3.1.xsd"));
169:
170: } else if ("http://jbpm.org/jpdl-3.0.xsd".equals(systemId)) {
171: log
172: .debug("providing input source to local 'jpdl-3.0.xsd' resource");
173: inputSource = new InputSource(this .getClass()
174: .getResourceAsStream("jpdl-3.0.xsd"));
175:
176: } else {
177: log.debug("original systemId as input source");
178: inputSource = new InputSource(systemId);
179: }
180: return inputSource;
181: }
182: }
183:
184: private static SAXParserFactory createSaxParserFactory() {
185: SAXParserFactory saxParserFactory = SAXParserFactory
186: .newInstance();
187: saxParserFactory.setValidating(true);
188: saxParserFactory.setNamespaceAware(true);
189: return saxParserFactory;
190: }
191:
192: private static final Log log = LogFactory.getLog(JpdlParser.class);
193: }
|