001    /* XMLInputFactory.java -- 
002       Copyright (C) 2005,2006  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    package javax.xml.stream;
039    
040    import java.io.BufferedReader;
041    import java.io.File;
042    import java.io.FileInputStream;
043    import java.io.InputStream;
044    import java.io.InputStreamReader;
045    import java.io.IOException;
046    import java.io.Reader;
047    import java.io.Writer;
048    import java.util.Properties;
049    import javax.xml.stream.util.XMLEventAllocator;
050    import javax.xml.transform.Source;
051    
052    /**
053     * Factory for creating stream and event readers from various kinds of input
054     * source.
055     * <h3>Parameters</h3>
056     * <table>
057     * <tr>
058     * <th>Name</th>
059     * <th>Description</th>
060     * <th>Type</th>
061     * <th>Default</th>
062     * <th>Required</th>
063     * </tr>
064     * <tr>
065     * <td>javax.xml.stream.isValidating</td>
066     * <td>Controls DTD validation</td>
067     * <td>Boolean</td>
068     * <td>Boolean.FALSE</td>
069     * <td>no</td>
070     * </tr>
071     * <tr>
072     * <td>javax.xml.stream.isNamespaceAware</td>
073     * <td>Controls namespace processing for XML 1.0</td>
074     * <td>Boolean</td>
075     * <td>Boolean.TRUE</td>
076     * <td>true is required, false is optional</td>
077     * </tr>
078     * <tr>
079     * <td>javax.xml.stream.isCoalescing</td>
080     * <td>Controls coalescing (normalization of adjacent character data)</td>
081     * <td>Boolean</td>
082     * <td>Boolean.FALSE</td>
083     * <td>yes</td>
084     * </tr>
085     * <tr>
086     * <td>javax.xml.stream.isReplacingEntityReferences</td>
087     * <td>Controls replacement of entity references with their replacement
088     * text</td>
089     * <td>Boolean</td>
090     * <td>Boolean.TRUE</td>
091     * <td>yes</td>
092     * </tr>
093     * <tr>
094     * <td>javax.xml.stream.isSupportingExternalEntities</td>
095     * <td>Controls whether to resolve external entities</td>
096     * <td>Boolean</td>
097     * <td>not specified</td>
098     * <td>yes</td>
099     * </tr>
100     * <tr>
101     * <td>javax.xml.stream.supportDTD</td>
102     * <td>Controls whether to support DTDs</td>
103     * <td>Boolean</td>
104     * <td>Boolean.TRUE</td>
105     * <td>yes</td>
106     * </tr>
107     * <tr>
108     * <td>javax.xml.stream.reporter</td>
109     * <td></td>
110     * <td>javax.xml.stream.XMLReporter</td>
111     * <td></td>
112     * <td>yes</td>
113     * </tr>
114     * <tr>
115     * <td>javax.xml.stream.resolver</td>
116     * <td></td>
117     * <td>javax.xml.stream.XMLResolver</td>
118     * <td></td>
119     * <td>yes</td>
120     * </tr>
121     * <tr>
122     * <td>javax.xml.stream.allocator</td>
123     * <td></td>
124     * <td>javax.xml.stream.util.XMLEventAllocator</td>
125     * <td></td>
126     * <td>yes</td>
127     * </tr>
128     * </table>
129     */
130    public abstract class XMLInputFactory
131    {
132    
133      /**
134       * Property used to control namespace support.
135       */
136      public static final String IS_NAMESPACE_AWARE = 
137        "javax.xml.stream.isNamespaceAware";
138    
139      /**
140       * Property used to control DTD validation.
141       */
142      public static final String IS_VALIDATING = "javax.xml.stream.isValidating";
143    
144      /**
145       * Property used to control whether to coalesce adjacent text events.
146       */
147      public static final String IS_COALESCING = "javax.xml.stream.isCoalescing";
148    
149      /**
150       * Property used to control whether to replace entity references with
151       * their replacement text.
152       */
153      public static final String IS_REPLACING_ENTITY_REFERENCES =
154        "javax.xml.stream.isReplacingEntityReferences";
155    
156      /**
157       * Property used to control whether to resolve external entities.
158       */
159      public static final String IS_SUPPORTING_EXTERNAL_ENTITIES =
160        "javax.xml.stream.isSupportingExternalEntities";
161    
162      /**
163       * Property used to indicate whether to support DTDs.
164       */
165      public static final String SUPPORT_DTD = "javax.xml.stream.supportDTD";
166    
167      /**
168       * Property used to control the error reporter implementation.
169       */
170      public static final String REPORTER = "javax.xml.stream.reporter";
171    
172      /**
173       * Property used to control the entity resolver implementation.
174       */
175      public static final String RESOLVER = "javax.xml.stream.resolver";
176    
177      /**
178       * Property used to control the event allocator implementation.
179       */
180      public static final String ALLOCATOR = "javax.xml.stream.allocator";
181    
182      protected XMLInputFactory()
183      {
184      }
185    
186      /**
187       * Creates a new factory instance.
188       * @see #newInstance(String,ClassLoader)
189       */
190      public static XMLInputFactory newInstance()
191        throws FactoryConfigurationError
192      {
193        return newInstance(null, null);
194      }
195    
196      /**
197       * Creates a new factory instance.
198       * The implementation class to load is the first found in the following
199       * locations:
200       * <ol>
201       * <li>the <code>javax.xml.stream.XMLInputFactory</code> system
202       * property</li>
203       * <li>the above named property value in the
204       * <code><i>$JAVA_HOME</i>/lib/stax.properties</code> file</li>
205       * <li>the class name specified in the
206       * <code>META-INF/services/javax.xml.stream.XMLInputFactory</code>
207       * system resource</li>
208       * <li>the default factory class</li>
209       * </ol>
210       */
211      public static XMLInputFactory newInstance(String factoryId,
212                                                ClassLoader classLoader)
213        throws FactoryConfigurationError
214      {
215        ClassLoader loader = classLoader;
216        if (loader == null)
217          {
218            loader = Thread.currentThread().getContextClassLoader();
219          }
220        if (loader == null)
221          {
222            loader = XMLInputFactory.class.getClassLoader();
223          }
224        String className = null;
225        int count = 0;
226        do
227          {
228            className = getFactoryClassName(loader, count++);
229            if (className != null)
230              {
231                try
232                  {
233                    Class t = (loader != null) ? loader.loadClass(className) :
234                      Class.forName(className);
235                    return (XMLInputFactory) t.newInstance();
236                  }
237                catch (ClassNotFoundException e)
238                  {
239                    className = null;
240                  }
241                catch (Exception e)
242                  {
243                    throw new FactoryConfigurationError(e,
244                         "error instantiating class " + className);
245                  }
246              }
247          }
248        while (className == null && count < 3);
249        return new gnu.xml.stream.XMLInputFactoryImpl();
250      }
251    
252      private static String getFactoryClassName(ClassLoader loader, int attempt)
253      {
254        final String propertyName = "javax.xml.stream.XMLInputFactory";
255        switch (attempt)
256          {
257            case 0:
258              return System.getProperty(propertyName);
259            case 1:
260              try
261                {
262                  File file = new File(System.getProperty("java.home"));
263                  file = new File(file, "lib");
264                  file = new File(file, "stax.properties");
265                  InputStream in = new FileInputStream(file);
266                  Properties props = new Properties();
267                  props.load(in);
268                  in.close();
269                  return props.getProperty(propertyName);
270                }
271              catch (IOException e)
272                {
273                  return null;
274                }
275            case 2:
276              try
277                {
278                  String serviceKey = "/META-INF/services/" + propertyName;
279                  InputStream in = (loader != null) ?
280                     loader.getResourceAsStream(serviceKey) :
281                    XMLInputFactory.class.getResourceAsStream(serviceKey);
282                  if (in != null)
283                    {
284                      BufferedReader r =
285                         new BufferedReader(new InputStreamReader(in));
286                      String ret = r.readLine();
287                      r.close();
288                      return ret;
289                    }
290                }
291              catch (IOException e)
292                {
293                }
294              return null;
295            default:
296              return null;
297          }
298      }
299    
300      /**
301       * Creates a new stream reader.
302       */
303      public abstract XMLStreamReader createXMLStreamReader(Reader reader)
304        throws XMLStreamException;
305    
306      /**
307       * Creates a new stream reader.
308       */
309      public abstract XMLStreamReader createXMLStreamReader(Source source)
310        throws XMLStreamException;
311    
312      /**
313       * Creates a new stream reader.
314       */
315      public abstract XMLStreamReader createXMLStreamReader(InputStream stream)
316        throws XMLStreamException;
317    
318      /**
319       * Creates a new stream reader.
320       */
321      public abstract XMLStreamReader createXMLStreamReader(InputStream stream,
322                                                            String encoding)
323        throws XMLStreamException;
324    
325      /**
326       * Creates a new stream reader.
327       */
328      public abstract XMLStreamReader createXMLStreamReader(String systemId,
329                                                            InputStream stream)
330        throws XMLStreamException;
331    
332      /**
333       * Creates a new stream reader.
334       */
335      public abstract XMLStreamReader createXMLStreamReader(String systemId,
336                                                            Reader reader)
337        throws XMLStreamException;
338    
339      /**
340       * Creates a new event reader.
341       */
342      public abstract XMLEventReader createXMLEventReader(Reader reader)
343        throws XMLStreamException;
344    
345      /**
346       * Creates a new event reader.
347       */
348      public abstract XMLEventReader createXMLEventReader(String systemId,
349                                                          Reader reader)
350        throws XMLStreamException;
351      
352      /**
353       * Creates a new event reader.
354       */
355      public abstract XMLEventReader createXMLEventReader(XMLStreamReader reader)
356        throws XMLStreamException;
357    
358      /**
359       * Creates a new event reader.
360       */
361      public abstract XMLEventReader createXMLEventReader(Source source)
362        throws XMLStreamException;
363    
364      /**
365       * Creates a new event reader.
366       */
367      public abstract XMLEventReader createXMLEventReader(InputStream stream)
368        throws XMLStreamException;
369    
370      /**
371       * Creates a new event reader.
372       */
373      public abstract XMLEventReader createXMLEventReader(InputStream stream,
374                                                          String encoding)
375        throws XMLStreamException;
376    
377      /**
378       * Creates a new event reader.
379       */
380      public abstract XMLEventReader createXMLEventReader(String systemId,
381                                                          InputStream stream)
382        throws XMLStreamException;
383    
384      /**
385       * Create a new filtered reader.
386       */
387      public abstract XMLStreamReader createFilteredReader(XMLStreamReader reader,
388                                                           StreamFilter filter)
389        throws XMLStreamException;
390    
391      /**
392       * Create a new filtered reader.
393       */
394      public abstract XMLEventReader createFilteredReader(XMLEventReader reader,
395                                                          EventFilter filter)
396        throws XMLStreamException;
397    
398      /**
399       * Returns the entity resolver.
400       */
401      public abstract XMLResolver getXMLResolver();
402    
403      /**
404       * Sets the entity resolver.
405       */
406      public abstract void setXMLResolver(XMLResolver resolver);
407    
408      /**
409       * Returns the error reporter.
410       */
411      public abstract XMLReporter getXMLReporter();
412    
413      /**
414       * Sets the error reporter.
415       */
416      public abstract void setXMLReporter(XMLReporter reporter);
417    
418      /**
419       * Sets the implementation-specific property of the given name.
420       * @exception IllegalArgumentException if the property is not supported
421       */
422      public abstract void setProperty(String name, Object value)
423        throws IllegalArgumentException;
424    
425      /**
426       * Returns the implementation-specific property of the given name.
427       * @exception IllegalArgumentException if the property is not supported
428       */
429      public abstract Object getProperty(String name)
430        throws IllegalArgumentException;
431    
432      /**
433       * Indicates whether the specified property is supported.
434       */
435      public abstract boolean isPropertySupported(String name);
436    
437      /**
438       * Sets the event allocator.
439       */
440      public abstract void setEventAllocator(XMLEventAllocator allocator);
441    
442      /**
443       * Returns the event allocator.
444       */
445      public abstract XMLEventAllocator getEventAllocator();
446    
447    }
448