| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.cocoon.components.validation.jaxp; |
| |
| import java.io.IOException; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import javax.xml.transform.sax.SAXSource; |
| import javax.xml.validation.SchemaFactory; |
| |
| import org.apache.avalon.framework.configuration.Configurable; |
| import org.apache.avalon.framework.configuration.Configuration; |
| import org.apache.avalon.framework.configuration.ConfigurationException; |
| import org.apache.avalon.framework.thread.ThreadSafe; |
| import org.apache.cocoon.components.validation.Schema; |
| import org.apache.cocoon.components.validation.Validator; |
| import org.apache.cocoon.components.validation.impl.AbstractSchemaParser; |
| import org.apache.cocoon.components.validation.impl.DraconianErrorHandler; |
| import org.apache.excalibur.source.Source; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * <p>An implementation of the {@link SchemaParser} interface wrapping JAXP |
| * {@link SchemaFactory} instances.</p> |
| * |
| */ |
| public class JaxpSchemaParser extends AbstractSchemaParser |
| implements Configurable, ThreadSafe { |
| |
| /** <p>The class name of the {@link SchemaFactory} to use.</p> */ |
| private String className = null; |
| /** <p>The list of grammars supported by this instance.</p> */ |
| private String[] grammars = null; |
| |
| /** |
| * <p>Create a new {@link JaxpSchemaParser} instance.</p> |
| */ |
| public JaxpSchemaParser() { |
| super(); |
| } |
| |
| /** |
| * <p>Configure this instance.</p> |
| * |
| * <p>The {@link JaxpSchemaParser} requires at least one configuration element: |
| * <code><factory-class><i>class name</i></factory-class></code>. |
| * This specifies the JAXP {@link SchemaFactory} class to be used by this |
| * instance.</p> |
| * |
| * <p>Grammars will be automatically detected if the {@link SchemaFactory} |
| * supports one of the {@link Validator.GRAMMAR_RELAX_NG RELAX-NG} grammar, |
| * {@link Validator.GRAMMAR_XML_SCHEMA XML-Schema} grammar, or the |
| * {@link Validator.GRAMMAR_XML_DTD XML-DTD} grammar.</p> |
| * |
| * <p>If the factory is known to support different grammars, the default |
| * detection can be overridden specifying in the configuration something similar |
| * to the following:</p> |
| * |
| * <pre> |
| * <grammars> |
| * <grammar>... a first grammar identifier ...</grammar> |
| * <grammar>... another grammar identifier ...</grammar> |
| * </grammars> |
| * </pre> |
| */ |
| public void configure(Configuration conf) |
| throws ConfigurationException { |
| this.className = conf.getChild("factory-class").getValue(); |
| final SchemaFactory fact; |
| try { |
| fact = (SchemaFactory) Class.forName(this.className).newInstance(); |
| } catch (Exception exception) { |
| String message = "Unable to instantiate factory " + this.className; |
| throw new ConfigurationException(message, conf, exception); |
| } |
| |
| /* Detect languages or use the supplied ones */ |
| Configuration languages[] = conf.getChild("grammars").getChildren("grammar"); |
| Set grammars = new HashSet(); |
| if (languages.length > 0) { |
| |
| /* If the configuration specified (formally) a list of grammars use it */ |
| for (int x = 0; x < languages.length; x++) { |
| String language = languages[x].getValue(); |
| if (fact.isSchemaLanguageSupported(language)) { |
| grammars.add(language); |
| continue; |
| } |
| /* If the configured language is not supported throw an exception */ |
| String message = "JAXP SchemaFactory \"" + this.className + "\" " + |
| "does not support configured grammar " + language; |
| throw new ConfigurationException(message, languages[x]); |
| } |
| } else { |
| |
| /* Attempt to detect the languages directly using the JAXP factory */ |
| if (fact.isSchemaLanguageSupported(Validator.GRAMMAR_XML_SCHEMA)) { |
| grammars.add(Validator.GRAMMAR_XML_SCHEMA); |
| } |
| if (fact.isSchemaLanguageSupported(Validator.GRAMMAR_RELAX_NG)) { |
| grammars.add(Validator.GRAMMAR_RELAX_NG); |
| } |
| if (fact.isSchemaLanguageSupported(Validator.GRAMMAR_XML_DTD)) { |
| grammars.add(Validator.GRAMMAR_XML_DTD); |
| } |
| } |
| |
| /* Store our grammars */ |
| this.grammars = (String[]) grammars.toArray(new String[grammars.size()]); |
| } |
| |
| /** |
| * <p>Parse the specified {@link Source} and return a new {@link Schema}.</p> |
| * |
| * <p>The returned {@link Schema} must be able to validate multiple documents |
| * via multiple invocations of {@link Schema#createValidator(ErrorHandler)}.</p> |
| * |
| * @param source the {@link Source} associated with the {@link Schema} to return. |
| * @return a <b>non-null</b> {@link Schema} instance. |
| * @throws SAXException if a grammar error occurred parsing the schema. |
| * @throws IOException if an I/O error occurred parsing the schema. |
| * @throws IllegalArgumentException if the specified grammar type is not one |
| * of the grammar types returned by the |
| * {@link #getSupportedGrammars()} method. |
| */ |
| public Schema parseSchema(Source source, String grammar) |
| throws SAXException, IOException { |
| final SchemaFactory factory; |
| try { |
| factory = (SchemaFactory) Class.forName(this.className).newInstance(); |
| } catch (Exception exception) { |
| String message = "Unable to instantiate factory " + this.className; |
| throw new SAXException(message, exception); |
| } |
| |
| JaxpResolver r = new JaxpResolver(this.sourceResolver, this.entityResolver); |
| SAXSource s = new SAXSource(r.resolveSource(source)); |
| factory.setErrorHandler(DraconianErrorHandler.INSTANCE); |
| factory.setResourceResolver(r); |
| |
| return new JaxpSchema(factory.newSchema(s), r.close()); |
| } |
| |
| public String[] getSupportedGrammars() { |
| return this.grammars; |
| } |
| } |