diff --git a/src/main/java/org/apache/commons/jxpath/ClassFunctions.java b/src/main/java/org/apache/commons/jxpath/ClassFunctions.java index dbe29237f..e209400be 100644 --- a/src/main/java/org/apache/commons/jxpath/ClassFunctions.java +++ b/src/main/java/org/apache/commons/jxpath/ClassFunctions.java @@ -23,6 +23,7 @@ import org.apache.commons.jxpath.functions.ConstructorFunction; import org.apache.commons.jxpath.functions.MethodFunction; +import org.apache.commons.jxpath.ri.JXPathFilter; import org.apache.commons.jxpath.util.MethodLookupUtils; /** @@ -92,6 +93,28 @@ public Function getFunction( String namespace, String name, Object[] parameters) { + return getFunction(namespace, name, parameters, null); + } + + public Function getFunction( + String namespace, + String name, + Object[] parameters, + JXPathFilter jxPathFilter) { + + // give chance to ClassFilter to filter out, if present + try { + if (jxPathFilter != null && !jxPathFilter.exposeToXPath(functionClass.getName())) { + throw new ClassNotFoundException(functionClass.getName()); + } + } + catch (ClassNotFoundException ex) { + throw new JXPathException( + "Cannot invoke extension function " + + (namespace != null ? namespace + ":" + name : name), + ex); + } + if (namespace == null) { if (this.namespace != null) { return null; diff --git a/src/main/java/org/apache/commons/jxpath/FunctionLibrary.java b/src/main/java/org/apache/commons/jxpath/FunctionLibrary.java index 171adbd75..13443a226 100644 --- a/src/main/java/org/apache/commons/jxpath/FunctionLibrary.java +++ b/src/main/java/org/apache/commons/jxpath/FunctionLibrary.java @@ -16,6 +16,8 @@ */ package org.apache.commons.jxpath; +import org.apache.commons.jxpath.ri.JXPathFilter; + import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -77,12 +79,30 @@ public Set getUsedNamespaces() { */ public Function getFunction(String namespace, String name, Object[] parameters) { + return getFunction(namespace, name, parameters, null); + } + + /** + * Returns a Function, if any, for the specified namespace, + * name and parameter types. + * @param namespace function namespace + * @param name function name + * @param parameters parameters + * @param jxPathFilter the XPath filter + * @return Function found + */ + public Function getFunction( + String namespace, + String name, + Object[] parameters, + JXPathFilter jxPathFilter) { Object candidates = functionCache().get(namespace); if (candidates instanceof Functions) { return ((Functions) candidates).getFunction( namespace, name, - parameters); + parameters, + jxPathFilter); } if (candidates instanceof List) { List list = (List) candidates; @@ -92,7 +112,8 @@ public Function getFunction(String namespace, String name, ((Functions) list.get(i)).getFunction( namespace, name, - parameters); + parameters, + jxPathFilter); if (function != null) { return function; } diff --git a/src/main/java/org/apache/commons/jxpath/Functions.java b/src/main/java/org/apache/commons/jxpath/Functions.java index 216f7229f..4bce6ffab 100644 --- a/src/main/java/org/apache/commons/jxpath/Functions.java +++ b/src/main/java/org/apache/commons/jxpath/Functions.java @@ -16,6 +16,8 @@ */ package org.apache.commons.jxpath; +import org.apache.commons.jxpath.ri.JXPathFilter; + import java.util.Set; /** @@ -46,4 +48,15 @@ public interface Functions { * @return Function */ Function getFunction(String namespace, String name, Object[] parameters); + + /** + * Returns a Function, if any, for the specified namespace, + * name and parameter types. + * @param namespace ns + * @param name function name + * @param parameters Object[] + * @param jxPathFilter the XPath filter + * @return Function + */ + Function getFunction(String namespace, String name, Object[] parameters, JXPathFilter jxPathFilter); } diff --git a/src/main/java/org/apache/commons/jxpath/PackageFunctions.java b/src/main/java/org/apache/commons/jxpath/PackageFunctions.java index 86b09e426..612cfc678 100644 --- a/src/main/java/org/apache/commons/jxpath/PackageFunctions.java +++ b/src/main/java/org/apache/commons/jxpath/PackageFunctions.java @@ -25,6 +25,7 @@ import org.apache.commons.jxpath.functions.ConstructorFunction; import org.apache.commons.jxpath.functions.MethodFunction; +import org.apache.commons.jxpath.ri.JXPathFilter; import org.apache.commons.jxpath.util.ClassLoaderUtil; import org.apache.commons.jxpath.util.MethodLookupUtils; import org.apache.commons.jxpath.util.TypeUtils; @@ -112,10 +113,41 @@ public Set getUsedNamespaces() { * @return a MethodFunction, a ConstructorFunction or null if no function * is found */ + public Function getFunction( + String namespace, + String name, + Object[] parameters) { + return getFunction(namespace, name, parameters, null); + } + + /** + * Returns a {@link Function}, if found, for the specified namespace, + * name and parameter types. + *

+ * @param namespace - if it is not the same as specified in the + * construction, this method returns null + * @param name - name of the method, which can one these forms: + *

+ * @param parameters Object[] of parameters + * @param jxPathFilter the XPath filter + * @return a MethodFunction, a ConstructorFunction or null if no function + * is found + */ public Function getFunction( String namespace, String name, - Object[] parameters) { + Object[] parameters, + JXPathFilter jxPathFilter) { + if ((namespace == null && this.namespace != null) //NOPMD || (namespace != null && !namespace.equals(this.namespace))) { return null; @@ -186,7 +218,7 @@ public Function getFunction( Class functionClass; try { - functionClass = ClassLoaderUtil.getClass(className, true); + functionClass = ClassLoaderUtil.getClass(className, true, jxPathFilter); } catch (ClassNotFoundException ex) { throw new JXPathException( diff --git a/src/main/java/org/apache/commons/jxpath/ri/JXPathClassFilter.java b/src/main/java/org/apache/commons/jxpath/ri/JXPathClassFilter.java new file mode 100644 index 000000000..19bdb789f --- /dev/null +++ b/src/main/java/org/apache/commons/jxpath/ri/JXPathClassFilter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.jxpath.ri; + +/** + * Class filter (optional) to be used by JXPath. + * + * System property "jxpath.class.deny" can be set to specify the list of restricted classnames. + * This property takes a list of java classnames (use comma as separator to specify more than one class). + * If this property is not set, it exposes any java class to javascript + * Ex: jxpath.class.deny=java.lang.Runtime will deny exposing java.lang.Runtime class via xpath, while all other classes will be exposed. + * + * @author bhmohanr-techie + * @version $Revision$ $Date$ + */ +public interface JXPathClassFilter { + + /** + * Should the Java class of the specified name be exposed via xpath? + * @param className is the fully qualified name of the java class being + * checked. This will not be null. Only non-array class names will be + * passed. + * @return true if the java class can be exposed via xpath, false otherwise + */ + public boolean exposeToXPath(String className); +} diff --git a/src/main/java/org/apache/commons/jxpath/ri/JXPathContextReferenceImpl.java b/src/main/java/org/apache/commons/jxpath/ri/JXPathContextReferenceImpl.java index 54214b89b..779350946 100644 --- a/src/main/java/org/apache/commons/jxpath/ri/JXPathContextReferenceImpl.java +++ b/src/main/java/org/apache/commons/jxpath/ri/JXPathContextReferenceImpl.java @@ -27,23 +27,10 @@ import java.util.Vector; import java.util.Map.Entry; -import org.apache.commons.jxpath.CompiledExpression; -import org.apache.commons.jxpath.ExceptionHandler; -import org.apache.commons.jxpath.Function; -import org.apache.commons.jxpath.Functions; -import org.apache.commons.jxpath.JXPathContext; -import org.apache.commons.jxpath.JXPathException; -import org.apache.commons.jxpath.JXPathFunctionNotFoundException; -import org.apache.commons.jxpath.JXPathInvalidSyntaxException; -import org.apache.commons.jxpath.JXPathNotFoundException; -import org.apache.commons.jxpath.JXPathTypeConversionException; -import org.apache.commons.jxpath.Pointer; +import org.apache.commons.jxpath.*; import org.apache.commons.jxpath.ri.axes.InitialContext; import org.apache.commons.jxpath.ri.axes.RootContext; -import org.apache.commons.jxpath.ri.compiler.Expression; -import org.apache.commons.jxpath.ri.compiler.LocationPath; -import org.apache.commons.jxpath.ri.compiler.Path; -import org.apache.commons.jxpath.ri.compiler.TreeCompiler; +import org.apache.commons.jxpath.ri.compiler.*; import org.apache.commons.jxpath.ri.model.NodePointer; import org.apache.commons.jxpath.ri.model.NodePointerFactory; import org.apache.commons.jxpath.ri.model.VariablePointerFactory; @@ -739,7 +726,7 @@ public Function getFunction(QName functionName, Object[] parameters) { while (funcCtx != null) { funcs = funcCtx.getFunctions(); if (funcs != null) { - func = funcs.getFunction(namespace, name, parameters); + func = funcs.getFunction(namespace, name, parameters, new JXPathFilter()); if (func != null) { return func; } diff --git a/src/main/java/org/apache/commons/jxpath/ri/JXPathFilter.java b/src/main/java/org/apache/commons/jxpath/ri/JXPathFilter.java new file mode 100644 index 000000000..be4ea1233 --- /dev/null +++ b/src/main/java/org/apache/commons/jxpath/ri/JXPathFilter.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.jxpath.ri; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * A filter to be used by JXPath, to evaluate the xpath string values to impose any restrictions. + * This class implements specific filter interfaces, and implements methods in those. + * For instance, it JXPathClassFilter interface, which is used to check if any restricted java classes are passed via xpath + * JXPath uses this filter instance when an extension function instance is created. + * + * @author bhmohanr-techie + * @version $Revision$ $Date$ + */ +public class JXPathFilter implements JXPathClassFilter { + ArrayList restrictedClassesList = null; + + public JXPathFilter() { + init(); + } + + public void init() { + String restrictedClasses = System.getProperty("jxpath.class.deny"); + restrictedClassesList = null; + if ((restrictedClasses != null) && (restrictedClasses.trim().length() > 0)) { + restrictedClassesList = new ArrayList(); + restrictedClassesList.addAll(Arrays.asList(restrictedClasses.split(","))); + } + } + + /** + * Specifies whether the Java class of the specified name be exposed via xpath + * + * @param className is the fully qualified name of the java class being checked. + * This will not be null. Only non-array class names will be passed. + * @return true if the java class can be exposed via xpath, false otherwise + */ + @Override + public boolean exposeToXPath(String className) { + if ((restrictedClassesList == null) || (restrictedClassesList.size() < 1) || restrictedClassesList.contains("*")) { + return true; + } + + if (restrictedClassesList.contains(className)) { + return false; + } + + return true; + } +} + diff --git a/src/main/java/org/apache/commons/jxpath/util/ClassLoaderUtil.java b/src/main/java/org/apache/commons/jxpath/util/ClassLoaderUtil.java index abb4d2f5f..c66e92dcb 100644 --- a/src/main/java/org/apache/commons/jxpath/util/ClassLoaderUtil.java +++ b/src/main/java/org/apache/commons/jxpath/util/ClassLoaderUtil.java @@ -16,6 +16,8 @@ */ package org.apache.commons.jxpath.util; +import org.apache.commons.jxpath.ri.JXPathFilter; + import java.util.HashMap; import java.util.Map; @@ -75,12 +77,19 @@ private static void addAbbreviation(String primitive, String abbreviation) { * @param classLoader the class loader to use to load the class * @param className the class name * @param initialize whether the class must be initialized + * @param jxPathFilter the XPath filter * @return the class represented by className using the classLoader * @throws ClassNotFoundException if the class is not found */ - public static Class getClass(ClassLoader classLoader, String className, boolean initialize) + public static Class getClass(ClassLoader classLoader, String className, boolean initialize, JXPathFilter jxPathFilter) throws ClassNotFoundException { Class clazz; + + // give chance to ClassFilter to filter out, if present + if (jxPathFilter != null && !jxPathFilter.exposeToXPath(className)) { + throw new ClassNotFoundException(className); + } + if (abbreviationMap.containsKey(className)) { String clsName = "[" + abbreviationMap.get(className); clazz = Class.forName(clsName, initialize, classLoader).getComponentType(); @@ -91,6 +100,38 @@ public static Class getClass(ClassLoader classLoader, String className, boolean return clazz; } + /** + * Returns the class represented by className using the + * classLoader. This implementation supports names like + * "java.lang.String[]" as well as "[Ljava.lang.String;". + * + * @param classLoader the class loader to use to load the class + * @param className the class name + * @param initialize whether the class must be initialized + * @return the class represented by className using the classLoader + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass(ClassLoader classLoader, String className, boolean initialize) + throws ClassNotFoundException { + return getClass(classLoader, className, initialize, null); + } + + /** + * Returns the (initialized) class represented by className + * using the classLoader. This implementation supports names + * like "java.lang.String[]" as well as + * "[Ljava.lang.String;". + * + * @param classLoader the class loader to use to load the class + * @param className the class name + * @param jxPathFilter the XPath filter + * @return the class represented by className using the classLoader + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass(ClassLoader classLoader, String className, JXPathFilter jxPathFilter) throws ClassNotFoundException { + return getClass(classLoader, className, true, jxPathFilter); + } + /** * Returns the (initialized) class represented by className * using the classLoader. This implementation supports names @@ -103,7 +144,7 @@ public static Class getClass(ClassLoader classLoader, String className, boolean * @throws ClassNotFoundException if the class is not found */ public static Class getClass(ClassLoader classLoader, String className) throws ClassNotFoundException { - return getClass(classLoader, className, true); + return getClass(classLoader, className, true, null); } /** @@ -117,7 +158,22 @@ public static Class getClass(ClassLoader classLoader, String className) throws C * @throws ClassNotFoundException if the class is not found */ public static Class getClass(String className) throws ClassNotFoundException { - return getClass(className, true); + return getClass(className, true, null); + } + + /** + * Returns the (initialized) class represented by className + * using the current thread's context class loader. This implementation + * supports names like "java.lang.String[]" as well as + * "[Ljava.lang.String;". + * + * @param className the class name + * @param jxPathFilter the XPath filter + * @return the class represented by className using the current thread's context class loader + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass(String className, JXPathFilter jxPathFilter) throws ClassNotFoundException { + return getClass(className, true, jxPathFilter); } /** @@ -132,17 +188,33 @@ public static Class getClass(String className) throws ClassNotFoundException { * @throws ClassNotFoundException if the class is not found */ public static Class getClass(String className, boolean initialize) throws ClassNotFoundException { + return getClass(className, initialize, null); + } + + /** + * Returns the class represented by className using the + * current thread's context class loader. This implementation supports + * names like "java.lang.String[]" as well as + * "[Ljava.lang.String;". + * + * @param className the class name + * @param initialize whether the class must be initialized + * @param jxPathFilter the XPath filter + * @return the class represented by className using the current thread's context class loader + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass(String className, boolean initialize, JXPathFilter jxPathFilter) throws ClassNotFoundException { ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); ClassLoader currentCL = ClassLoaderUtil.class.getClassLoader(); if (contextCL != null) { try { - return getClass(contextCL, className, initialize); + return getClass(contextCL, className, initialize, jxPathFilter); } catch (ClassNotFoundException e) {//NOPMD // ignore this exception and try the current class loader. } } - return getClass(currentCL, className, initialize); + return getClass(currentCL, className, initialize, jxPathFilter); } /** diff --git a/src/test/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunctionTest.java b/src/test/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunctionTest.java index 7a222e4d4..7ec7f9419 100644 --- a/src/test/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunctionTest.java +++ b/src/test/java/org/apache/commons/jxpath/ri/compiler/ExtensionFunctionTest.java @@ -16,23 +16,10 @@ */ package org.apache.commons.jxpath.ri.compiler; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Locale; - -import org.apache.commons.jxpath.ClassFunctions; -import org.apache.commons.jxpath.ExpressionContext; -import org.apache.commons.jxpath.Function; -import org.apache.commons.jxpath.FunctionLibrary; -import org.apache.commons.jxpath.Functions; -import org.apache.commons.jxpath.JXPathContext; -import org.apache.commons.jxpath.JXPathTestCase; -import org.apache.commons.jxpath.NodeSet; -import org.apache.commons.jxpath.PackageFunctions; -import org.apache.commons.jxpath.Pointer; -import org.apache.commons.jxpath.TestBean; -import org.apache.commons.jxpath.Variables; +import java.util.*; + +import org.apache.commons.jxpath.*; +import org.apache.commons.jxpath.ri.JXPathFilter; import org.apache.commons.jxpath.ri.model.NodePointer; import org.apache.commons.jxpath.util.JXPath11CompatibleTypeConverter; import org.apache.commons.jxpath.util.TypeConverter; @@ -49,6 +36,7 @@ public class ExtensionFunctionTest extends JXPathTestCase { private JXPathContext context; private TestBean testBean; private TypeConverter typeConverter; + JXPathFilter jxPathFilter = new JXPathFilter(); public void setUp() { if (context == null) { @@ -385,6 +373,139 @@ public void testBCNodeSetHack() { Boolean.TRUE); } + public void testClassFunctionsWithClassFilter() { + try { + Functions iFunctions = new ClassFunctions(TestFunctions3.class, "test3"); + + System.setProperty("jxpath.class.deny", "org.apache.commons.jxpath.ri.compiler.TestFunctions3"); + jxPathFilter.init(); + + Function classFunction = iFunctions.getFunction("test3", "testFunction3Method1", null, jxPathFilter); + classFunction = null; + throw new Exception("testClassFunctionsWithClassFilter() failed."); + } catch (Throwable t) { + assertTrue((t.getMessage().indexOf("Cannot invoke extension function test3:testFunction3Method1; org.apache.commons.jxpath.ri.compiler.TestFunctions3") > -1) + || (t.getMessage().indexOf("java.lang.ClassNotFoundException: org.apache.commons.jxpath.ri.compiler.TestFunctions3") > -1)); + } finally { + System.clearProperty("jxpath.class.deny"); + } + } + + public void testClassFunctionsWithoutClassFilter() { + Function classFunction = null; + try { + Functions iFunctions = new ClassFunctions(TestFunctions3.class, "test3"); + + System.clearProperty("jxpath.class.deny"); + jxPathFilter.init(); + + classFunction = iFunctions.getFunction("test3", "testFunction3Method1", null, jxPathFilter); + } catch (Throwable t) { + fail(t.getMessage()); + } finally { + System.clearProperty("jxpath.class.deny"); + assertTrue(classFunction != null); + classFunction = null; + } + } + + public void testPackageFunctionsWithClassFilter() { + try { + Functions iFunctions = new PackageFunctions("org.apache.commons.jxpath.ri.compiler.","jxpathtests"); + + System.setProperty("jxpath.class.deny", "org.apache.commons.jxpath.ri.compiler.TestFunctions3"); + jxPathFilter.init(); + + Function packageFunction = iFunctions.getFunction("jxpathtests", "TestFunctions3.testFunction3Method1", null, jxPathFilter); + packageFunction = null; + throw new Exception("testPackageFunctionsWithClassFilter() failed."); + } catch (Throwable t) { + assertTrue((t.getMessage().indexOf("Cannot invoke extension function jxpathtests:TestFunctions3.testFunction3Method1; org.apache.commons.jxpath.ri.compiler.TestFunctions3") > -1) + || (t.getMessage().indexOf("java.lang.ClassNotFoundException: org.apache.commons.jxpath.ri.compiler.TestFunctions3") > -1)); + } finally { + System.clearProperty("jxpath.class.deny"); + } + } + + public void testPackageFunctionsWithoutClassFilter() { + Function packageFunction = null; + try { + Functions iFunctions = new PackageFunctions("org.apache.commons.jxpath.ri.compiler.","jxpathtests"); + + System.clearProperty("jxpath.class.deny"); + jxPathFilter.init(); + + packageFunction = iFunctions.getFunction("jxpathtests", "TestFunctions3.testFunction3Method1", null, jxPathFilter); + } catch (Throwable t) { + fail(t.getMessage()); + } finally { + System.clearProperty("jxpath.class.deny"); + assertTrue(packageFunction != null); + packageFunction = null; + } + } + + public void testJXPathContextFunctionsWithClassFilter() { + String failedMethods = null; + try { + System.setProperty("jxpath.class.deny", "java.lang.Thread"); + jxPathFilter.init(); + + try { + context.iterate("java.lang.Thread.sleep(5000)"); + throw new Exception("testJXPathContextFunctionsWithClassFilter() failed for iterate()"); + } catch (Throwable t) { + if ((t.getMessage().indexOf("Cannot invoke extension function java.lang.Thread.sleep; java.lang.Thread") > -1) + || (t.getMessage().indexOf("java.lang.ClassNotFoundException: java.lang.Thread") > -1)) { + //success + } else { + failedMethods = "org.apache.commons.jxpath.JXPathContext.iterate()"; + } + } + + try { + context.selectSingleNode("java.lang.Thread.sleep(5000)"); + throw new Exception("testJXPathContextFunctionsWithClassFilter() failed for iterate()"); + } catch (Throwable t) { + if ((t.getMessage().indexOf("Cannot invoke extension function java.lang.Thread.sleep; java.lang.Thread") > -1) + || (t.getMessage().indexOf("java.lang.ClassNotFoundException: java.lang.Thread") > -1)) { + //success + } else { + failedMethods += ("".equals(failedMethods) ? "org.apache.commons.jxpath.JXPathContext.selectSingleNode()" : ", org.apache.commons.jxpath.JXPathContext.selectSingleNode()"); + } + } + + } catch (Throwable t) { + fail(t.getMessage()); + } finally { + System.clearProperty("jxpath.class.deny"); + if (failedMethods != null) { + fail("Problem exists in: " + failedMethods); + } + } + } + + public void testJXPathContextFunctionsWithoutClassFilter() { + try { + System.clearProperty("jxpath.class.deny"); + jxPathFilter.init(); + + long t = System.currentTimeMillis(); + context.iterate("java.lang.Thread.sleep(5000)"); + t = System.currentTimeMillis() - t; + assertTrue(t >= 5); + + t = System.currentTimeMillis(); + context.selectSingleNode("java.lang.Thread.sleep(5000)"); + t = System.currentTimeMillis() - t; + assertTrue(t >= 5); + } catch (Throwable t) { + fail(t.getMessage()); + } finally { + System.clearProperty("jxpath.class.deny"); + } + } + private static class Context implements ExpressionContext { private Object object; diff --git a/src/test/java/org/apache/commons/jxpath/ri/compiler/TestFunctions3.java b/src/test/java/org/apache/commons/jxpath/ri/compiler/TestFunctions3.java new file mode 100644 index 000000000..d8d0c92a6 --- /dev/null +++ b/src/test/java/org/apache/commons/jxpath/ri/compiler/TestFunctions3.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.jxpath.ri.compiler; + +import org.apache.commons.jxpath.Functions; +import org.apache.commons.jxpath.JXPathContext; + +import java.util.*; + +/** + * A test class with few methods, with different argument list + * + * @author bhmohanr-techie + * @version $Revision$ $Date$ + */ +public final class TestFunctions3 { + + static { + System.out.println("TestFunctions3: static block..."); + } + + public TestFunctions3() { + System.out.println("TestFunctions3: constructor..."); + } + + public static String testFunction3Method1() { + System.out.println("TestFunctions3: testFunction3Method1 method..."); + return "testFunction3Method1"; + } + + public String testFunction3Method2(String str) { + System.out.println("TestFunctions3: testFunction3Method2 method..." + str); + return "testFunction3Method2:" + str; + } + + public String testFunction3Method3(String str1, String str2) { + System.out.println("TestFunctions3: testFunction3Method3 method..." + str1 + ", " + str2); + return "testFunction3Method3:" + str1 + ":" + str2; + } + +} \ No newline at end of file