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
18 package org.apache.commons.jxpath;
19
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Method;
22 import java.util.Collections;
23 import java.util.Set;
24
25 import org.apache.commons.jxpath.functions.ConstructorFunction;
26 import org.apache.commons.jxpath.functions.MethodFunction;
27 import org.apache.commons.jxpath.util.MethodLookupUtils;
28
29 /**
30 * Extension functions provided by a Java class.
31 *
32 * Let's say we declared a ClassFunction like this: <blockquote>
33 *
34 * <pre>
35 * new ClassFunctions(Integer.class, "int")
36 * </pre>
37 *
38 * </blockquote>
39 *
40 * We can now use XPaths like:
41 * <dl>
42 * <dt>{@code "int:new(3)"}</dt>
43 * <dd>Equivalent to {@code Integer.valueOf(3)}</dd>
44 * <dt>{@code "int:getInteger('foo')"}</dt>
45 * <dd>Equivalent to {@code Integer.getInteger("foo")}</dd>
46 * <dt>{@code "int:floatValue(int:new(4))"}</dt>
47 * <dd>Equivalent to {@code Integer.valueOf(4).floatValue()}</dd>
48 * </dl>
49 *
50 * <p>
51 * If the first argument of a method is {@link ExpressionContext}, the expression context in which the function is evaluated is passed to the method.
52 */
53 public class ClassFunctions implements Functions {
54
55 private static final Object[] EMPTY_ARRAY = {};
56 private final Class functionClass;
57 private final String namespace;
58
59 /**
60 * Constructs a new ClassFunctions.
61 *
62 * @param functionClass Class providing the functions
63 * @param namespace assigned ns
64 */
65 public ClassFunctions(final Class functionClass, final String namespace) {
66 this.functionClass = functionClass;
67 this.namespace = namespace;
68 }
69
70 /**
71 * Returns a {@link Function}, if any, for the specified namespace, name and parameter types.
72 *
73 * @param namespace if it is not the namespace specified in the constructor, the method returns null
74 * @param name is a function name or "new" for a constructor.
75 * @param parameters Object[] of parameters
76 * @return a MethodFunction, a ConstructorFunction or null if there is no such function.
77 */
78 @Override
79 public Function getFunction(final String namespace, final String name, Object[] parameters) {
80 if (namespace == null) {
81 if (this.namespace != null) {
82 return null;
83 }
84 } else if (!namespace.equals(this.namespace)) {
85 return null;
86 }
87 if (parameters == null) {
88 parameters = EMPTY_ARRAY;
89 }
90 if (name.equals("new")) {
91 final Constructor constructor = MethodLookupUtils.lookupConstructor(functionClass, parameters);
92 if (constructor != null) {
93 return new ConstructorFunction(constructor);
94 }
95 } else {
96 Method method = MethodLookupUtils.lookupStaticMethod(functionClass, name, parameters);
97 if (method != null) {
98 return new MethodFunction(method);
99 }
100 method = MethodLookupUtils.lookupMethod(functionClass, name, parameters);
101 if (method != null) {
102 return new MethodFunction(method);
103 }
104 }
105 return null;
106 }
107
108 /**
109 * Returns a set of one namespace - the one specified in the constructor.
110 *
111 * @return a singleton
112 */
113 @Override
114 public Set<String> getUsedNamespaces() {
115 return Collections.singleton(namespace);
116 }
117 }