001/* XPathFactory.java -- 
002   Copyright (C) 2004, 2005  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.xpath;
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.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 */
054public 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}