001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.jxpath; 018 019import java.lang.reflect.Constructor; 020import java.lang.reflect.Method; 021import java.util.Collections; 022import java.util.Set; 023 024import org.apache.commons.jxpath.functions.ConstructorFunction; 025import org.apache.commons.jxpath.functions.MethodFunction; 026import org.apache.commons.jxpath.util.MethodLookupUtils; 027 028/** 029 * Extension functions provided by a Java class. 030 * 031 * Let's say we declared a ClassFunction like this: 032 * <blockquote><pre> 033 * new ClassFunctions(Integer.class, "int") 034 * </pre></blockquote> 035 * 036 * We can now use XPaths like: 037 * <dl> 038 * <dt><code>"int:new(3)"</code></dt> 039 * <dd>Equivalent to <code>new Integer(3)</code></dd> 040 * <dt><code>"int:getInteger('foo')"</code></dt> 041 * <dd>Equivalent to <code>Integer.getInteger("foo")</code></dd> 042 * <dt><code>"int:floatValue(int:new(4))"</code></dt> 043 * <dd>Equivalent to <code>new Integer(4).floatValue()</code></dd> 044 * </dl> 045 * 046 * <p> 047 * If the first argument of a method is {@link ExpressionContext}, the 048 * expression context in which the function is evaluated is passed to 049 * the method. 050 * 051 * @author Dmitri Plotnikov 052 * @version $Revision: 652845 $ $Date: 2008-05-02 19:46:46 +0200 (Fr, 02 Mai 2008) $ 053 */ 054public class ClassFunctions implements Functions { 055 private static final Object[] EMPTY_ARRAY = new Object[0]; 056 057 private Class functionClass; 058 private String namespace; 059 060 /** 061 * Create a new ClassFunctions. 062 * @param functionClass Class providing the functions 063 * @param namespace assigned ns 064 */ 065 public ClassFunctions(Class functionClass, String namespace) { 066 this.functionClass = functionClass; 067 this.namespace = namespace; 068 } 069 070 /** 071 * Returns a set of one namespace - the one specified in the constructor. 072 * 073 * @return a singleton 074 */ 075 public Set getUsedNamespaces() { 076 return Collections.singleton(namespace); 077 } 078 079 /** 080 * Returns a {@link Function}, if any, for the specified namespace, 081 * name and parameter types. 082 * 083 * @param namespace if it is not the namespace specified in the constructor, 084 * the method returns null 085 * @param name is a function name or "new" for a constructor. 086 * @param parameters Object[] of parameters 087 * 088 * @return a MethodFunction, a ConstructorFunction or null if there is no 089 * such function. 090 */ 091 public Function getFunction( 092 String namespace, 093 String name, 094 Object[] parameters) { 095 if (namespace == null) { 096 if (this.namespace != null) { 097 return null; 098 } 099 } 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}