001    /* DocumentBuilderFactory.java --
002       Copyright (C) 2004, 2005  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.parsers;
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.Properties;
047    import javax.xml.validation.Schema;
048    
049    /**
050     * Factory for obtaining document builders.
051     * Instances of this class are <em>not</em> guaranteed to be thread safe.
052     *
053     * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
054     */
055    public abstract class DocumentBuilderFactory
056    {
057    
058      private boolean namespaceAware;
059      private boolean validating;
060      private boolean ignoringElementContentWhitespace;
061      private boolean expandEntityReferences = true;
062      private boolean ignoringComments;
063      private boolean coalescing;
064      private Schema schema;
065      private boolean xIncludeAware;
066    
067      protected DocumentBuilderFactory()
068      {
069      }
070    
071      /**
072       * Creates a new factory instance.
073       * The implementation class to load is the first found in the following
074       * locations:
075       * <ol>
076       * <li>the <code>javax.xml.parsers.DocumentBuilderFactory</code> system
077       * property</li>
078       * <li>the above named property value in the
079       * <code><i>$JAVA_HOME</i>/lib/jaxp.properties</code> file</li>
080       * <li>the class name specified in the
081       * <code>META-INF/services/javax.xml.parsers.DocumentBuilderFactory</code>
082       * system resource</li>
083       * <li>the default factory class</li>
084       * </ol>
085       */
086      public static DocumentBuilderFactory newInstance()
087      {
088        ClassLoader loader = Thread.currentThread().getContextClassLoader();
089        if (loader == null)
090          {
091            loader = DocumentBuilderFactory.class.getClassLoader();
092          }
093        String className = null;
094        int count = 0;
095        do
096          {
097            className = getFactoryClassName(loader, count++);
098            if (className != null)
099              {
100                try
101                  {
102                    Class<?> t = (loader != null) ? loader.loadClass(className) :
103                      Class.forName(className);
104                    return (DocumentBuilderFactory) t.newInstance();
105                  }
106                catch (ClassNotFoundException e)
107                  {
108                    className = null;
109                  }
110                catch (Exception e)
111                  {
112                    throw new FactoryConfigurationError(e,
113                        "error instantiating class " + className);
114                  }
115              }
116          }
117        while (className == null && count < 3);
118        return new gnu.xml.dom.DomDocumentBuilderFactory();
119      }
120    
121      private static String getFactoryClassName(ClassLoader loader, int attempt)
122      {
123        final String propertyName = "javax.xml.parsers.DocumentBuilderFactory";
124        switch (attempt)
125          {
126            case 0:
127              return System.getProperty(propertyName);
128            case 1:
129              try
130                {
131                  File file = new File(System.getProperty("java.home"));
132                  file = new File(file, "lib");
133                  file = new File(file, "jaxp.properties");
134                  InputStream in = new FileInputStream(file);
135                  Properties props = new Properties();
136                  props.load(in);
137                  in.close();
138                  return props.getProperty(propertyName);
139                }
140              catch (IOException e)
141                {
142                  return null;
143                }
144            case 2:
145              try
146                {
147                  String serviceKey = "/META-INF/services/" + propertyName;
148                  InputStream in = (loader != null) ?
149                    loader.getResourceAsStream(serviceKey) :
150                    DocumentBuilderFactory.class.getResourceAsStream(serviceKey);
151                  if (in != null)
152                    {
153                      BufferedReader r =
154                        new BufferedReader(new InputStreamReader(in));
155                      String ret = r.readLine();
156                      r.close();
157                      return ret;
158                    }
159                }
160              catch (IOException e)
161                {
162                }
163              return null;
164            default:
165              return null;
166          }
167      }
168    
169      /**
170       * Creates a new document builder instance using the currently specified
171       * factory configuration.
172       * @exception ParserConfigurationException if the specified configuration
173       * is not supported
174       */
175      public abstract DocumentBuilder newDocumentBuilder()
176        throws ParserConfigurationException;
177    
178      /**
179       * Sets whether document builders obtained from this factory will be XML
180       * Namespace aware.
181       */
182      public void setNamespaceAware(boolean awareness)
183      {
184        namespaceAware = awareness;
185      }
186    
187      /**
188       * Sets whether document builders obtained from this factory will validate
189       * their input.
190       */
191      public void setValidating(boolean validating)
192      {
193        this.validating = validating;
194      }
195    
196      /**
197       * Sets whether document builders obtained from this factory will
198       * eliminate whitespace within elements that have an element-only content
199       * model.
200       */
201      public void setIgnoringElementContentWhitespace(boolean whitespace)
202      {
203        ignoringElementContentWhitespace = whitespace;
204      }
205    
206      /**
207       * Sets whether document builders obtained from this factory will expand
208       * entity reference nodes.
209       */
210      public void setExpandEntityReferences(boolean expandEntityRef)
211      {
212        expandEntityReferences = expandEntityRef;
213      }
214    
215      /**
216       * Sets whether document builders obtained from this factory will discard
217       * comment nodes.
218       */
219      public void setIgnoringComments(boolean ignoreComments)
220      {
221        ignoringComments = ignoreComments;
222      }
223    
224      /**
225       * Sets whether document builders obtained from this factory will convert
226       * CDATA sections to text nodes and normalize adjacent text nodes into a
227       * single text node.
228       */
229      public void setCoalescing(boolean coalescing)
230      {
231        this.coalescing = coalescing;
232      }
233    
234      /**
235       * Indicates whether document builders obtained from this factory will be
236       * XML Namespace aware.
237       */
238      public boolean isNamespaceAware()
239      {
240        return namespaceAware;
241      }
242    
243      /**
244       * Indicates whether document builders obtained from this factory will
245       * validate their input.
246       */
247      public boolean isValidating()
248      {
249        return validating;
250      }
251    
252      /**
253       * Indicates whether document builders obtained from this factory will
254       * eliminate whitespace within elements that have an element-only content
255       * model.
256       */
257      public boolean isIgnoringElementContentWhitespace()
258      {
259        return ignoringElementContentWhitespace;
260      }
261    
262      /**
263       * Indicates whether document builders obtained from this factory will
264       * expand entity reference nodes.
265       */
266      public boolean isExpandEntityReferences()
267      {
268        return expandEntityReferences;
269      }
270    
271      /**
272       * Indicates whether document builders obtained from this factory will
273       * discard comment nodes.
274       */
275      public boolean isIgnoringComments()
276      {
277        return ignoringComments;
278      }
279    
280      /**
281       * Indicates whether document builders obtained from this factory will
282       * convert CDATA sections to text nodes and normalize adjacent text nodes
283       * into a single text node.
284       */
285      public boolean isCoalescing()
286      {
287        return coalescing;
288      }
289    
290      /**
291       * Set the named attribute on the underlying implementation.
292       * @param name the name of the attribute
293       * @param value the new value
294       * @exception IllegalArgumentException if the attribute is not recognized
295       */
296      public abstract void setAttribute(String name, Object value)
297        throws IllegalArgumentException;
298    
299      /**
300       * Retrieves the named attribute value from the underlying implementation.
301       * @param name the name of the attribute
302       * @exception IllegalArgumentException if the attribute is not recognized
303       */
304      public abstract Object getAttribute(String name)
305        throws IllegalArgumentException;
306    
307      // -- JAXP 1.3 methods --
308    
309      /**
310       * Returns the schema.
311       * @see #setSchema
312       * @since 1.5
313       */
314      public Schema getSchema()
315      {
316        return schema;
317      }
318    
319      /**
320       * Sets the schema.
321       * @see #getSchema
322       * @since 1.5
323       */
324      public void setSchema(Schema schema)
325      {
326        this.schema = schema;
327      }
328    
329      /**
330       * Indicates whether parsers obtained from this factory will be XInclude
331       * aware.
332       * @since 1.5
333       */
334      public boolean isXIncludeAware()
335      {
336        return xIncludeAware;
337      }
338    
339      /**
340       * Sets whether parsers obtained from this factory will be XInclude aware.
341       * @since 1.5
342       */
343      public void setXIncludeAware(boolean state)
344      {
345        xIncludeAware = state;
346      }
347    
348      /**
349       * Sets the value of the specified feature.
350       * @param name the feature name (URI)
351       * @param value whether to enable the feature or not
352       * @exception ParserConfigurationException if the feature is not
353       * supported.
354       * @since 1.5
355       */
356      public abstract void setFeature(String name, boolean value)
357        throws ParserConfigurationException;
358    
359      /**
360       * Returns the value of the specified feature.
361       * @param name the feature name (URI)
362       * @exception ParserConfigurationException if the feature is not
363       * supported.
364       * @since 1.5
365       */
366      public abstract boolean getFeature(String name)
367        throws ParserConfigurationException;
368    
369    }