001: /*
002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
003: * Copyright (C) 2006 - Javolution (http://javolution.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javolution.xml.stream;
010:
011: import java.io.OutputStream;
012: import java.io.Writer;
013: import javolution.context.ObjectFactory;
014: import javolution.lang.Configurable;
015:
016: /**
017: * <p> The class represents the factory for getting {@link XMLStreamWriter}
018: * intances.</p>
019: *
020: * <p> The {@link #newInstance() default implementation} automatically
021: * {@link ObjectFactory#recycle recycles} any writer which has been
022: * {@link XMLStreamWriter#close() closed}.</p>
023: *
024: * <P> Usage example:[code]
025: *
026: * // Lets format to an appendable.
027: * TextBuilder xml = new TextBuilder();
028: * AppendableWriter out = new AppendableWriter(xml);
029: *
030: * // Creates a factory producing writers using tab indentation.
031: * XMLOutpuFactory factory = XMLOutputFactory.newInstance();
032: * factory.setProperty(XMLOutputFactory.INDENTATION, "/t");
033: *
034: * // Creates a new writer (potentially recycled).
035: * XMLStreamWriter writer = factory.createXMLStreamReader(out);
036: *
037: * // Formats to XML.
038: * writer.writeStartDocument();
039: * writer.writeStartElement(...);
040: * ...
041: * writer.close(); // Automatically recycles this writer.
042: * out.close(); // Underlying output should be closed explicitly.
043: *
044: * // Displays the formatted output.
045: * System.out.println(xml);
046: * [/code]</p>
047: *
048: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
049: * @version 4.0, September 4, 2006
050: */
051: public abstract class XMLOutputFactory {
052:
053: /**
054: * Holds the XMLOutputFactory default implementation (configurable).
055: */
056: public static final Configurable/*<Class<? extends XMLOutputFactory>>*/DEFAULT = new Configurable/*<Class<? extends XMLOutputFactory>>*/(
057: Default.CLASS);
058:
059: /**
060: * Property used to set prefix defaulting on the output side
061: * (type: <code>Boolean</code>, default: <code>FALSE</code>).
062: */
063: public static final String IS_REPAIRING_NAMESPACES = "javolution.xml.stream.isRepairingNamespaces";
064:
065: /**
066: * Property used to specify the prefix to be appended by a trailing
067: * part (a sequence number) in order to make it unique to be usable as
068: * a temporary non-colliding prefix when repairing namespaces
069: * (type: <code>String</code>, default: <code>"ns"</code>).
070: */
071: public final static String REPAIRING_PREFIX = "javolution.xml.stream.repairingPrefix";
072:
073: /**
074: * Property used to specify an indentation string; non-null indentation
075: * forces the writer to write elements into separate lines
076: * (type: <code>String</code>, default: <code>null</code>).
077: */
078: public static final String INDENTATION = "javolution.xml.stream.indentation";
079:
080: /**
081: * Property indicating if the stream writers are allowed to automatically
082: * output empty elements when a start element is immediately followed by
083: * matching end element
084: * (type: <code>Boolean</code>, default: <code>FALSE</code>).
085: */
086: public final static String AUTOMATIC_EMPTY_ELEMENTS = "javolution.xml.stream.automaticEmptyElements";
087:
088: /**
089: * Default constructor.
090: */
091: protected XMLOutputFactory() {
092: }
093:
094: /**
095: * Returns a new instance of the {@link #DEFAULT} output factory
096: * implementation which may be configurated by the user
097: * (see {@link #setProperty(String, Object)}). The output factory
098: * instance is allocated through {@link ObjectFactory#getInstance(Class)}.
099: *
100: * @return a new factory instance.
101: */
102: public static XMLOutputFactory newInstance() {
103: Class cls = (Class) DEFAULT.get();
104: return (XMLOutputFactory) ObjectFactory.getInstance(cls)
105: .object();
106: }
107:
108: /**
109: * Returns a XML stream writer to the specified i/o writer.
110: *
111: * @param writer the writer to write to.
112: * @throws XMLStreamException
113: */
114: public abstract XMLStreamWriter createXMLStreamWriter(Writer writer)
115: throws XMLStreamException;
116:
117: /**
118: * Returns a XML stream writer to the specified output stream (UTF-8
119: * encoding).
120: *
121: * @param stream the stream to write to.
122: * @throws XMLStreamException
123: */
124: public abstract XMLStreamWriter createXMLStreamWriter(
125: OutputStream stream) throws XMLStreamException;
126:
127: /**
128: * Returns a XML stream writer to the specified output stream using the
129: * specified encoding.
130: *
131: * @param stream the stream to write to.
132: * @param encoding the encoding to use.
133: * @throws XMLStreamException
134: */
135: public abstract XMLStreamWriter createXMLStreamWriter(
136: OutputStream stream, String encoding)
137: throws XMLStreamException;
138:
139: /**
140: * Allows the user to set specific features/properties on the underlying
141: * implementation.
142: *
143: * @param name the name of the property.
144: * @param value the value of the property.
145: * @throws IllegalArgumentException if the property is not supported.
146: */
147: public abstract void setProperty(String name, Object value)
148: throws IllegalArgumentException;
149:
150: /**
151: * Gets a feature/property on the underlying implementation.
152: *
153: * @param name the name of the property
154: * @return the value of the property
155: * @throws IllegalArgumentException if the property is not supported.
156: */
157: public abstract Object getProperty(String name)
158: throws IllegalArgumentException;
159:
160: /**
161: * Queries the set of properties that this factory supports.
162: *
163: * @param name the name of the property (may not be null).
164: * @return <code>true</code> if the property is supported;
165: * <code>false</code> otherwise.
166: */
167: public abstract boolean isPropertySupported(String name);
168:
169: /**
170: * This class represents the default implementation.
171: */
172: private static final class Default extends XMLOutputFactory {
173:
174: static final Class CLASS = new Default().getClass();
175:
176: // Property setting.
177: private Boolean _isRepairingNamespaces = new Boolean(false);
178:
179: // Property setting.
180: private String _repairingPrefix = "ns";
181:
182: // Property setting.
183: private Boolean _automaticEmptyElements = new Boolean(false);
184:
185: // Property setting.
186: private String _indentation;
187:
188: // Implements XMLOutputFactory abstract method.
189: public XMLStreamWriter createXMLStreamWriter(Writer writer)
190: throws XMLStreamException {
191: XMLStreamWriterImpl xmlWriter = newWriter();
192: xmlWriter.setOutput(writer);
193: return xmlWriter;
194: }
195:
196: // Implements XMLOutputFactory abstract method.
197: public XMLStreamWriter createXMLStreamWriter(OutputStream stream)
198: throws XMLStreamException {
199: XMLStreamWriterImpl xmlWriter = newWriter();
200: xmlWriter.setOutput(stream);
201: return xmlWriter;
202: }
203:
204: // Implements XMLOutputFactory abstract method.
205: public XMLStreamWriter createXMLStreamWriter(
206: OutputStream stream, String encoding)
207: throws XMLStreamException {
208: if ((encoding == null) || encoding.equals("UTF-8")
209: || encoding.equals("utf-8"))
210: return createXMLStreamWriter(stream);
211: XMLStreamWriterImpl xmlWriter = newWriter();
212: xmlWriter.setOutput(stream, encoding);
213: return xmlWriter;
214: }
215:
216: private XMLStreamWriterImpl newWriter() {
217: XMLStreamWriterImpl xmlWriter = (XMLStreamWriterImpl) XML_WRITER_FACTORY
218: .object();
219: xmlWriter._objectFactory = XML_WRITER_FACTORY;
220: xmlWriter.setRepairingNamespaces(_isRepairingNamespaces
221: .booleanValue());
222: xmlWriter.setRepairingPrefix(_repairingPrefix);
223: xmlWriter.setIndentation(_indentation);
224: xmlWriter.setAutomaticEmptyElements(_automaticEmptyElements
225: .booleanValue());
226: return xmlWriter;
227: }
228:
229: // Implements XMLOutputFactory abstract method.
230: public void setProperty(String name, Object value)
231: throws IllegalArgumentException {
232: if (name.equals(IS_REPAIRING_NAMESPACES)) {
233: _isRepairingNamespaces = (Boolean) value;
234: } else if (name.equals(REPAIRING_PREFIX)) {
235: _repairingPrefix = (String) value;
236: } else if (name.equals(AUTOMATIC_EMPTY_ELEMENTS)) {
237: _automaticEmptyElements = (Boolean) value;
238: } else if (name.equals(INDENTATION)) {
239: _indentation = (String) value;
240: } else {
241: throw new IllegalArgumentException("Property: " + name
242: + " not supported");
243: }
244: }
245:
246: // Implements XMLOutputFactory abstract method.
247: public Object getProperty(String name)
248: throws IllegalArgumentException {
249: if (name.equals(IS_REPAIRING_NAMESPACES)) {
250: return _isRepairingNamespaces;
251: } else if (name.equals(REPAIRING_PREFIX)) {
252: return _repairingPrefix;
253: } else if (name.equals(AUTOMATIC_EMPTY_ELEMENTS)) {
254: return _automaticEmptyElements;
255: } else if (name.equals(INDENTATION)) {
256: return _indentation;
257: } else {
258: throw new IllegalArgumentException("Property: " + name
259: + " not supported");
260: }
261: }
262:
263: // Implements XMLOutputFactory abstract method.
264: public boolean isPropertySupported(String name) {
265: return name.equals(IS_REPAIRING_NAMESPACES)
266: || name.equals(REPAIRING_PREFIX)
267: || name.equals(AUTOMATIC_EMPTY_ELEMENTS)
268: || name.equals(INDENTATION);
269: }
270:
271: }
272:
273: /**
274: * Holds a factory producing reusable writer instances.
275: */
276: private static final ObjectFactory XML_WRITER_FACTORY = new ObjectFactory() {
277:
278: protected Object create() {
279: return new XMLStreamWriterImpl();
280: }
281:
282: protected void cleanup(Object obj) {
283: ((XMLStreamWriterImpl) obj).reset();
284: }
285:
286: };
287:
288: // Allows instances of private classes to be factory produced.
289: static {
290: ObjectFactory.setInstance(new ObjectFactory() {
291: protected Object create() {
292: return new Default();
293: }
294: }, Default.CLASS);
295: }
296: }
|