You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jmeter-dev@jakarta.apache.org by se...@apache.org on 2007/10/03 20:55:39 UTC

svn commit: r581687 - in /jakarta/jmeter/trunk: src/jorphan/org/apache/jorphan/reflect/Functor.java test/src/org/apache/jorphan/reflect/ test/src/org/apache/jorphan/reflect/TestFunctor.java xdocs/changes.xml

Author: sebb
Date: Wed Oct  3 11:55:38 2007
New Revision: 581687

URL: http://svn.apache.org/viewvc?rev=581687&view=rev
Log:
Functor code tightened up; Functor can now be used with interfaces, as well as pre-defined targets and parameters.

Added:
    jakarta/jmeter/trunk/test/src/org/apache/jorphan/reflect/
    jakarta/jmeter/trunk/test/src/org/apache/jorphan/reflect/TestFunctor.java   (with props)
Modified:
    jakarta/jmeter/trunk/src/jorphan/org/apache/jorphan/reflect/Functor.java
    jakarta/jmeter/trunk/xdocs/changes.xml

Modified: jakarta/jmeter/trunk/src/jorphan/org/apache/jorphan/reflect/Functor.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/jorphan/org/apache/jorphan/reflect/Functor.java?rev=581687&r1=581686&r2=581687&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/jorphan/org/apache/jorphan/reflect/Functor.java (original)
+++ jakarta/jmeter/trunk/src/jorphan/org/apache/jorphan/reflect/Functor.java Wed Oct  3 11:55:38 2007
@@ -22,147 +22,315 @@
 import java.util.Arrays;
 
 import org.apache.jorphan.logging.LoggingManager;
