001    /* XMLEventFactory.java --
002       Copyright (C) 2005,2006,2009  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.util.Iterator;
047    import java.util.Properties;
048    import javax.xml.namespace.NamespaceContext;
049    import javax.xml.namespace.QName;
050    import javax.xml.stream.events.Attribute;
051    import javax.xml.stream.events.Characters;
052    import javax.xml.stream.events.Comment;
053    import javax.xml.stream.events.DTD;
054    import javax.xml.stream.events.EndDocument;
055    import javax.xml.stream.events.EndElement;
056    import javax.xml.stream.events.EntityDeclaration;
057    import javax.xml.stream.events.EntityReference;
058    import javax.xml.stream.events.Namespace;
059    import javax.xml.stream.events.ProcessingInstruction;
060    import javax.xml.stream.events.StartDocument;
061    import javax.xml.stream.events.StartElement;
062    
063    /**
064     * Factory for XML events.
065     */
066    public abstract class XMLEventFactory
067    {
068    
069      protected XMLEventFactory()
070      {
071      }
072    
073      /**
074       * Create a new factory instance.
075       * @see #newInstance(String,ClassLoader)
076       */
077      public static XMLEventFactory newInstance()
078        throws FactoryConfigurationError
079      {
080        return newInstance(null, null);
081      }
082    
083      /**
084       * Create a new factory instance.
085       * The implementation class to load is the first found in the following
086       * locations:
087       * <ol>
088       * <li>the <code>javax.xml.stream.XMLEventFactory</code> system
089       * property</li>
090       * <li>the above named property value in the
091       * <code><i>$JAVA_HOME</i>/lib/stax.properties</code> file</li>
092       * <li>the class name specified in the
093       * <code>META-INF/services/javax.xml.stream.XMLEventFactory</code>
094       * system resource</li>
095       * <li>the default factory class</li>
096       * </ol>
097       * @param factoryId name of the factory to find, same as a property name
098       * @param classLoader the class loader to use
099       * @return the factory implementation
100       * @exception FactoryConfigurationError if an instance of this factory
101       * cannot be loaded
102       */
103      public static XMLEventFactory newInstance(String factoryId,
104                                                ClassLoader classLoader)
105        throws FactoryConfigurationError
106      {
107        ClassLoader loader = classLoader;
108        if (loader == null)
109          {
110            loader = Thread.currentThread().getContextClassLoader();
111          }
112        if (loader == null)
113          {
114            loader = XMLEventFactory.class.getClassLoader();
115          }
116        String className = null;
117        int count = 0;
118        do
119          {
120            className = getFactoryClassName(loader, count++);
121            if (className != null)
122              {
123                try
124                  {
125                    Class<?> t = (loader != null) ? loader.loadClass(className) :
126                      Class.forName(className);
127                    return (XMLEventFactory) t.newInstance();
128                  }
129                catch (ClassNotFoundException e)
130                  {
131                    className = null;
132                  }
133                catch (Exception e)
134                  {
135                    throw new FactoryConfigurationError(e,
136                         "error instantiating class " + className);
137                  }
138              }
139          }
140        while (className == null && count < 3);
141        return new gnu.xml.stream.XMLEventFactoryImpl();
142      }
143    
144      private static String getFactoryClassName(ClassLoader loader, int attempt)
145      {
146        final String propertyName = "javax.xml.stream.XMLEventFactory";
147        switch (attempt)
148          {
149            case 0:
150              return System.getProperty(propertyName);
151            case 1:
152              try
153                {
154                  File file = new File(System.getProperty("java.home"));
155                  file = new File(file, "lib");
156                  file = new File(file, "stax.properties");
157                  InputStream in = new FileInputStream(file);
158                  Properties props = new Properties();
159                  props.load(in);
160                  in.close();
161                  return props.getProperty(propertyName);
162                }
163              catch (IOException e)
164                {
165                  return null;
166                }
167            case 2:
168              try
169                {
170                  String serviceKey = "/META-INF/services/" + propertyName;
171                  InputStream in = (loader != null) ?
172                     loader.getResourceAsStream(serviceKey) :
173                    XMLEventFactory.class.getResourceAsStream(serviceKey);
174                  if (in != null)
175                    {
176                      BufferedReader r =
177                         new BufferedReader(new InputStreamReader(in));
178                      String ret = r.readLine();
179                      r.close();
180                      return ret;
181                    }
182                }
183              catch (IOException e)
184                {
185                }
186              return null;
187            default:
188              return null;
189          }
190      }
191    
192      /**
193       * Sets the location for each event created by this factory.
194       */
195      public abstract void setLocation(Location location);
196    
197      /**
198       * Create an attribute event.
199       */
200      public abstract Attribute createAttribute(String prefix, String namespaceURI,
201                                                String localName, String value);
202    
203      /**
204       * Create an attribute event.
205       */
206      public abstract Attribute createAttribute(String localName, String value);
207    
208      /**
209       * Create an attribute event.
210       */
211      public abstract Attribute createAttribute(QName name, String value);
212    
213      /**
214       * Create a namespace declaration event.
215       */
216      public abstract Namespace createNamespace(String namespaceURI);
217    
218      /**
219       * Create a namespace declaration event.
220       */
221      public abstract Namespace createNamespace(String prefix, String namespaceUri);
222    
223      /**
224       * Create a start-element event.
225       */
226      @SuppressWarnings("unchecked")
227      public abstract StartElement createStartElement(QName name,
228                                                      Iterator attributes,
229                                                      Iterator namespaces);
230    
231      /**
232       * Create a start-element event.
233       */
234      public abstract StartElement createStartElement(String prefix,
235                                                      String namespaceUri,
236                                                      String localName);
237    
238      /**
239       * Create a start-element event.
240       */
241      @SuppressWarnings("unchecked")
242      public abstract StartElement createStartElement(String prefix,
243                                                      String namespaceUri,
244                                                      String localName,
245                                                      Iterator attributes,
246                                                      Iterator namespaces);
247    
248      /**
249       * Create a start-element event.
250       */
251      @SuppressWarnings("unchecked")
252      public abstract StartElement createStartElement(String prefix,
253                                                      String namespaceUri,
254                                                      String localName,
255                                                      Iterator attributes,
256                                                      Iterator namespaces,
257                                                      NamespaceContext context);
258    
259      /**
260       * Create an end-element event.
261       */
262      @SuppressWarnings("unchecked")
263      public abstract EndElement createEndElement(QName name,
264                                                  Iterator namespaces);
265    
266      /**
267       * Create an end-element event.
268       */
269      public abstract EndElement createEndElement(String prefix,
270                                                  String namespaceUri,
271                                                  String localName);
272    
273      /**
274       * Create an end-element event.
275       */
276      @SuppressWarnings("unchecked")
277      public abstract EndElement createEndElement(String prefix,
278                                                  String namespaceUri,
279                                                  String localName,
280                                                  Iterator namespaces);
281    
282      /**
283       * Create a text event.
284       */
285      public abstract Characters createCharacters(String content);
286    
287      /**
288       * Create a text event of type CDATA section.
289       */
290      public abstract Characters createCData(String content);
291    
292      /**
293       * Create a text event of type whitespace.
294       */
295      public abstract Characters createSpace(String content);
296    
297      /**
298       * Create a text event of type ignorable whitespace.
299       */
300      public abstract Characters createIgnorableSpace(String content);
301    
302      /**
303       * Create a start-document event.
304       */
305      public abstract StartDocument createStartDocument();
306    
307      /**
308       * Create a start-document event.
309       */
310      public abstract StartDocument createStartDocument(String encoding,
311                                                        String version,
312                                                        boolean standalone);
313    
314      /**
315       * Create a start-document event.
316       */
317      public abstract StartDocument createStartDocument(String encoding,
318                                                        String version);
319    
320      /**
321       * Create a start-document event.
322       */
323      public abstract StartDocument createStartDocument(String encoding);
324    
325      /**
326       * Create an end-document event.
327       */
328      public abstract EndDocument createEndDocument();
329    
330      /**
331       * Create an entity reference event.
332       */
333      public abstract EntityReference createEntityReference(String name,
334                                                            EntityDeclaration declaration);
335    
336      /**
337       * Create a comment event.
338       */
339      public abstract Comment createComment(String text);
340    
341      /**
342       * Create a processing instruction event.
343       */
344      public abstract ProcessingInstruction createProcessingInstruction(String target,
345                                                                        String data);
346    
347      /**
348       * Create a DOCTYPE declaration event.
349       */
350      public abstract DTD createDTD(String dtd);
351    
352    }