001: /* $Id: XercesParser.java 467222 2006-10-24 03:17:11Z markt $
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: package org.apache.tomcat.util.digester;
020:
021: import java.lang.reflect.Method;
022: import java.util.Properties;
023:
024: import javax.xml.parsers.ParserConfigurationException;
025: import javax.xml.parsers.SAXParser;
026: import javax.xml.parsers.SAXParserFactory;
027:
028: import org.apache.juli.logging.Log;
029: import org.apache.juli.logging.LogFactory;
030: import org.xml.sax.SAXException;
031: import org.xml.sax.SAXNotRecognizedException;
032: import org.xml.sax.SAXNotSupportedException;
033:
034: /**
035: * Create a <code>SAXParser</code> based on the underlying Xerces version.
036: * Currently, Xerces 2.3 and up doesn't implement schema validation the same way
037: * 2.1 was. In other to support schema validation in a portable way between
038: * parser, some features/properties need to be set.
039: *
040: * @since 1.6
041: */
042:
043: public class XercesParser {
044:
045: /**
046: * The Log to which all SAX event related logging calls will be made.
047: */
048: protected static Log log = LogFactory
049: .getLog("org.apache.commons.digester.Digester.sax");
050:
051: /**
052: * The JAXP 1.2 property required to set up the schema location.
053: */
054: private static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
055:
056: /**
057: * The JAXP 1.2 property to set up the schemaLanguage used.
058: */
059: protected static String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
060:
061: /**
062: * Xerces dynamic validation property
063: */
064: protected static String XERCES_DYNAMIC = "http://apache.org/xml/features/validation/dynamic";
065:
066: /**
067: * Xerces schema validation property
068: */
069: protected static String XERCES_SCHEMA = "http://apache.org/xml/features/validation/schema";
070:
071: /**
072: * A <code>float</code> representing the underlying Xerces version
073: */
074: protected static float version;
075:
076: /**
077: * The current Xerces version.
078: */
079: protected static String versionNumber = null;
080:
081: /**
082: * Return the current Xerces version.
083: * @return the current Xerces version.
084: */
085: private static String getXercesVersion() {
086: // If for some reason we can't get the version, set it to 1.0.
087: String versionNumber = "1.0";
088: try {
089: // Use reflection to avoid a build dependency with Xerces.
090: Class versionClass = Class
091: .forName("org.apache.xerces.impl.Version");
092: // Will return Xerces-J 2.x.0
093: Method method = versionClass.getMethod("getVersion",
094: (Class[]) null);
095: String version = (String) method.invoke(null,
096: (Object[]) null);
097: versionNumber = version.substring("Xerces-J".length(),
098: version.lastIndexOf("."));
099: } catch (Exception ex) {
100: // Do nothing.
101: }
102: return versionNumber;
103: }
104:
105: /**
106: * Create a <code>SAXParser</code> based on the underlying
107: * <code>Xerces</code> version.
108: * @param properties parser specific properties/features
109: * @return an XML Schema/DTD enabled <code>SAXParser</code>
110: */
111: public static SAXParser newSAXParser(Properties properties)
112: throws ParserConfigurationException, SAXException,
113: SAXNotSupportedException {
114:
115: SAXParserFactory factory = (SAXParserFactory) properties
116: .get("SAXParserFactory");
117:
118: if (versionNumber == null) {
119: versionNumber = getXercesVersion();
120: version = new Float(versionNumber).floatValue();
121: }
122:
123: // Note: 2.2 is completely broken (with XML Schema).
124: if (version > 2.1) {
125:
126: configureXerces(factory);
127: return factory.newSAXParser();
128: } else {
129: SAXParser parser = factory.newSAXParser();
130: configureOldXerces(parser, properties);
131: return parser;
132: }
133: }
134:
135: /**
136: * Configure schema validation as recommended by the JAXP 1.2 spec.
137: * The <code>properties</code> object may contains information about
138: * the schema local and language.
139: * @param properties parser optional info
140: */
141: private static void configureOldXerces(SAXParser parser,
142: Properties properties) throws ParserConfigurationException,
143: SAXNotSupportedException {
144:
145: String schemaLocation = (String) properties
146: .get("schemaLocation");
147: String schemaLanguage = (String) properties
148: .get("schemaLanguage");
149:
150: try {
151: if (schemaLocation != null) {
152: parser
153: .setProperty(JAXP_SCHEMA_LANGUAGE,
154: schemaLanguage);
155: parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation);
156: }
157: } catch (SAXNotRecognizedException e) {
158: log.info(parser.getClass().getName() + ": "
159: + e.getMessage() + " not supported.");
160: }
161:
162: }
163:
164: /**
165: * Configure schema validation as recommended by the Xerces spec.
166: * Both DTD and Schema validation will be enabled simultaneously.
167: * @param factory SAXParserFactory to be configured
168: */
169: private static void configureXerces(SAXParserFactory factory)
170: throws ParserConfigurationException,
171: SAXNotRecognizedException, SAXNotSupportedException {
172:
173: factory.setFeature(XERCES_DYNAMIC, true);
174: factory.setFeature(XERCES_SCHEMA, true);
175:
176: }
177: }
|