/**
* Copyright 2011 meltmedia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xchain.framework.jxpath;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import org.apache.commons.jxpath.functions.ConstructorFunction;
import org.apache.commons.jxpath.functions.MethodFunction;
import org.xchain.framework.jxpath.MethodLookupUtils;
import org.apache.commons.jxpath.util.TypeUtils;
import org.apache.commons.jxpath.Function;
import org.apache.commons.jxpath.JXPathException;
import org.apache.commons.jxpath.NodeSet;
import org.apache.commons.jxpath.PackageFunctions;
import org.apache.commons.jxpath.Pointer;
/**
* Almost an exact copy of <code>org.apache.commons.jxpath.PackageFunctions</code> implementation
* written by Dimitri Plotnikov. This implementation is Adjusted to use a different method lookup
* utility class that better handles inheritance oddities introduced in Java 1.5 when inheriting
* from a generic type.
*
* @author Dimitri Plotnikov
* @author John Trimble
*/
public class GenericsWisePackageFunctions extends PackageFunctions {
private static final Object[] EMPTY_ARRAY = new Object[0];
private String namespace;
private String classPrefix;
public GenericsWisePackageFunctions(String classPrefix, String namespace) {
super(classPrefix, namespace);
this.namespace = namespace;
this.classPrefix = classPrefix;
}
public Set getUsedNamespaces() {
return Collections.singleton(namespace);
}
public Function getFunction(
String namespace,
String name,
Object[] parameters) {
if ((namespace == null && this.namespace != null) //NOPMD
|| (namespace != null && !namespace.equals(this.namespace))) {
return null;
}
if (parameters == null) {
parameters = EMPTY_ARRAY;
}
if (parameters.length >= 1) {
Object target = TypeUtils.convert(parameters[0], Object.class);
if (target != null) {
Method method =
MethodLookupUtils.lookupMethod(
target.getClass(),
name,
parameters);
if (method != null) {
return new MethodFunction(method);
}
if (target instanceof NodeSet) {
target = ((NodeSet) target).getPointers();
}
method =
MethodLookupUtils.lookupMethod(
target.getClass(),
name,
parameters);
if (method != null) {
return new MethodFunction(method);
}
if (target instanceof Collection) {
Iterator iter = ((Collection) target).iterator();
if (iter.hasNext()) {
target = iter.next();
if (target instanceof Pointer) {
target = ((Pointer) target).getValue();
}
}
else {
target = null;
}
}
}
if (target != null) {
Method method =
MethodLookupUtils.lookupMethod(
target.getClass(),
name,
parameters);
if (method != null) {
return new MethodFunction(method);
}
}
}
String fullName = classPrefix + name;
int inx = fullName.lastIndexOf('.');
if (inx == -1) {
return null;
}
String className = fullName.substring(0, inx);
String methodName = fullName.substring(inx + 1);
Class functionClass;
try {
functionClass = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
}
catch (ClassNotFoundException ex) {
throw new JXPathException(
"Cannot invoke extension function "
+ (namespace != null ? namespace + ":" + name : name),
ex);
}
if (methodName.equals("new")) {
Constructor constructor =
MethodLookupUtils.lookupConstructor(functionClass, parameters);
if (constructor != null) {
return new ConstructorFunction(constructor);
}
}
else {
Method method =
MethodLookupUtils.lookupStaticMethod(
functionClass,
methodName,
parameters);
if (method != null) {
return new MethodFunction(method);
}
}
return null;
}
}