/*
* Javolution - Java(TM) Solution for Real-Time and Embedded Systems
* Copyright (C) 2005 - Javolution (http://javolution.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package javolution.xml.stream;
import java.io.InputStream;
import java.io.Reader;
import j2me.util.Map;
import javolution.context.ObjectFactory;
import javolution.lang.Configurable;
/**
* <p> The class represents the factory for getting {@link XMLStreamReader}
* intances.
*
* <p> The {@link #newInstance() default implementation} automatically
* {@link ObjectFactory#recycle recycles} any reader which has been
* {@link XMLStreamReader#close() closed}.</p>
*
* <P> Usage example:[code]
*
* // Lets read a CharSequence input.
* String xml = "...";
* CharSequenceReader in = new CharSequenceReader().setInput(xml);
* // Creates a factory of readers coalescing adjacent character data.
* XMLInputFactory factory = XMLInputFactory.newInstance();
* factory.setProperty(XMLInputFactory.IS_COALESCING, true);
*
* // Creates a new reader (potentially recycled).
* XMLStreamReader reader = factory.createXMLStreamReader(in);
*
* // Parses XML.
* for (int e=reader.next(); e != XMLStreamConstants.END_DOCUMENT; e = reader.next()) {
* switch (e) { // Event.
* ...
* }
* }
* reader.close(); // Automatically recycles this writer.
* in.close(); // Underlying input should be closed explicitly.
* [/code]</p>
*
* @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
* @version 4.0, September 4, 2006
*/
public abstract class XMLInputFactory {
/**
* Holds the XMLInputFactory implementation (configurable).
*/
public static final Configurable/*<Class<? extends XMLInputFactory>>*/
CLASS = new Configurable/*<Class<? extends XMLInputFactory>>*/(Default.class) {};
/**
* The property that requires the parser to coalesce adjacent character data
* sections (type: <code>Boolean</code>, default: <code>FALSE</code>)
*/
public static final String IS_COALESCING = "javolution.xml.stream.isCoalescing";
/**
* Property used to specify additional entities to be recognized by the
* readers (type: <code>java.util.Map</code>, default: <code>null</code>).
* For example:[code]
* FastMap<String, String> HTML_ENTITIES = new FastMap<String, String>();
* HTML_ENTITIES.put("nbsp", " ");
* HTML_ENTITIES.put("copy", "©");
* HTML_ENTITIES.put("eacute", "é");
* ...
* XMLInputFactory factory = XMLInputFactory.newInstance();
* factory.setProperty(ENTITIES, HTML_ENTITIES);
* [/code]
*/
public static final String ENTITIES = "javolution.xml.stream.entities";
/**
* Default constructor.
*/
protected XMLInputFactory() {
}
/**
* Returns a new instance of the {@link #CLASS} input factory
* implementation which may be configurated by the user
* (see {@link #setProperty(String, Object)}). The input factory
* instance is allocated through {@link ObjectFactory#getInstance(Class)}.
*
* @return a new factory instance.
*/
public static XMLInputFactory newInstance() {
Class cls = (Class) CLASS.get();
return (XMLInputFactory) ObjectFactory.getInstance(cls).object();
}
/**
* Returns a XML stream reader for the specified I/O reader.
*
* @param reader the XML data to read from.
* @throws XMLStreamException
*/
public abstract XMLStreamReader createXMLStreamReader(Reader reader)
throws XMLStreamException;
/**
* Returns a XML stream reader for the specified input stream
* (encoding autodetected).
*
* @param stream the input stream to read from.
* @throws XMLStreamException
*/
public abstract XMLStreamReader createXMLStreamReader(InputStream stream)
throws XMLStreamException;
/**
* Returns a XML stream reader for the specified input stream using the
* specified encoding.
*
* @param stream the input stream to read from.
* @param encoding the character encoding of the stream.
* @throws XMLStreamException
*/
public abstract XMLStreamReader createXMLStreamReader(InputStream stream,
String encoding) throws XMLStreamException;
/**
* Allows the user to set specific feature/property on the underlying
* implementation. The underlying implementation is not required to support
* every setting of every property in the specification and may use
* <code>IllegalArgumentException</code> to signal that an unsupported
* property may not be set with the specified value.
*
* @param name the name of the property.
* @param value the value of the property
* @throws IllegalArgumentException if the property is not supported.
*/
public abstract void setProperty(String name, Object value)
throws IllegalArgumentException;
/**
* Gets the value of a feature/property from the underlying implementation.
*
* @param name the name of the property (may not be null).
* @return the value of the property.
* @throws IllegalArgumentException if the property is not supported.
*/
public abstract Object getProperty(String name)
throws IllegalArgumentException;
/**
* Queries the set of properties that this factory supports.
*
* @param name the name of the property.
* @return <code>true</code> if the property is supported;
* <code>false</code> otherwise.
*/
public abstract boolean isPropertySupported(String name);
/**
* This class represents the default factory implementation.
*/
private static final class Default extends XMLInputFactory {
Map _entities = null;
// Implements XMLInputFactory abstract method.
public XMLStreamReader createXMLStreamReader(Reader reader)
throws XMLStreamException {
XMLStreamReaderImpl xmlReader = newReader();
xmlReader.setInput(reader);
return xmlReader;
}
// Implements XMLInputFactory abstract method.
public XMLStreamReader createXMLStreamReader(InputStream stream)
throws XMLStreamException {
XMLStreamReaderImpl xmlReader = newReader();
xmlReader.setInput(stream);
return xmlReader;
}
// Implements XMLInputFactory abstract method.
public XMLStreamReader createXMLStreamReader(InputStream stream,
String encoding) throws XMLStreamException {
XMLStreamReaderImpl xmlReader = newReader();
xmlReader.setInput(stream, encoding);
return xmlReader;
}
// Implements XMLInputFactory abstract method.
public void setProperty(String name, Object value)
throws IllegalArgumentException {
if (name.equals(IS_COALESCING)) {
// Do nothing, always coalescing.
} else if (name.equals(ENTITIES)) {
_entities = (Map) value;
} else {
throw new IllegalArgumentException("Property: " + name
+ " not supported");
}
}
// Implements XMLInputFactory abstract method.
public Object getProperty(String name) throws IllegalArgumentException {
if (name.equals(IS_COALESCING)) {
return Boolean.TRUE;
} else if (name.equals(ENTITIES)) {
return _entities;
} else {
throw new IllegalArgumentException("Property: " + name
+ " not supported");
}
}
// Implements XMLInputFactory abstract method.
public boolean isPropertySupported(String name) {
return name.equals(IS_COALESCING) || name.equals(ENTITIES);
}
private XMLStreamReaderImpl newReader() {
XMLStreamReaderImpl xmlReader = (XMLStreamReaderImpl) XML_READER_FACTORY
.object();
if (_entities != null) {
xmlReader.setEntities(_entities);
}
xmlReader._objectFactory = XML_READER_FACTORY;
return xmlReader;
}
}
private static ObjectFactory XML_READER_FACTORY = new ObjectFactory() {
protected Object create() {
return new XMLStreamReaderImpl();
}
protected void cleanup(Object obj) {
((XMLStreamReaderImpl) obj).reset();
}
};
// Allows instances of private classes to be factory produced.
static {
ObjectFactory.setInstance(new ObjectFactory() {
protected Object create() {
return new Default();
} }, Default.class);
}}