1/*
2 * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.xml.stream;
27
28import com.sun.xml.internal.stream.XMLOutputFactoryImpl;
29import javax.xml.transform.Result;
30
31/**
32 * Defines an abstract implementation of a factory for
33 * getting XMLEventWriters and XMLStreamWriters.
34 *
35 * The following table defines the standard properties of this specification.
36 * Each property varies in the level of support required by each implementation.
37 * The level of support required is described in the 'Required' column.
38 *
39 *     <table class="striped">
40 *     <caption>Configuration Parameters</caption>
41 *     <thead>
42 *      <tr>
43 *        <th>Property Name</th>
44 *        <th>Behavior</th>
45 *        <th>Return type</th>
46 *        <th>Default Value</th>
47 *        <th>Required</th>
48 *              </tr>
49 *    </thead>
50 *    <tbody>
51 *         <tr><td>javax.xml.stream.isRepairingNamespaces</td><td>defaults prefixes
52 *                 on the output side</td><td>Boolean</td><td>False</td><td>Yes</td></tr>
53 *      </tbody>
54 *   </table>
55 *
56 * <p>The following paragraphs describe the namespace and prefix repair algorithm:
57 *
58 * <p>The property can be set with the following code line:
59 * {@code setProperty("javax.xml.stream.isRepairingNamespaces", new Boolean(true|false));}
60 *
61 * <p>This property specifies that the writer default namespace prefix declarations.
62 * The default value is false.
63 *
64 * <p>If a writer isRepairingNamespaces it will create a namespace declaration
65 * on the current StartElement for
66 * any attribute that does not
67 * currently have a namespace declaration in scope.  If the StartElement
68 * has a uri but no prefix specified a prefix will be assigned, if the prefix
69 * has not been declared in a parent of the current StartElement it will be declared
70 * on the current StartElement.  If the defaultNamespace is bound and in scope
71 * and the default namespace matches the URI of the attribute or StartElement
72 * QName no prefix will be assigned.
73 *
74 * <p>If an element or attribute name has a prefix, but is not
75 * bound to any namespace URI, then the prefix will be removed
76 * during serialization.
77 *
78 * <p>If element and/or attribute names in the same start or
79 * empty-element tag are bound to different namespace URIs and
80 * are using the same prefix then the element or the first
81 * occurring attribute retains the original prefix and the
82 * following attributes have their prefixes replaced with a
83 * new prefix that is bound to the namespace URIs of those
84 * attributes.
85 *
86 * <p>If an element or attribute name uses a prefix that is
87 * bound to a different URI than that inherited from the
88 * namespace context of the parent of that element and there
89 * is no namespace declaration in the context of the current
90 * element then such a namespace declaration is added.
91 *
92 * <p>If an element or attribute name is bound to a prefix and
93 * there is a namespace declaration that binds that prefix
94 * to a different URI then that namespace declaration is
95 * either removed if the correct mapping is inherited from
96 * the parent context of that element, or changed to the
97 * namespace URI of the element or attribute using that prefix.
98 *
99 * @version 1.2
100 * @author Copyright (c) 2009, 2015 by Oracle Corporation. All Rights Reserved.
101 * @see XMLInputFactory
102 * @see XMLEventWriter
103 * @see XMLStreamWriter
104 * @since 1.6
105 */
106public abstract class XMLOutputFactory {
107  /**
108   * Property used to set prefix defaulting on the output side
109   */
110  public static final String IS_REPAIRING_NAMESPACES=
111    "javax.xml.stream.isRepairingNamespaces";
112
113  static final String DEFAULIMPL = "com.sun.xml.internal.stream.XMLOutputFactoryImpl";
114
115  protected XMLOutputFactory(){}
116
117   /**
118   * Creates a new instance of the {@code XMLOutputFactory} builtin
119   * system-default implementation.
120   *
121   * @return A new instance of the {@code XMLOutputFactory} builtin
122   *         system-default implementation.
123   *
124   * @since 9
125   */
126  public static XMLOutputFactory newDefaultFactory() {
127      return new XMLOutputFactoryImpl();
128  }
129
130  /**
131   * Creates a new instance of the factory in exactly the same manner as the
132   * {@link #newFactory()} method.
133   * @throws FactoryConfigurationError if an instance of this factory cannot be loaded
134   */
135  public static XMLOutputFactory newInstance()
136    throws FactoryConfigurationError
137  {
138    return FactoryFinder.find(XMLOutputFactory.class, DEFAULIMPL);
139  }
140
141  /**
142   * Create a new instance of the factory.
143   * <p>
144   * This static method creates a new factory instance. This method uses the
145   * following ordered lookup procedure to determine the XMLOutputFactory
146   * implementation class to load:
147   * <ul>
148   * <li>
149   *   Use the javax.xml.stream.XMLOutputFactory system property.
150   * </li>
151   * <li>
152   *   <p>
153   *   Use the configuration file "stax.properties". The file is in standard
154   *   {@link java.util.Properties} format and typically located in the
155   *   {@code conf} directory of the Java installation. It contains the fully qualified
156   *   name of the implementation class with the key being the system property
157   *   defined above.
158   *
159   *   <p>
160   *   The stax.properties file is read only once by the implementation
161   *   and its values are then cached for future use.  If the file does not exist
162   *   when the first attempt is made to read from it, no further attempts are
163   *   made to check for its existence.  It is not possible to change the value
164   *   of any property in stax.properties after it has been read for the first time.
165   *
166   *   <p>
167   *   Use the jaxp configuration file "jaxp.properties". The file is in the same
168   *   format as stax.properties and will only be read if stax.properties does
169   *   not exist.
170   * </li>
171   * <li>
172   *   <p>
173   *   Use the service-provider loading facility, defined by the
174   *   {@link java.util.ServiceLoader} class, to attempt to locate and load an
175   *   implementation of the service using the {@linkplain
176   *   java.util.ServiceLoader#load(java.lang.Class) default loading mechanism}:
177   *   the service-provider loading facility will use the {@linkplain
178   *   java.lang.Thread#getContextClassLoader() current thread's context class loader}
179   *   to attempt to load the service. If the context class
180   *   loader is null, the {@linkplain
181   *   ClassLoader#getSystemClassLoader() system class loader} will be used.
182   * </li>
183   * <li>
184   *   <p>
185   *   Otherwise, the {@linkplain #newDefaultFactory() system-default}
186   *   implementation is returned.
187   * </li>
188   * </ul>
189   * <p>
190   * Once an application has obtained a reference to a XMLOutputFactory it
191   * can use the factory to configure and obtain stream instances.
192   * <p>
193   * Note that this is a new method that replaces the deprecated newInstance() method.
194   *   No changes in behavior are defined by this replacement method relative to the
195   *   deprecated method.
196   *
197   * @throws FactoryConfigurationError in case of {@linkplain
198   *   java.util.ServiceConfigurationError service configuration error} or if
199   *   the implementation is not available or cannot be instantiated.
200   */
201  public static XMLOutputFactory newFactory()
202    throws FactoryConfigurationError
203  {
204    return FactoryFinder.find(XMLOutputFactory.class, DEFAULIMPL);
205  }
206
207  /**
208   * Create a new instance of the factory.
209   *
210   * @param factoryId             Name of the factory to find, same as
211   *                              a property name
212   * @param classLoader           classLoader to use
213   * @return the factory implementation
214   * @throws FactoryConfigurationError if an instance of this factory cannot be loaded
215   *
216   * @deprecated  This method has been deprecated because it returns an
217   *              instance of XMLInputFactory, which is of the wrong class.
218   *              Use the new method {@link #newFactory(java.lang.String,
219   *              java.lang.ClassLoader)} instead.
220   */
221  @Deprecated(since="1.7")
222  public static XMLInputFactory newInstance(String factoryId,
223          ClassLoader classLoader)
224          throws FactoryConfigurationError {
225      //do not fallback if given classloader can't find the class, throw exception
226      return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null);
227  }
228
229  /**
230   * Create a new instance of the factory.
231   * If the classLoader argument is null, then the ContextClassLoader is used.
232   * <p>
233   * This method uses the following ordered lookup procedure to determine
234   * the XMLOutputFactory implementation class to load:
235   * <ul>
236   * <li>
237   *   Use the value of the system property identified by {@code factoryId}.
238   * </li>
239   * <li>
240   *   <p>
241   *   Use the configuration file "stax.properties". The file is in standard
242   *   {@link java.util.Properties} format and typically located in the
243   *   {@code conf} directory of the Java installation. It contains the fully qualified
244   *   name of the implementation class with the key being the system property
245   *   defined above.
246   *
247   *   <p>
248   *   The stax.properties file is read only once by the implementation
249   *   and its values are then cached for future use.  If the file does not exist
250   *   when the first attempt is made to read from it, no further attempts are
251   *   made to check for its existence.  It is not possible to change the value
252   *   of any property in stax.properties after it has been read for the first time.
253   *
254   *   <p>
255   *   Use the jaxp configuration file "jaxp.properties". The file is in the same
256   *   format as stax.properties and will only be read if stax.properties does
257   *   not exist.
258   * </li>
259   * <li>
260   *   <p>
261   *   If {@code factoryId} is "javax.xml.stream.XMLOutputFactory",
262   *   use the service-provider loading facility, defined by the
263   *   {@link java.util.ServiceLoader} class, to attempt to {@linkplain
264   *   java.util.ServiceLoader#load(java.lang.Class, java.lang.ClassLoader) locate and load}
265   *   an implementation of the service using the specified {@code ClassLoader}.
266   *   If {@code classLoader} is null, the {@linkplain
267   *   java.util.ServiceLoader#load(java.lang.Class) default loading mechanism} will apply:
268   *   That is, the service-provider loading facility will use the {@linkplain
269   *   java.lang.Thread#getContextClassLoader() current thread's context class loader}
270   *   to attempt to load the service. If the context class
271   *   loader is null, the {@linkplain
272   *   ClassLoader#getSystemClassLoader() system class loader} will be used.
273   * </li>
274   * <li>
275   *   <p>
276   *   Otherwise, throws a {@link FactoryConfigurationError}.
277   * </li>
278   * </ul>
279   *
280   * @apiNote The parameter factoryId defined here is inconsistent with that
281   * of other JAXP factories where the first parameter is fully qualified
282   * factory class name that provides implementation of the factory.
283   *
284   * <p>
285   *   Note that this is a new method that replaces the deprecated
286   *   {@link #newInstance(java.lang.String, java.lang.ClassLoader)
287   *   newInstance(String factoryId, ClassLoader classLoader)} method.
288   *   The original method was incorrectly defined to return XMLInputFactory.
289   *
290   *
291   * @param factoryId             Name of the factory to find, same as
292   *                              a property name
293   * @param classLoader           classLoader to use
294   * @return the factory implementation
295   * @throws FactoryConfigurationError in case of {@linkplain
296   *   java.util.ServiceConfigurationError service configuration error} or if
297   *   the implementation is not available or cannot be instantiated.
298   */
299  public static XMLOutputFactory newFactory(String factoryId,
300          ClassLoader classLoader)
301          throws FactoryConfigurationError {
302      //do not fallback if given classloader can't find the class, throw exception
303      return FactoryFinder.find(XMLOutputFactory.class, factoryId, classLoader, null);
304  }
305
306  /**
307   * Create a new XMLStreamWriter that writes to a writer
308   * @param stream the writer to write to
309   * @throws XMLStreamException
310   */
311  public abstract XMLStreamWriter createXMLStreamWriter(java.io.Writer stream) throws XMLStreamException;
312
313  /**
314   * Create a new XMLStreamWriter that writes to a stream
315   * @param stream the stream to write to
316   * @throws XMLStreamException
317   */
318  public abstract XMLStreamWriter createXMLStreamWriter(java.io.OutputStream stream) throws XMLStreamException;
319
320  /**
321   * Create a new XMLStreamWriter that writes to a stream
322   * @param stream the stream to write to
323   * @param encoding the encoding to use
324   * @throws XMLStreamException
325   */
326  public abstract XMLStreamWriter createXMLStreamWriter(java.io.OutputStream stream,
327                                         String encoding) throws XMLStreamException;
328
329  /**
330   * Create a new XMLStreamWriter that writes to a JAXP result.  This method is optional.
331   * @param result the result to write to
332   * @throws UnsupportedOperationException if this method is not
333   * supported by this XMLOutputFactory
334   * @throws XMLStreamException
335   */
336  public abstract XMLStreamWriter createXMLStreamWriter(Result result) throws XMLStreamException;
337
338
339  /**
340   * Create a new XMLEventWriter that writes to a JAXP result.  This method is optional.
341   * @param result the result to write to
342   * @throws UnsupportedOperationException if this method is not
343   * supported by this XMLOutputFactory
344   * @throws XMLStreamException
345   */
346  public abstract XMLEventWriter createXMLEventWriter(Result result) throws XMLStreamException;
347
348  /**
349   * Create a new XMLEventWriter that writes to a stream
350   * @param stream the stream to write to
351   * @throws XMLStreamException
352   */
353  public abstract XMLEventWriter createXMLEventWriter(java.io.OutputStream stream) throws XMLStreamException;
354
355
356
357  /**
358   * Create a new XMLEventWriter that writes to a stream
359   * @param stream the stream to write to
360   * @param encoding the encoding to use
361   * @throws XMLStreamException
362   */
363  public abstract XMLEventWriter createXMLEventWriter(java.io.OutputStream stream,
364                                                     String encoding) throws XMLStreamException;
365
366  /**
367   * Create a new XMLEventWriter that writes to a writer
368   * @param stream the stream to write to
369   * @throws XMLStreamException
370   */
371  public abstract XMLEventWriter createXMLEventWriter(java.io.Writer stream) throws XMLStreamException;
372
373  /**
374   * Allows the user to set specific features/properties on the underlying implementation.
375   * @param name The name of the property
376   * @param value The value of the property
377   * @throws java.lang.IllegalArgumentException if the property is not supported
378   */
379  public abstract void setProperty(java.lang.String name,
380                                    Object value)
381    throws IllegalArgumentException;
382
383  /**
384   * Get a feature/property on the underlying implementation
385   * @param name The name of the property
386   * @return The value of the property
387   * @throws java.lang.IllegalArgumentException if the property is not supported
388   */
389  public abstract Object getProperty(java.lang.String name)
390    throws IllegalArgumentException;
391
392  /**
393   * Query the set of properties that this factory supports.
394   *
395   * @param name The name of the property (may not be null)
396   * @return true if the property is supported and false otherwise
397   */
398  public abstract boolean isPropertySupported(String name);
399}
400