KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > jxpath > PackageFunctions


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
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 package org.apache.commons.jxpath;
17
18 import java.lang.reflect.Constructor JavaDoc;
19 import java.lang.reflect.Method JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.Collections JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.Set JavaDoc;
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 import org.apache.commons.jxpath.util.TypeUtils;
29
30 /**
31  * Extension functions provided by Java classes. The class prefix specified
32  * in the constructor is used when a constructor or a static method is called.
33  * Usually, a class prefix is a package name (hence the name of this class).
34  *
35  * Let's say, we declared a PackageFunction like this:
36  * <blockquote><pre>
37  * new PackageFunctions("java.util.", "util")
38  * </pre></blockquote>
39  *
40  * We can now use XPaths like:
41  * <dl>
42  * <dt><code>"util:Date.new()"</code></dt>
43  * <dd>Equivalent to <code>new java.util.Date()</code></dd>
44  * <dt><code>"util:Collections.singleton('foo')"</code></dt>
45  * <dd>Equivalent to <code>java.util.Collections.singleton("foo")</code></dd>
46  * <dt><code>"util:substring('foo', 1, 2)"</code></dt>
47  * <dd>Equivalent to <code>"foo".substring(1, 2)</code>. Note that in
48  * this case, the class prefix is not used. JXPath does not check that
49  * the first parameter of the function (the method target) is in fact
50  * a member of the package described by this PackageFunctions object.</dd>
51  * </dl>
52  *
53  * <p>
54  * If the first argument of a method or constructor is ExpressionContext, the
55  * expression context in which the function is evaluated is passed to
56  * the method.
57  * </p>
58  * <p>
59  * There is one PackageFunctions object registered by default with each
60  * JXPathContext. It does not have a namespace and uses no class prefix.
61  * The existence of this object allows us to use XPaths like:
62  * <code>"java.util.Date.new()"</code> and <code>"length('foo')"</code>
63  * without the explicit registration of any extension functions.
64  * </p>
65
66  *
67  * @author Dmitri Plotnikov
68  * @version $Revision: 1.14 $ $Date: 2004/04/04 23:16:23 $
69  */

70 public class PackageFunctions implements Functions {
71     private String JavaDoc classPrefix;
72     private String JavaDoc namespace;
73     private static final Object JavaDoc[] EMPTY_ARRAY = new Object JavaDoc[0];
74
75     public PackageFunctions(String JavaDoc classPrefix, String JavaDoc namespace) {
76         this.classPrefix = classPrefix;
77         this.namespace = namespace;
78     }
79
80     /**
81      * Returns the namespace specified in the constructor
82      */

83     public Set JavaDoc getUsedNamespaces() {
84         return Collections.singleton(namespace);
85     }
86
87     /**
88      * Returns a Function, if any, for the specified namespace,
89      * name and parameter types.
90      * <p>
91      * @param namespace - if it is not the same as specified in the
92      * construction, this method returns null
93      * @param name - name of the method, which can one these forms:
94      * <ul>
95      * <li><b>methodname</b>, if invoking a method on an object passed as the
96      * first parameter</li>
97      * <li><b>Classname.new</b>, if looking for a constructor</li>
98      * <li><b>subpackage.subpackage.Classname.new</b>, if looking for a
99      * constructor in a subpackage</li>
100      * <li><b>Classname.methodname</b>, if looking for a static method</li>
101      * <li><b>subpackage.subpackage.Classname.methodname</b>, if looking for a
102      * static method of a class in a subpackage</li>
103      * </ul>
104      *
105      * @return a MethodFunction, a ConstructorFunction or null if no function
106      * is found
107      */

108     public Function getFunction(
109         String JavaDoc namespace,
110         String JavaDoc name,
111         Object JavaDoc[] parameters)
112     {
113         if ((namespace == null && this.namespace != null)
114             || (namespace != null && !namespace.equals(this.namespace))) {
115             return null;
116         }
117
118         if (parameters == null) {
119             parameters = EMPTY_ARRAY;
120         }
121
122         if (parameters.length >= 1) {
123             Object JavaDoc target = TypeUtils.convert(parameters[0], Object JavaDoc.class);
124             if (target != null) {
125                 Method JavaDoc method =
126                     MethodLookupUtils.lookupMethod(
127                         target.getClass(),
128                         name,
129                         parameters);
130                 if (method != null) {
131                     return new MethodFunction(method);
132                 }
133                     
134                 if (target instanceof NodeSet) {
135                     target = ((NodeSet) target).getPointers();
136                 }
137                 
138                 method =
139                     MethodLookupUtils.lookupMethod(
140                         target.getClass(),
141                         name,
142                         parameters);
143                 if (method != null) {
144                     return new MethodFunction(method);
145                 }
146                 
147                 if (target instanceof Collection JavaDoc) {
148                     Iterator JavaDoc iter = ((Collection JavaDoc) target).iterator();
149                     if (iter.hasNext()) {
150                         target = iter.next();
151                         if (target instanceof Pointer) {
152                             target = ((Pointer) target).getValue();
153                         }
154                     }
155                     else {
156                         target = null;
157                     }
158                 }
159             }
160             if (target != null) {
161                 Method JavaDoc method =
162                     MethodLookupUtils.lookupMethod(
163                         target.getClass(),
164                         name,
165                         parameters);
166                 if (method != null) {
167                     return new MethodFunction(method);
168                 }
169             }
170         }
171
172         String JavaDoc fullName = classPrefix + name;
173         int inx = fullName.lastIndexOf('.');
174         if (inx == -1) {
175             return null;
176         }
177
178         String JavaDoc className = fullName.substring(0, inx);
179         String JavaDoc methodName = fullName.substring(inx + 1);
180
181         Class JavaDoc functionClass;
182         try {
183             functionClass = Class.forName(className);
184         }
185         catch (ClassNotFoundException JavaDoc ex) {
186             throw new JXPathException(
187                 "Cannot invoke extension function "
188                     + (namespace != null ? namespace + ":" + name : name),
189                 ex);
190         }
191
192         if (methodName.equals("new")) {
193             Constructor JavaDoc constructor =
194                 MethodLookupUtils.lookupConstructor(functionClass, parameters);
195             if (constructor != null) {
196                 return new ConstructorFunction(constructor);
197             }
198         }
199         else {
200             Method JavaDoc method =
201                 MethodLookupUtils.lookupStaticMethod(
202                     functionClass,
203                     methodName,
204                     parameters);
205             if (method != null) {
206                 return new MethodFunction(method);
207             }
208         }
209         return null;
210     }
211 }
Popular Tags