+import org.apache.jorphan.util.JMeterError;
 import org.apache.log.Logger;
 
 /**
- * @author mstover
+ * Implements function call-backs.
+ * 
+ * Functors may be defined for instance objects or classes.
+ * 
+ * The method is created on first use, which allows the invokee (class or instance)
+ * to be omitted from the constructor.
+ * 
+ * The class name takes precedence over the instance.
+ * 
+ * If a functor is created with a particular instance, then that is used for all future calls;
+ * if an object is provided, it is ignored. 
+ * This allows easy override of the table model behaviour.
+ * 
+ * If an argument list is provided in the constructor, then that is ignored in subsequent invoke() calls.
+ * 
+ * Usage:
+ * f = new Functor("methodName")
+ * o = f.invoke(object) - OR -
+ * o = f.invoke(object,params)
+ * 
+ * f2 = new Functor(object,"methodName");
+ * o = f2.invoke() - OR -
+ * o = f2.invoke(params)
+ * 
+ * f3 = new Functor(class,"methodName");
+ * o = f3.invoke(object) - will be ignored
+ * o = f3.invoke() - OR -
+ * o = f3.invoke(params)
+ * o = f3.invoke(object,params) - object will be ignored
+ * 
  */
 public class Functor {
-	private static Logger log = LoggingManager.getLoggerForClass();
+	private static final Logger log = LoggingManager.getLoggerForClass();
 
-	Object invokee;
+	/*
+	 * If non-null, then any object provided to invoke() is ignored.
+	 */
+	private final Object invokee;
+
+	/*
+	 * Class to be used to create the Method.
+	 * Will be non-null if either Class or Object was provided during construction.
+	 * 
+	 *  Can be used instead of invokee, e.g. when using interfaces.
+	*/
+	private final Class clazz; 
 
-	String methodName;
+	// Methondname must always be provided.
+	private final String methodName;
 
-	Object[] args;
+	/*
+	 * If non-null, then any argument list passed to invoke() will be ignored.
+	 */
+	private Object[] args;
 
-	Class[] types;
+	/*
+	 * Argument types used to create the method.
+	 * May be provided explicitly, or derived from the constructor argument list.
+	 */
+	private final Class[] types;
 
-	Method methodToInvoke;
+	/*
+	 * This depends on the class or invokee and either args or types;
+	 * it is set once by doCreateMethod(), which must be the only method to access it.
+	*/
+	private Method methodToInvoke;
+	
+	Functor(){
+		throw new IllegalArgumentException("Must provide at least one argument");
+	}
 
 	/**
 	 * Create a functor with the invokee and a method name.
 	 * 
-	 * @param invokee
-	 * @param methodName
+	 * The invokee will be used in all future invoke calls.
+	 * 
+	 * @param _invokee object on which to invoke the method
+	 * @param _methodName method name
+	 */
+	public Functor(Object _invokee, String _methodName) {
+		this(null, _invokee, _methodName, null, null);
+	}
+
+	/**
+	 * Create a functor from class and method name.
+	 * This is useful for methods defined in interfaces.
+	 * 
+	 * The actual invokee must be provided in all invoke() calls,
+	 * and must be an instance of the class.
+	 * 
+	 * @param _clazz class to be used
+	 * @param _methodName method name
 	 */
-	public Functor(Object invokee, String methodName) {
-		this(methodName);
-		this.invokee = invokee;
+	public Functor(Class _clazz, String _methodName) {
+		this(_clazz, null, _methodName, null, null);
 	}
 
 	/**
 	 * Create a functor with the invokee, method name, and argument class types.
 	 * 
-	 * @param invokee
-	 * @param methodName
+	 * The invokee will be ignored in any invoke() calls.
+	 * 
+	 * @param _invokee object on which to invoke the method
+	 * @param _methodName method name
 	 * @param types
 	 */
-	public Functor(Object invokee, String methodName, Class[] types) {
-		this(invokee, methodName);
-		this.types = types;
+	public Functor(Object _invokee, String _methodName, Class[] types) {
+		this(null, _invokee, _methodName, null, types);
 	}
 
 	/**
 	 * Create a functor with just the method name.
 	 * 
-	 * @param methodName
+	 * The invokee and any parameters must be provided in all invoke() calls.
+	 * 
+	 * @param _methodName method name
 	 */
-	public Functor(String methodName) {
-		this.methodName = methodName;
+	public Functor(String _methodName) {
+		this(null, null, _methodName, null, null);
 	}
 
 	/**
 	 * Create a functor with the method name and argument class types.
 	 * 
-	 * @param methodName
-	 * @param types
+	 * The invokee must be provided in all invoke() calls
+	 * 
+	 * @param _methodName method name
+	 * @param _types parameter types
 	 */
-	public Functor(String methodName, Class[] types) {
-		this(methodName);
-		this.types = types;
+	public Functor(String _methodName, Class[] _types) {
+		this(null, null, _methodName, null, _types);
 	}
 
 	/**
 	 * Create a functor with an invokee, method name, and argument values.
 	 * 
-	 * @param invokee
-	 * @param methodName
-	 * @param args
+	 * The invokee will be ignored in any invoke() calls.
+	 * 
+	 * @param _invokee object on which to invoke the method
+	 * @param _methodName method name
+	 * @param _args arguments to be passed to the method
 	 */
-	public Functor(Object invokee, String methodName, Object[] args) {
-		this(invokee, methodName);
-		this.args = args;
+	public Functor(Object _invokee, String _methodName, Object[] _args) {
+		this(null, _invokee, _methodName, _args, null);
 	}
 
-	public Functor(String methodName, Object[] args) {
-		this(methodName);
-		this.args = args;
+	/**
+	 * Create a functor from method name and arguments.
+	 *  
+	 * The class will be determined from the first invoke call.
+	 * All invoke calls must include a target object;
+	 * which must be of the same type as the initial invokee.
+	 * 
+	 * @param _methodName method name
+	 * @param _args
+	 */
+	public Functor(String _methodName, Object[] _args) {
+		this(null, null, _methodName, _args, null);
 	}
 
 	/**
-	 * Create a functor with an invokee, method name, argument values, and
-	 * argument class types.
+	 * Create a functor from various different combinations of parameters.
 	 * 
-	 * @param invokee
-	 * @param methodName
-	 * @param args
-	 * @param types
+	 * @param _clazz class containing the method
+	 * @param _invokee invokee to use for the method call
+	 * @param _methodName the method name (required)
+	 * @param _args arguments to be used
+	 * @param _types types of arguments to be used
+	 * 
+	 * @throws IllegalArgumentException if:
+	 * - methodName is null
+	 * - both class and invokee are specified
+	 * - both arguments and types are specified
 	 */
-	public Functor(Object invokee, String methodName, Object[] args, Class[] types) {
-		this(invokee, methodName, args);
-		this.types = types;
+	private Functor(Class _clazz, Object _invokee, String _methodName, Object[] _args, Class[] _types) {
+		if (_methodName == null){
+			throw new IllegalArgumentException("Methodname must not be null");
+		}
+		if (_clazz != null && _invokee != null){
+			throw new IllegalArgumentException("Cannot provide both Class and Object");
+		}
+		if (_args != null && _types != null){
+			throw new IllegalArgumentException("Cannot provide both arguments and argument types");
+		}
+		// If class not provided, default to invokee class, else null
+		this.clazz = _clazz != null ? _clazz : (_invokee != null ? _invokee.getClass() : null);
+		this.invokee = _invokee;
+		this.methodName = _methodName;
+		this.args = _args;
+		// If types not provided, default to argument types, else null
+		this.types = _types != null ? _types : (_args != null ? _getTypes(_args) : null);
 	}
 
-	public Object invoke() {
+	//////////////////////////////////////////
+	
+	/*
+	 * Low level invocation routine.
+	 * 
+	 * Should only be called after any defaults have been applied.
+	 * 
+	 */
+	private Object doInvoke(Class _class, Object _invokee, Object[] _args) {
+		Class[] argTypes = getTypes(_args);
 		try {
-			return createMethod(getTypes()).invoke(invokee, getArgs());
+			Method method = doCreateMethod(_class , argTypes);
+			if (method == null){
+				throw new JMeterError("Can't find method "+_class+typesToString(argTypes));
+			}
+			return method.invoke(_invokee, _args);
 		} catch (Exception e) {
-			final String message = "Trouble functing method: "+methodName+" invokee: "+invokee.getClass().getName();
+			final String message = "Trouble functing: "
+				+_class.getName()
+				+"."+methodName+"(...) : "
+				+" invokee: "+_invokee
+				+" "+e.getMessage();
 			log.warn(message, e);
-			throw new org.apache.jorphan.util.JMeterError(message,e); // JDK1.4
+			throw new JMeterError(message,e);
+		}
+	}
+
+	/**
+	 * Invoke a Functor, which must have been created with either a class name or object.
+	 * 
+	 * @return the object if any
+	 */
+	public Object invoke() {
+		if (invokee == null) {
+			throw new IllegalStateException("Cannot call invoke() - invokee not known");
 		}
+		// If invokee was provided, then clazz has been set up
+		return doInvoke(clazz, invokee, getArgs());
 	}
 
+	/**
+	 * Invoke the method on a given object.
+	 * 
+	 * @param p_invokee - provides the object to call; ignored if the class or object were provided to the constructor
+	 * @return the value
+	 */
 	public Object invoke(Object p_invokee) {
-		this.invokee = p_invokee;
-		return invoke();
+		return invoke(p_invokee, getArgs());
 	}
 
+	/**
+	 * Invoke the method with the provided parameters.
+	 * 
+	 * The invokee must have been provided in the constructor.
+	 * 
+	 * @param p_args parameters for the method
+	 * @return the value
+	 */
 	public Object invoke(Object[] p_args) {
-		this.args = p_args;
-		return invoke();
+		if (invokee == null){
+			throw new IllegalStateException("Invokee was not provided in constructor");
+		}
+		// If invokee was provided, then clazz has been set up
+		return doInvoke(clazz, invokee, args != null? args : p_args);
 	}
 
+	/**
+	 * Invoke the method on the invokee with the provided parameters.
+	 * 
+	 * The invokee must agree with the class (if any) provided at construction time.
+	 * 
+	 * If the invokee was provided at construction time, then this invokee will be ignored.
+	 * If actual arguments were provided at construction time, then arguments will be ignored.
+	 * 
+	 */
 	public Object invoke(Object p_invokee, Object[] p_args) {
-		this.args = p_args;
-		this.invokee = p_invokee;
-		return invoke();
+		return doInvoke(clazz != null ? clazz : p_invokee.getClass(), // Use constructor class if present
+				       invokee != null ? invokee : p_invokee, // use invokee if provided
+						args != null? args : p_args);// use argumenrs if provided
 	}
 
-	private Method createMethod(Class[] p_types) {
-		log.debug("Trying to functorize invokee: " + invokee.getClass().getName() + " method: " + methodName
+	/*
+	 * Low-level (recursive) routine to define the method - if not already defined.
+	 * Synchronized to protect access to methodToInvoke.
+	 */
+	private synchronized Method doCreateMethod(Class p_class, Class[] p_types) {
+		if (log.isDebugEnabled()){
+		    log.debug("doCreateMethod() using "+this.toString()
+		    	+"class="
+				+ p_class.getName()
 				+ " types: " + Arrays.asList(p_types));
+		}
 		if (methodToInvoke == null) {
 			try {
-				methodToInvoke = invokee.getClass().getMethod(methodName, p_types);
+				methodToInvoke = p_class.getMethod(methodName, p_types);
 			} catch (Exception e) {
 				for (int i = 0; i < p_types.length; i++) {
 					Class primitive = getPrimitive(p_types[i]);
 					if (primitive != null) {
-						methodToInvoke = createMethod(getNewArray(i, primitive, p_types));
+						methodToInvoke = doCreateMethod(p_class, getNewArray(i, primitive, p_types));
 						if (methodToInvoke != null)
 							return methodToInvoke;
 					}
 					Class[] interfaces = p_types[i].getInterfaces();
 					for (int j = 0; j < interfaces.length; j++) {
-						methodToInvoke = createMethod(getNewArray(i, interfaces[j], p_types));
+						methodToInvoke = doCreateMethod(p_class,getNewArray(i, interfaces[j], p_types));
 						if (methodToInvoke != null) {
 							return methodToInvoke;
 						}
 					}
 					Class parent = p_types[i].getSuperclass();
-					methodToInvoke = createMethod(getNewArray(i, parent, p_types));
+					methodToInvoke = doCreateMethod(p_class,getNewArray(i, parent, p_types));
 					if (methodToInvoke != null) {
 						return methodToInvoke;
 					}
@@ -172,7 +340,7 @@
 		return methodToInvoke;
 	}
 
-	/*
+	/**
 	 * Check if a read Functor method is valid.
 	 * 
 	 * @deprecated ** for use by Unit test code only **
@@ -181,16 +349,15 @@
 	 */
 	public boolean checkMethod(Object _invokee){
 		Method m = null;
-		this.invokee=_invokee;
 		try {
-		    m = createMethod(getTypes());
+		    m = doCreateMethod(_invokee.getClass(), getTypes(args));
 		} catch (Exception e){
 			// ignored
 		}
 		return null != m;
 	}
 
-	/*
+	/**
 	 * Check if a write Functor method is valid.
 	 * 
 	 * @deprecated ** for use by Unit test code only **
@@ -199,9 +366,8 @@
 	 */
 	public boolean checkMethod(Object _invokee, Class c){
 		Method m = null;
-		this.invokee=_invokee;
 		try {
-		    m = createMethod(new Class[]{c});
+		    m = doCreateMethod(_invokee.getClass(), new Class[]{c});
 		} catch (Exception e){
 			// ignored
 		}
@@ -210,16 +376,38 @@
 
 	public String toString(){
 		StringBuffer sb = new StringBuffer(100);
-		sb.append("method: ");
-		sb.append(methodName);
+		if (clazz != null){
+			sb.append(clazz.getName());
+		}
 		if (invokee != null){
-		    sb.append(" invokee: ");
-		    sb.append(invokee.getClass().getName());
+		    sb.append("@");
+		    sb.append(System.identityHashCode(invokee));
+		} 
+		sb.append(".");
+		sb.append(methodName);
+		typesToString(sb,types);
+		return sb.toString();
+	}
+
+	private void typesToString(StringBuffer sb,Class[] _types) {
+		sb.append("(");
+		if (_types != null){
+			for(int i=0; i < _types.length; i++){
+				if (i>0) sb.append(",");
+				sb.append(_types[i].getName());
+			}
 		}
+		sb.append(")");
+	}
+
+	private String typesToString(Class[] argTypes) {
+		StringBuffer sb = new StringBuffer();
+		typesToString(sb,argTypes);
 		return sb.toString();
 	}
 
-	protected Class getPrimitive(Class t) {
+	private Class getPrimitive(Class t) {
+		if (t==null) return null;
 		if (t.equals(Integer.class)) {
 			return int.class;
 		} else if (t.equals(Long.class)) {
@@ -240,7 +428,7 @@
 		return null;
 	}
 
-	protected Class[] getNewArray(int i, Class replacement, Class[] orig) {
+	private Class[] getNewArray(int i, Class replacement, Class[] orig) {
 		Class[] newArray = new Class[orig.length];
 		for (int j = 0; j < newArray.length; j++) {
 			if (j == i) {
@@ -252,21 +440,26 @@
 		return newArray;
 	}
 
-	private Class[] getTypes() {
-		if (types == null) // do only once per functor instance. Could
-		// cause errors if functor used for multiple
-		// same-named-different-parametered methods.
+	// TODO - should this be synchronised?
+	private Class[] getTypes(Object[] _args) {
+		if (types == null)
 		{
-			if (args != null) {
-				types = new Class[args.length];
-				for (int i = 0; i < args.length; i++) {
-					types[i] = args[i].getClass();
-				}
-			} else {
-				types = new Class[0];
-			}
+			return _getTypes(_args);
 		}
 		return types;
+	}
+
+	private static Class[] _getTypes(Object[] _args) {
+		Class[] _types;
+		if (_args != null) {
+			_types = new Class[_args.length];
+			for (int i = 0; i < _args.length; i++) {
+				_types[i] = _args[i].getClass();
+			}
+		} else {
+			_types = new Class[0];
+		}
+		return _types;
 	}
 
 	private Object[] getArgs() {

Added: jakarta/jmeter/trunk/test/src/org/apache/jorphan/reflect/TestFunctor.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/test/src/org/apache/jorphan/reflect/TestFunctor.java?rev=581687&view=auto
==============================================================================
--- jakarta/jmeter/trunk/test/src/org/apache/jorphan/reflect/TestFunctor.java (added)
+++ jakarta/jmeter/trunk/test/src/org/apache/jorphan/reflect/TestFunctor.java Wed Oct  3 11:55:38 2007
@@ -0,0 +1,218 @@
+/*
+ * 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.jorphan.reflect;
+
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.jmeter.junit.JMeterTestCase;
+import org.apache.jorphan.util.JMeterError;
+
+/*
+ * Unit tests for classes that use Functors
+ * 
+ */
+public class TestFunctor extends JMeterTestCase {
+
+	interface HasName {
+		String getName();
+	}
+	
+	interface HasString {
+		String getString(String s);
+	}
+
+	class Test1 implements HasName {
+		private final String name;
+		public Test1(){
+			this("");
+		}
+		public Test1(String s){
+			name=s;
+		}
+		public String getName(){
+			return name;
+		}
+		public String getString(String s){
+			return s;
+		}
+	}
+	class Test1a extends Test1{
+		Test1a(){
+			super("1a");
+		}
+		Test1a(String s){
+			super("1a:"+s);
+		}
+		public String getName(){
+			return super.getName()+".";
+		}
+	}
+	class Test2 implements HasName, HasString {
+		private final String name;
+		public Test2(){
+			this("");
+		}
+		public Test2(String s){
+			name=s;
+		}
+		public String getName(){
+			return name;
+		}
+		public String getString(String s){
+			return s;
+		}
+	}
+	
+	public TestFunctor(String arg0) {
+		super(arg0);
+	}
+    
+	public void testName() throws Exception{
+		Functor f1 = new Functor("getName");
+		Functor f2 = new Functor("getName");
+		Functor f1a = new Functor("getName");
+		Test1 t1 = new Test1("t1");
+		Test2 t2 = new Test2("t2");
+		Test1a t1a = new Test1a("aa");
+		assertEquals("t1",f1.invoke(t1));
+		//assertEquals("t1",f1.invoke());
+		try {
+		    f1.invoke(t2);
+		    fail("Should have generated error");
+		} catch (JMeterError e){
+			
+		}
+		assertEquals("t2",f2.invoke(t2));
+		//assertEquals("t2",f2.invoke());
+		assertEquals("1a:aa.",f1a.invoke(t1a));
+		//assertEquals("1a:aa.",f1a.invoke());
+		try {
+		    f1a.invoke(t1);// can't call invoke using super class
+		    fail("Should have generated error");
+		} catch (JMeterError e){
+			
+		}
+		// OK (currently) to invoke using sub-class 
+		assertEquals("1a:aa.",f1.invoke(t1a));
+		//assertEquals("1a:aa.",f1.invoke());// N.B. returns different result from before
+	}
+    
+	public void testNameTypes() throws Exception{
+		Functor f = new Functor("getString",new Class[]{String.class});
+		Functor f2 = new Functor("getString");// Args will be provided later
+		Test1 t1 = new Test1("t1");
+		assertEquals("x1",f.invoke(t1,new String[]{"x1"}));
+		try {
+			assertEquals("x1",f.invoke(t1));
+		    fail("Should have generated an Exception");
+		} catch (JMeterError ok){
+		}
+		assertEquals("x2",f2.invoke(t1,new String[]{"x2"}));
+		try {
+			assertEquals("x2",f2.invoke(t1));
+		    fail("Should have generated an Exception");
+		} catch (JMeterError ok){
+		}
+	}
+	public void testObjectName() throws Exception{
+		Test1 t1 = new Test1("t1");
+		Test2 t2 = new Test2("t2");
+		Functor f1 = new Functor(t1,"getName");
+		assertEquals("t1",f1.invoke(t1));
+		assertEquals("t1",f1.invoke(t2)); // should use original object
+	}
+	
+	// Check how Class definition behaves
+	public void testClass() throws Exception{
+		Test1 t1 = new Test1("t1");
+		Test1 t1a = new Test1a("t1a");
+		Test2 t2 = new Test2("t2");
+		Functor f1 = new Functor(HasName.class,"getName");
+		assertEquals("t1",f1.invoke(t1));
+		assertEquals("1a:t1a.",f1.invoke(t1a));
+		assertEquals("t2",f1.invoke(t2));
+		try {
+			f1.invoke();
+			fail("Should have failed");
+		} catch (IllegalStateException ok){
+			
+		}
+		Functor f2 = new Functor(HasString.class,"getString");
+		assertEquals("xyz",f2.invoke(t2,new String[]{"xyz"}));
+		try {
+			f2.invoke(t1,new String[]{"xyz"});
+			fail("Should have failed");
+		} catch (JMeterError ok){
+			
+		}
+		Functor f3 = new Functor(t2,"getString");
+		assertEquals("xyz",f3.invoke(t2,new Object[]{"xyz"}));
+		
+		Properties p = new Properties();
+		p.put("Name","Value");
+		Functor fk = new Functor(Map.Entry.class,"getKey");
+		Functor fv = new Functor(Map.Entry.class,"getValue");
+		Object o = p.entrySet().iterator().next();
+		assertEquals("Name",fk.invoke(o));
+		assertEquals("Value",fv.invoke(o));
+	}
+	
+	public void testBadParameters() throws Exception{
+		try {
+			new Functor(null);
+			fail("should have generated IllegalArgumentException;");
+		} catch (IllegalArgumentException ok){}
+		try {
+			new Functor(null,new Class[]{});
+			fail("should have generated IllegalArgumentException;");
+		} catch (IllegalArgumentException ok){}
+		try {
+			new Functor(null,new Object[]{});
+			fail("should have generated IllegalArgumentException;");
+		} catch (IllegalArgumentException ok){}
+		try {
+			new Functor(String.class,null);
+			fail("should have generated IllegalArgumentException;");
+		} catch (IllegalArgumentException ok){}
+		try {
+			new Functor(new Object(),null);
+			fail("should have generated IllegalArgumentException;");
+		} catch (IllegalArgumentException ok){}
+		try {
+			new Functor(new Object(),null, new Class[]{});
+			fail("should have generated IllegalArgumentException;");
+		} catch (IllegalArgumentException ok){}
+		try {
+			new Functor(new Object(),null, new Object[]{});
+			fail("should have generated IllegalArgumentException;");
+		} catch (IllegalArgumentException ok){}
+	}
+	public void testIllegalState() throws Exception{
+		Functor f = new Functor("method");
+		try {
+			f.invoke();
+			fail("should have generated IllegalStateException;");
+		} catch (IllegalStateException ok){}		
+		try {
+			f.invoke(new Object[]{});
+			fail("should have generated IllegalStateException;");
+		} catch (IllegalStateException ok){}		
+	}
+}

Propchange: jakarta/jmeter/trunk/test/src/org/apache/jorphan/reflect/TestFunctor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/jmeter/trunk/test/src/org/apache/jorphan/reflect/TestFunctor.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: jakarta/jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/xdocs/changes.xml?rev=581687&r1=581686&r2=581687&view=diff
==============================================================================
--- jakarta/jmeter/trunk/xdocs/changes.xml (original)
+++ jakarta/jmeter/trunk/xdocs/changes.xml Wed Oct  3 11:55:38 2007
@@ -47,6 +47,11 @@
 <li>Test Plan items can now only be dropped/pasted into parts of the tree where they are allowed</li>
 </ul>
 
+<h4>Non-functional Improvements</h4>
+<ul>
+<li>Functor code tightened up; Functor can now be used with interfaces, as well as pre-defined targets and parameters.</li>
+</ul>
+
 <!--  ===================  -->
 
 <h3>Version 2.3</h3>



---------------------------------------------------------------------
To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org