001/* XMLOutputFactory.java -- 
002   Copyright (C) 2005,2006  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038package javax.xml.stream;
039
040import java.io.BufferedReader;
041import java.io.File;
042import java.io.FileInputStream;
043import java.io.InputStream;
044import java.io.InputStreamReader;
045import java.io.IOException;
046import java.io.OutputStream;
047import java.io.Writer;
048import java.util.Properties;
049import javax.xml.transform.Result;
050
051/**
052 * Factory for obtaining XML stream and event writers for various kinds of
053 * output sink.
054 * <h3>Configuration</h3>
055 * <table>
056 * <tr>
057 * <th>Name</th>
058 * <th>Description</th>
059 * <th>Type</th>
060 * <th>Default</th>
061 * <th>Required</th>
062 * </tr>
063 * <tr>
064 * <td>javax.xml.stream.isRepairingNamespaces</td>
065 * <td>default namespace prefixes</td>
066 * <td>Boolean</td>
067 * <td>Boolean.FALSE</td>
068 * <td>yes</td>
069 * </tr>
070 * </table>
071 */
072public abstract class XMLOutputFactory
073{
074
075  /**
076   * Property used to control whether to default namespace prefixes.
077   * If true, the writer will create a namespace declaration for any
078   * attribute that doesn't have a namespace declaration in scope.
079   */
080  public static final java.lang.String IS_REPAIRING_NAMESPACES = 
081    "javax.xml.stream.isRepairingNamespaces";
082
083  protected XMLOutputFactory()
084  {
085  }
086
087  /**
088   * Creates a new <b>output</b> factory.
089   * The implementation class to load is the first found in the following
090   * locations:
091   * <ol>
092   * <li>the <code>javax.xml.stream.XMLOutputFactory</code> system
093   * property</li>
094   * <li>the above named property value in the
095   * <code><i>$JAVA_HOME</i>/lib/stax.properties</code> file</li>
096   * <li>the class name specified in the
097   * <code>META-INF/services/javax.xml.stream.XMLOutputFactory</code>
098   * system resource</li>
099   * <li>the default factory class</li>
100   * </ol>
101   */
102  public static XMLOutputFactory newInstance()
103    throws FactoryConfigurationError
104  {
105    ClassLoader loader = Thread.currentThread().getContextClassLoader();
106    if (loader == null)
107      {
108        loader = XMLOutputFactory.class.getClassLoader();
109      }
110    String className = null;
111    int count = 0;
112    do
113      {
114        className = getFactoryClassName(loader, count++);
115        if (className != null)
116          {
117            try
118              {
119                Class<?> t = (loader != null) ? loader.loadClass(className) :
120                  Class.forName(className);
121                return (XMLOutputFactory) t.newInstance();
122              }
123            catch (ClassNotFoundException e)
124              {
125                className = null;
126              }
127            catch (Exception e)
128              {
129                throw new FactoryConfigurationError(e,
130                     "error instantiating class " + className);
131              }
132          }
133      }
134    while (className == null && count < 3);
135    return new gnu.xml.stream.XMLOutputFactoryImpl();
136  }
137
138  private static String getFactoryClassName(ClassLoader loader, int attempt)
139  {
140    final String propertyName = "javax.xml.stream.XMLOutputFactory";
141    switch (attempt)
142      {
143        case 0:
144          return System.getProperty(propertyName);
145        case 1:
146          try
147            {
148              File file = new File(System.getProperty("java.home"));
149              file = new File(file, "lib");
150              file = new File(file, "stax.properties");
151              InputStream in = new FileInputStream(file);
152              Properties props = new Properties();
153              props.load(in);
154              in.close();
155              return props.getProperty(propertyName);
156            }
157          catch (IOException e)
158            {
159              return null;
160            }
161        case 2:
162          try
163            {
164              String serviceKey = "/META-INF/services/" + propertyName;
165              InputStream in = (loader != null) ?
166                 loader.getResourceAsStream(serviceKey) :
167                XMLOutputFactory.class.getResourceAsStream(serviceKey);
168              if (in != null)
169                {
170                  BufferedReader r =
171                     new BufferedReader(new InputStreamReader(in));
172                  String ret = r.readLine();
173                  r.close();
174                  return ret;
175                }
176            }
177          catch (IOException e)
178            {
179            }
180          return null;
181        default:
182          return null;
183      }
184  }
185
186  /**
187   * Creates a new <b>input</b> factory.
188   * This appears to be an API design bug.
189   * @see javax.xml.stream.XMLInputFactory.newInstance(String,ClassLoader)
190   */
191  public static XMLInputFactory newInstance(String factoryId,
192                                            ClassLoader classLoader)
193    throws FactoryConfigurationError
194  {
195    return XMLInputFactory.newInstance(factoryId, classLoader);
196  }
197
198  /**
199   * Creates a new stream writer.
200   */
201  public abstract XMLStreamWriter createXMLStreamWriter(Writer stream)
202    throws XMLStreamException;
203
204  /**
205   * Creates a new stream writer.
206   */
207  public abstract XMLStreamWriter createXMLStreamWriter(OutputStream stream)
208    throws XMLStreamException;
209
210  /**
211   * Creates a new stream writer.
212   */
213  public abstract XMLStreamWriter createXMLStreamWriter(OutputStream stream,
214                                                        String encoding)
215    throws XMLStreamException;
216
217  /**
218   * Creates a new stream writer.
219   * @exception UnsupportedOperationException if this method is not
220   * supported
221   */
222  public abstract XMLStreamWriter createXMLStreamWriter(Result result)
223    throws XMLStreamException;
224  
225  /**
226   * Creates a new event writer.
227   * @exception UnsupportedOperationException if this method is not
228   * supported
229   */
230  public abstract XMLEventWriter createXMLEventWriter(Result result)
231    throws XMLStreamException;
232
233  /**
234   * Creates a new event writer.
235   */
236  public abstract XMLEventWriter createXMLEventWriter(OutputStream stream)
237    throws XMLStreamException;
238
239  /**
240   * Creates a new event writer.
241   */
242  public abstract XMLEventWriter createXMLEventWriter(OutputStream stream,
243                                                      String encoding)
244    throws XMLStreamException;
245
246  /**
247   * Creates a new event writer.
248   */
249  public abstract XMLEventWriter createXMLEventWriter(Writer stream)
250    throws XMLStreamException;
251
252  /**
253   * Sets the implementation-specific property of the given name.
254   * @exception IllegalArgumentException if the property is not supported
255   */
256  public abstract void setProperty(String name, Object value)
257    throws IllegalArgumentException;
258
259  /**
260   * Returns the implementation-specific property of the given name.
261   * @exception IllegalArgumentException if the property is not supported
262   */
263  public abstract Object getProperty(String name)
264    throws IllegalArgumentException;
265
266  /**
267   * Indicates whether the specified property is supported.
268   */
269  public abstract boolean isPropertySupported(String name);
270
271}
272