View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jxpath;
18  
19  import java.lang.reflect.Constructor;
20  import java.lang.reflect.Method;
21  import java.util.Collections;
22  import java.util.Set;
23  
24  import org.apache.commons.jxpath.functions.ConstructorFunction;
25  import org.apache.commons.jxpath.functions.MethodFunction;
26  import org.apache.commons.jxpath.util.MethodLookupUtils;
27  
28  /**
29   * Extension functions provided by a Java class.
30   *
31   * Let's say we declared a ClassFunction like this:
32   * <blockquote><pre>
33   *     new ClassFunctions(Integer.class, "int")
34   * </pre></blockquote>
35   *
36   * We can now use XPaths like:
37   * <dl>
38   *  <dt><code>"int:new(3)"</code></dt>
39   *  <dd>Equivalent to <code>new Integer(3)</code></dd>
40   *  <dt><code>"int:getInteger('foo')"</code></dt>
41   *  <dd>Equivalent to <code>Integer.getInteger("foo")</code></dd>
42   *  <dt><code>"int:floatValue(int:new(4))"</code></dt>
43   *  <dd>Equivalent to <code>new Integer(4).floatValue()</code></dd>
44   * </dl>
45   *
46   * <p>
47   * If the first argument of a method is {@link ExpressionContext}, the
48   * expression context in which the function is evaluated is passed to
49   * the method.
50   *
51   * @author Dmitri Plotnikov
52   * @version $Revision: 652845 $ $Date: 2008-05-02 19:46:46 +0200 (Fr, 02 Mai 2008) $
53   */
54  public class ClassFunctions implements Functions {
55      private static final Object[] EMPTY_ARRAY = new Object[0];
56  
57      private Class functionClass;
58      private String namespace;
59  
60      /**
61       * Create a new ClassFunctions.
62       * @param functionClass Class providing the functions
63       * @param namespace assigned ns
64       */
65      public ClassFunctions(Class functionClass, String namespace) {
66          this.functionClass = functionClass;
67          this.namespace = namespace;
68      }
69  
70      /**
71       * Returns a set of one namespace - the one specified in the constructor.
72       *
73       * @return a singleton
74       */
75      public Set getUsedNamespaces() {
76          return Collections.singleton(namespace);
77      }
78  
79      /**
80       * Returns a {@link Function}, if any, for the specified namespace,
81       * name and parameter types.
82       *
83       * @param namespace if it is not the namespace specified in the constructor,
84       *     the method returns null
85       * @param name is a function name or "new" for a constructor.
86       * @param parameters Object[] of parameters
87       *
88       * @return a MethodFunction, a ConstructorFunction or null if there is no
89       *      such function.
90       */
91      public Function getFunction(
92          String namespace,
93          String name,
94          Object[] parameters) {
95          if (namespace == null) {
96              if (this.namespace != null) {
97                  return null;
98              }
99          }
100         else if (!namespace.equals(this.namespace)) {
101             return null;
102         }
103 
104         if (parameters == null) {
105             parameters = EMPTY_ARRAY;
106         }
107 
108         if (name.equals("new")) {
109             Constructor constructor =
110                 MethodLookupUtils.lookupConstructor(functionClass, parameters);
111             if (constructor != null) {
112                 return new ConstructorFunction(constructor);
113             }
114         }
115         else {
116             Method method = MethodLookupUtils.
117                 lookupStaticMethod(functionClass, name, parameters);
118             if (method != null) {
119                 return new MethodFunction(method);
120             }
121 
122             method = MethodLookupUtils.
123                 lookupMethod(functionClass, name, parameters);
124             if (method != null) {
125                 return new MethodFunction(method);
126             }
127         }
128 
129         return null;
130     }
131 }