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: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to