/* * 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 xni.parser; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Hashtable; import java.util.Locale; import java.util.Vector; import org.apache.xerces.xni.XMLDTDContentModelHandler; import org.apache.xerces.xni.XMLDTDHandler; import org.apache.xerces.xni.XMLDocumentHandler; import org.apache.xerces.xni.XNIException; import org.apache.xerces.xni.parser.XMLComponent; import org.apache.xerces.xni.parser.XMLConfigurationException; import org.apache.xerces.xni.parser.XMLEntityResolver; import org.apache.xerces.xni.parser.XMLErrorHandler; import org.apache.xerces.xni.parser.XMLInputSource; import org.apache.xerces.xni.parser.XMLParserConfiguration; /** * This abstract parser configuration simply helps manage components, * features and properties, and other tasks common to all parser * configurations. In order to subclass this configuration and use * it effectively, the subclass is required to do the following: * <ul> * <li> * Add all configurable components using the <code>addComponent</code> * method,</li> * <li>Implement the <code>parse</code> method, and</li> * <li>Call the <code>resetComponents</code> before parsing.</li> * </ul> * * @author Andy Clark, IBM * * @version $Id: AbstractConfiguration.java 699895 2008-09-28 21:21:24Z mrglavas $ */ public abstract class AbstractConfiguration implements XMLParserConfiguration { // // Data // // features and properties /** Recognized features. */ protected final Vector fRecognizedFeatures = new Vector(); /** Recognized properties. */ protected final Vector fRecognizedProperties = new Vector(); /** Features. */ protected final Hashtable fFeatures = new Hashtable(); /** Properties. */ protected final Hashtable fProperties = new Hashtable(); // other parser configuration fields /** The registered entity resolver. */ protected XMLEntityResolver fEntityResolver; /** The registered error handler. */ protected XMLErrorHandler fErrorHandler; /** The registered document handler. */ protected XMLDocumentHandler fDocumentHandler; /** The registered DTD handler. */ protected XMLDTDHandler fDTDHandler; /** The registered DTD content model handler. */ protected XMLDTDContentModelHandler fDTDContentModelHandler; /** Locale for error messages. */ protected Locale fLocale; // components /** List of configurable components. */ protected final Vector fComponents = new Vector(); // // XMLParserConfiguration methods // /** * Allows a parser to add parser specific features to be recognized * and managed by the parser configuration. * * @param featureIds An array of the additional feature identifiers * to be recognized. */ public void addRecognizedFeatures(String[] featureIds) { int length = featureIds != null ? featureIds.length : 0; for (int i = 0; i < length; i++) { String featureId = featureIds[i]; if (!fRecognizedFeatures.contains(featureId)) { fRecognizedFeatures.addElement(featureId); } } } // addRecognizedFeatures(String[]) /** * Sets the state of a feature. This method is called by the parser * and gets propagated to components in this parser configuration. * * @param featureId The feature identifier. * @param state The state of the feature. * * @throws XMLConfigurationException Thrown if there is a configuration * error. */ public void setFeature(String featureId, boolean state) throws XMLConfigurationException { if (!fRecognizedFeatures.contains(featureId)) { short type = XMLConfigurationException.NOT_RECOGNIZED; throw new XMLConfigurationException(type, featureId); } fFeatures.put(featureId, state ? Boolean.TRUE : Boolean.FALSE); int length = fComponents.size(); for (int i = 0; i < length; i++) { XMLComponent component = (XMLComponent)fComponents.elementAt(i); component.setFeature(featureId, state); } } // setFeature(String,boolean) /** * Returns the state of a feature. * * @param featureId The feature identifier. * * @throws XMLConfigurationException Thrown if there is a configuration * error. */ public boolean getFeature(String featureId) throws XMLConfigurationException { if (!fRecognizedFeatures.contains(featureId)) { short type = XMLConfigurationException.NOT_RECOGNIZED; throw new XMLConfigurationException(type, featureId); } Boolean state = (Boolean)fFeatures.get(featureId); return state != null ? state.booleanValue() : false; } // getFeature(String):boolean /** * Allows a parser to add parser specific properties to be recognized * and managed by the parser configuration. * * @param propertyIds An array of the additional property identifiers * to be recognized. */ public void addRecognizedProperties(String[] propertyIds) { int length = propertyIds != null ? propertyIds.length : 0; for (int i = 0; i < length; i++) { String propertyId = propertyIds[i]; if (!fRecognizedProperties.contains(propertyId)) { fRecognizedProperties.addElement(propertyId); } } } // addRecognizedProperties(String[]) /** * Sets the value of a property. This method is called by the parser * and gets propagated to components in this parser configuration. * * @param propertyId The property identifier. * @param value The value of the property. * * @throws XMLConfigurationException Thrown if there is a configuration * error. */ public void setProperty(String propertyId, Object value) throws XMLConfigurationException { if (!fRecognizedProperties.contains(propertyId)) { short type = XMLConfigurationException.NOT_RECOGNIZED; throw new XMLConfigurationException(type, propertyId); } if (value != null) { fProperties.put(propertyId, value); } else { fProperties.remove(propertyId); } int length = fComponents.size(); for (int i = 0; i < length; i++) { XMLComponent component = (XMLComponent)fComponents.elementAt(i); component.setProperty(propertyId, value); } } // setProperty(String,Object) /** * Returns the value of a property. * * @param propertyId The property identifier. * * @throws XMLConfigurationException Thrown if there is a configuration * error. */ public Object getProperty(String propertyId) throws XMLConfigurationException { if (!fRecognizedProperties.contains(propertyId)) { short type = XMLConfigurationException.NOT_RECOGNIZED; throw new XMLConfigurationException(type, propertyId); } Object value = fProperties.get(propertyId); return value; } // getProperty(String):Object /** * Sets the entity resolver. * * @param resolver The new entity resolver. */ public void setEntityResolver(XMLEntityResolver resolver) { fEntityResolver = resolver; } // setEntityResolver(XMLEntityResolver) /** Returns the registered entity resolver. */ public XMLEntityResolver getEntityResolver() { return fEntityResolver; } // getEntityResolver():XMLEntityResolver /** * Sets the error handler. * * @param handler The error resolver. */ public void setErrorHandler(XMLErrorHandler handler) { fErrorHandler = handler; } // setErrorHandler(XMLErrorHandler) /** Returns the registered error handler. */ public XMLErrorHandler getErrorHandler() { return fErrorHandler; } // getErrorHandler():XMLErrorHandler /** * Sets the document handler to receive information about the document. * * @param handler The document handler. */ public void setDocumentHandler(XMLDocumentHandler handler) { fDocumentHandler = handler; } // setDocumentHandler(XMLDocumentHandler) /** Returns the registered document handler. */ public XMLDocumentHandler getDocumentHandler() { return fDocumentHandler; } // getDocumentHandler():XMLDocumentHandler /** * Sets the DTD handler. * * @param handler The DTD handler. */ public void setDTDHandler(XMLDTDHandler handler) { fDTDHandler = handler; } // setDTDHandler(XMLDTDHandler) /** Returns the registered DTD handler. */ public XMLDTDHandler getDTDHandler() { return fDTDHandler; } // getDTDHandler():XMLDTDHandler /** * Sets the DTD content model handler. * * @param handler The DTD content model handler. */ public void setDTDContentModelHandler(XMLDTDContentModelHandler handler) { fDTDContentModelHandler = handler; } // setDTDContentModelHandler(XMLDTDContentModelHandler) /** Returns the registered DTD content model handler. */ public XMLDTDContentModelHandler getDTDContentModelHandler() { return fDTDContentModelHandler; } // getDTDContentModelHandler():XMLDTDContentModelHandler /** * Parse an XML document. * <p> * The parser can use this method to instruct this configuration * to begin parsing an XML document from any valid input source * (a character stream, a byte stream, or a URI). * <p> * Parsers may not invoke this method while a parse is in progress. * Once a parse is complete, the parser may then parse another XML * document. * <p> * This method is synchronous: it will not return until parsing * has ended. If a client application wants to terminate * parsing early, it should throw an exception. * <p> * <strong>Note:</strong> This method needs to be implemented * by the subclass. * * @param source The input source for the top-level of the * XML document. * * @exception XNIException Any XNI exception, possibly wrapping * another exception. * @exception IOException An IO exception from the parser, possibly * from a byte stream or character stream * supplied by the parser. */ public abstract void parse(XMLInputSource inputSource) throws IOException, XNIException; /** * Set the locale to use for messages. * * @param locale The locale object to use for localization of messages. * * @exception XNIException Thrown if the parser does not support the * specified locale. */ public void setLocale(Locale locale) { fLocale = locale; } // setLocale(Locale) /** Returns the locale. */ public Locale getLocale() { return fLocale; } // getLocale():Locale // // Protected methods // /** * Adds a component to list of configurable components. If the * same component is added multiple times, the component is * added only the first time. * <p> * This method helps manage the components in the configuration. * Therefore, all subclasses should call this method to add the * components specific to the configuration. * * @param component The component to add. * * @see #resetComponents */ protected void addComponent(XMLComponent component) { if (!fComponents.contains(component)) { fComponents.addElement(component); addRecognizedFeatures(component.getRecognizedFeatures()); addRecognizedProperties(component.getRecognizedProperties()); } } // addComponent(XMLComponent) /** * Resets all of the registered components. Before the subclassed * configuration begins parsing, it should call this method to * reset the components. * * @see #addComponent */ protected void resetComponents() throws XMLConfigurationException { int length = fComponents.size(); for (int i = 0; i < length; i++) { XMLComponent component = (XMLComponent)fComponents.elementAt(i); component.reset(this); } } // resetComponents() /** * This method tries to open the necessary stream for the given * XMLInputSource. If the input source already has a character * stream (java.io.Reader) or a byte stream (java.io.InputStream) * set, this method returns immediately. However, if no character * or byte stream is already open, this method attempts to open * an input stream using the source's system identifier. * * @param source The input source to open. */ protected void openInputSourceStream(XMLInputSource source) throws IOException { if (source.getCharacterStream() != null) { return; } InputStream stream = source.getByteStream(); if (stream == null) { String systemId = source.getSystemId(); try { URL url = new URL(systemId); stream = url.openStream(); } catch (MalformedURLException e) { stream = new FileInputStream(systemId); } source.setByteStream(stream); } } // openInputSourceStream(XMLInputSource) } // class AbstractConfiguration