View Javadoc

1   /*
2    * Copyright 2006 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.xml.xpath;
18  
19  import java.util.Collections;
20  import java.util.Map;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  import org.springframework.util.Assert;
26  import org.springframework.util.ClassUtils;
27  import org.springframework.xml.JaxpVersion;
28  
29  /**
30   * Factory for compiled <code>XPathExpression</code>s, being aware of JAXP 1.3+ XPath functionality, and Jaxen. Mainly
31   * for internal use of the framework.
32   * <p/>
33   * The goal of this class is to avoid runtime dependencies a specific XPath engine, simply using the best XPath
34   * implementation that is available. Prefers JAXP 1.3+ XPath implementations to Jaxen.
35   *
36   * @author Arjen Poutsma
37   * @see XPathExpression
38   * @since 1.0.0
39   */
40  public abstract class XPathExpressionFactory {
41  
42      private static final Log logger = LogFactory.getLog(XPathExpressionFactory.class);
43  
44      private static final String JAXEN_CLASS_NAME = "org.jaxen.XPath";
45  
46      private static boolean jaxp13Available;
47  
48      private static boolean jaxenAvailable;
49  
50      static {
51          // Check whether JAXP 1.3 is available
52          jaxp13Available = JaxpVersion.isAtLeastJaxp13();
53  
54          // Check whether Jaxen is available
55          try {
56              ClassUtils.forName(JAXEN_CLASS_NAME);
57              jaxenAvailable = true;
58          }
59          catch (ClassNotFoundException ex) {
60              jaxenAvailable = false;
61          }
62      }
63  
64      /**
65       * Create a compiled XPath expression using the given string.
66       *
67       * @param expression the XPath expression
68       * @return the compiled XPath expression
69       * @throws IllegalStateException if neither JAXP 1.3+, or Jaxen are available
70       * @throws XPathParseException   if the given expression cannot be parsed
71       */
72      public static XPathExpression createXPathExpression(String expression)
73              throws IllegalStateException, XPathParseException {
74          return createXPathExpression(expression, Collections.EMPTY_MAP);
75      }
76  
77      /**
78       * Create a compiled XPath expression using the given string and namespaces. The namespace map should consist of
79       * string prefixes mapped to string namespaces.
80       *
81       * @param expression the XPath expression
82       * @param namespaces a map that binds string prefixes to string namespaces
83       * @return the compiled XPath expression
84       * @throws IllegalStateException if neither JAXP 1.3+, or Jaxen are available
85       * @throws XPathParseException   if the given expression cannot be parsed
86       */
87      public static XPathExpression createXPathExpression(String expression, Map namespaces)
88              throws IllegalStateException, XPathParseException {
89          Assert.hasLength(expression, "expression is empty");
90          if (jaxp13Available) {
91              try {
92                  logger.trace("Creating [javax.xml.xpath.XPathExpression]");
93                  return Jaxp13XPathExpressionFactory.createXPathExpression(expression, namespaces);
94              }
95              catch (XPathException e) {
96                  throw e;
97              }
98              catch (Throwable e) {
99                  jaxp13Available = false;
100             }
101         }
102         if (jaxenAvailable) {
103             logger.trace("Creating [org.jaxen.XPath]");
104             return JaxenXPathExpressionFactory.createXPathExpression(expression, namespaces);
105         }
106         throw new IllegalStateException(
107                 "Could not create XPathExpression: could not locate JAXP 1.3, or Jaxen on the class path");
108     }
109 
110 
111 }