001    /* XPathFactory.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.xpath;
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    
048    /**
049     * Factory for creating XPath environments.
050     *
051     * @author (a href='mailto:dog@gnu.org'>Chris Burdess</a)
052     * @since 1.3
053     */
054    public abstract class XPathFactory
055    {
056    
057      /**
058       * The default property name according to the JAXP specification.
059       */
060      public static final String DEFAULT_PROPERTY_NAME =
061                    "javax.xml.xpath.XPathFactory";
062    
063      /**
064       * The default object model URI.
065       */
066      public static final String DEFAULT_OBJECT_MODEL_URI =
067        XPathConstants.DOM_OBJECT_MODEL;
068    
069      protected XPathFactory()
070      {
071      }
072    
073      /**
074       * Returns a new factory for the default (DOM) object model.
075       */
076      public static final XPathFactory newInstance()
077      {
078        try
079          {
080            return newInstance(DEFAULT_OBJECT_MODEL_URI);
081          }
082        catch (XPathFactoryConfigurationException e)
083          {
084            throw new RuntimeException(e.getMessage());
085          }
086      }
087    
088      /**
089       * Returns a new factory for the given object model URI.
090       * The implementation class to load is the first found in the following
091       * locations that advertises support for the given model URI:
092       * <ol>
093       * <li>the <code>javax.xml.xpath.XPathFactory</code> system property</li>
094       * <li>the above named property value in the
095       * <code><i>$JAVA_HOME</i>/lib/jaxp.properties</code> file</li>
096       * <li>the class name specified in the
097       * <code>META-INF/services/javax.xml.xpath.XPathFactory</code> system
098       * resource</li>
099       * <li>the default factory class</li>
100       * </ol>
101       * @param uri the object model URI
102       */
103      public static final XPathFactory newInstance(String uri)
104        throws XPathFactoryConfigurationException
105      {
106        ClassLoader loader = Thread.currentThread().getContextClassLoader();
107        if (loader == null)
108          {
109            loader = XPathFactory.class.getClassLoader();
110          }
111        String className = null;
112        int count = 0;
113        do
114          {
115            className = getFactoryClassName(loader, count++);
116            if (className != null)
117              {
118                try
119                  {
120                    Class<?> t = (loader != null) ? loader.loadClass(className) :
121                      Class.forName(className);
122                    XPathFactory ret = (XPathFactory) t.newInstance();
123                    if (ret.isObjectModelSupported(uri))
124                      {
125                        return ret;
126                      }
127                    className = null;
128                  }
129                catch (ClassNotFoundException e)
130                  {
131                    className = null;
132                  }
133                catch (Exception e)
134                  {
135                    throw new XPathFactoryConfigurationException(e);
136                  }
137              }
138          }
139        while (className == null && count < 4);
140        String msg = "no factories with support for " + uri;
141        throw new XPathFactoryConfigurationException(msg);
142      }
143    
144      private static String getFactoryClassName(ClassLoader loader, int attempt)
145      {
146        final String propertyName = DEFAULT_PROPERTY_NAME;
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, "jaxp.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                    XPathFactory.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            case 3:
188              return "gnu.xml.xpath.XPathFactoryImpl";
189            default:
190              return null;
191          }
192      }
193    
194      /**
195       * Indicates whether the specified object model URI is supported by
196       * this factory.
197       */
198      public abstract boolean isObjectModelSupported(String objectModel);
199    
200      /**
201       * Sets the state of the named feature.
202       */
203      public abstract void setFeature(String name, boolean value)
204        throws XPathFactoryConfigurationException;
205    
206      /**
207       * Returns the state of the named feature.
208       */
209      public abstract boolean getFeature(String name)
210        throws XPathFactoryConfigurationException;
211    
212      /**
213       * Sets the XPath variable resolver calback.
214       */
215      public abstract void setXPathVariableResolver(XPathVariableResolver resolver);
216    
217      /**
218       * Sets the XPath extension function resolver calback.
219       */
220      public abstract void setXPathFunctionResolver(XPathFunctionResolver resolver);
221    
222      /**
223       * Returns a new XPath evaluation environment.
224       */
225      public abstract XPath newXPath();
226    
227    }