You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@avalon.apache.org by Berin Loritsch <bl...@apache.org> on 2002/10/03 06:55:14 UTC

Wanting delegates

Delegates are the key to programming intelligent agents--such as the type
that would be needed to determine the best set of components for an
assembly file.  The proper matching can be performed with generic search
algorithms that use specific methods as parameters to the search algorithm.

I decided that it would be relatively easy to throw together an inheritance
based Delegate mechanism.  The class is in Excalibur Util along with an example
in the TestCase.

There are some limitations to the Delegate mechanism:

1) the Object must be accessible to the org.apache.excalibur.util package
    (which means that the object is public).

2) the method must be public--no other access level will even be considered.

3) The method cannot be named the same as any of the standard Object methods.

These are out of necessity and the way the reflection package works.
The reason the method names cannot be the same as any standard Object method
is that there is no other way to determine what method the Delegate needs
to implement.


-- 

"They that give up essential liberty to obtain a little temporary safety
  deserve neither liberty nor safety."
                 - Benjamin Franklin


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Wanting delegates

Posted by Berin Loritsch <bl...@apache.org>.
Leo Sutic wrote:
> 
>>From: Berin Loritsch [mailto:bloritsch@apache.org] 
>>
>>Delegates are the key to programming intelligent agents--such 
>>as the type that would be needed to determine the best set of 
>>components for an assembly file.  The proper matching can be 
>>performed with generic search algorithms that use specific 
>>methods as parameters to the search algorithm.
>>
>>I decided that it would be relatively easy to throw together 
>>an inheritance based Delegate mechanism.  The class is in 
>>Excalibur Util along with an example in the TestCase.
>>
>>There are some limitations to the Delegate mechanism:
>>
>>1) the Object must be accessible to the 
>>org.apache.excalibur.util package
>>    (which means that the object is public).
> 
> 
> Seems reasonable.
>  
> 
>>2) the method must be public--no other access level will even 
>>be considered.
> 
> 
> Seems very reasonable.
> 
> 
>>3) The method cannot be named the same as any of the standard 
>>Object methods.
> 
> 
> Seems reasonable.
>  
> 
>>These are out of necessity and the way the reflection package 
>>works. The reason the method names cannot be the same as any 
>>standard Object method is that there is no other way to 
>>determine what method the Delegate needs to implement.
> 
> 
> Berin, 
> 
> I am +1 for exploring this. But I think a scratchpad is the proper 
> place for it. I don't like your implementation as it is now and
> I'm -1 on putting it into excalibur/util in the state it is now.

Util is a scratchpad.


> A delegate is basically a method pointer. I assume that the
> difference between calls via a delegate a through an interface
> is that you can name the method anything you want.

Yes and no.  A delegate is a way of treating a Method like an
Object.  The end result is similar, but the implications are
different.

The implementation as it is now (I threw it together last night
at midnight) is the beginning.  What would be perfect is something
backed by BCEL so that all we have to do is "create" a new keyword.

If I had a line like this:

delegate MyDel = new delegate String echo( String );

then I would be able to have a new delegate class created on the
spot with the face:

String answer = MyDel.echo( "message" );

Of course, something along the lines of a proxy factory would be
worth exploring.

> 
> Therefore, when creating a delegate, you should be able to name
> the method:
> 
> interface Interface {
>   void delegate (); // This can be anything. It is the signature of the
>                     // delegate method.
> }
> 
> class MyClass {
> 
>   void myMethod () {
>     // The method I want to delegate to.
>   }
> 
>   void doDelegation {
>     Interface myDelegate = 
>         (Interface) Delegate.newDelegate (this, "myMethod", Interface);
> 
>     myDelegate.delegate (); // Calls myMethod.
>   }
> 
> }
> 
> The Delegate.newDelegate creates a proxy etc...
> 
> This means code will be like this:
> 
> public class Button {
> 
>   public interface OnPressedHandler {
>     public void action ();
>   }
> 
>   OnPressedHandler onPressed = null;
> 
>   public void delegatePressedEventFromAWT () {
>     onPressed.action ();
>   }
> 
>   public void setOnPressed (OnPressedHandler handler) {
>     onPressed = handler;
>   }
> }
> 
> 
> public class ButtonUser {
> 
>   Button button1 = new Button ();
>   Button button2 = new Button ();
> 
>   public void onButton1 () {
>     // ---
>   }
> 
>   public void onButton2 () {
>     // ---
>   }
> 
>   public void setup () {
>     button1.setOnPressed (
>         (Button.OnPressedHandler) Delegate.newDelegate 
>             (this, "onButton1", Button.OnPressedHandler));
> 
>     button2.setOnPressed (
>         (Button.OnPressedHandler) Delegate.newDelegate 
>             (this, "onButton2", Button.OnPressedHandler));
>   }
> }
> 
> Warning: I have no idea if the above is feasible. (I have not
> implemented it yet.) But I think so.
> 
> /LS
> 
> 
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>
> 


-- 

"They that give up essential liberty to obtain a little temporary safety
  deserve neither liberty nor safety."
                 - Benjamin Franklin


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Wanting delegates

Posted by Berin Loritsch <bl...@apache.org>.
Leo Sutic wrote:
> Berin,
> 
> this is what I want:


I'll see what I can do :)

> 
> 
> 
> import java.lang.reflect.*;
> import java.util.*;
> 
> /**
>  * Interface for events. See the Button class below for example of use.
>  */
> interface Event {
>     public void register (Object o);
>     public void deregister (Object o);
> }
> 
> /**
>  * Creates events (multicast delegates)
>  */
> class EventFactory {
>     
>     static class EventHandler implements InvocationHandler {
>         
>         private ArrayList handlers = new ArrayList ();
>         private Method registerMethod;
>         private Method deregisterMethod;
>                 
>         public EventHandler () {
>             try {
>                 registerMethod = Event.class.getDeclaredMethod
> ("register", new Class[] { Object.class });
>                 deregisterMethod = Event.class.getDeclaredMethod
> ("deregister", new Class[] { Object.class });
>             } catch (Exception e) {
>                 // If this happens we've had a severe error somewhere.
>                 throw new Error (e.toString ());
>             }
>         }
>         
>         public Object invoke(Object proxy, Method method, Object[] args)
> throws Throwable  {
>             System.out.println ("EventHandler invocation: " +
> method.getName ());
>             if (method.equals (registerMethod)) {
>                 handlers.add (args[0]);
>                 return null;
>             } else if (method.equals (deregisterMethod)) {
>                 handlers.remove (args[0]);
>                 return null;
>             } else {
>                 Iterator iter = handlers.iterator ();
>                 while (iter.hasNext ()) {
>                     method.invoke (iter.next (), args);
>                 }
>                 
>                 // As events are multicast, the only allowed return
> value is void.
>                 
>                 return null;
>             }
>         }
>     }
>     
>     public static Event newEvent (Class delegateInterface) {
>         return (Event) Proxy.newProxyInstance
> (delegateInterface.getClassLoader (),
>             new Class[]{ Event.class, delegateInterface }, new
> EventHandler () );
>     }
>     
> }
> 
> /**
>  * Creates delegates.
>  */
> class DelegateFactory {
>     
>     static class DelegateHandler implements InvocationHandler {
>         
>         private final Object instance;
>         private final Method delegateMethod;
>         
>         public DelegateHandler (Object instance, String methodName) {
>             this.instance = instance;
>             
>             // Right now we only test on method name.
>             // This could be extended to test on delegate 
>             // method signature.
>             
>             Class instanceClass = instance.getClass ();
>             Method[] methods = instanceClass.getDeclaredMethods ();
>             Method method = null;
>             for (int i = 0; i < methods.length; i++) {
>                 if (methods[i].getName ().equals (methodName)) {
>                     method = methods[i];
>                 }
>             }
>             this.delegateMethod = method;
>         }
>                 
>         public Object invoke(Object proxy, Method m, Object[] args)
> throws Throwable {
>             return delegateMethod.invoke (instance, args);
>         }
>     }
>     
>     public static Object newDelegate (Object instance, String
> methodName, Class delegateInterface) {
>         return Proxy.newProxyInstance (delegateInterface.getClassLoader
> (),
>             new Class[]{ delegateInterface }, new DelegateHandler
> (instance, methodName) );
>     }
>     
> }
> 
> // -------------------- Test Code
> 
> class Button {
>     
>     interface Delegate {
>         public String action ();
>     }
>     
>     public Event multicast = EventFactory.newEvent (Delegate.class);
>     public Delegate unicast = null;
>     
>     public void fireMulticast () {
>         ((Delegate) multicast).action ();
>     }
>     
>     public void fireUnicast () {
>         String result = ((Delegate) unicast).action ();
>         System.out.println ("Result from unicast is " + result);
>     }
> }
> 
> public class Hack {
>     
>     public String myFirstEventHandler () {
>         System.out.println ("In myFirstEventHandler.");
>         return "myFirstEventHandler";
>     }
>     
>     public String mySecondEventHandler () {
>         System.out.println ("In mySecondEventHandler.");
>         return "mySecondEventHandler";
>     }
>     
>     public String myDelegate () {
>         System.out.println ("In myDelegate.");
>         return "delegate";
>     }
>     
>     public void run () {
>         Button button = new Button ();
>         
>         button.multicast.register (DelegateFactory.newDelegate (this,
> "myFirstEventHandler", Button.Delegate.class));
>         button.multicast.register (DelegateFactory.newDelegate (this,
> "mySecondEventHandler", Button.Delegate.class));
>         
>         button.unicast = (Button.Delegate) DelegateFactory.newDelegate
> (this, "myDelegate", Button.Delegate.class);
>         
>         button.fireMulticast ();
>         button.fireUnicast ();
>     }
>     
>     public static void main (String[] args) {
>         new Hack ().run ();
>     }
> }
>  
> 
> 
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>
> 


-- 

"They that give up essential liberty to obtain a little temporary safety
  deserve neither liberty nor safety."
                 - Benjamin Franklin


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: Wanting delegates

Posted by Leo Sutic <le...@inspireinfrastructure.com>.
Berin,

this is what I want:



import java.lang.reflect.*;
import java.util.*;

/**
 * Interface for events. See the Button class below for example of use.
 */
interface Event {
    public void register (Object o);
    public void deregister (Object o);
}

/**
 * Creates events (multicast delegates)
 */
class EventFactory {
    
    static class EventHandler implements InvocationHandler {
        
        private ArrayList handlers = new ArrayList ();
        private Method registerMethod;
        private Method deregisterMethod;
                
        public EventHandler () {
            try {
                registerMethod = Event.class.getDeclaredMethod
("register", new Class[] { Object.class });
                deregisterMethod = Event.class.getDeclaredMethod
("deregister", new Class[] { Object.class });
            } catch (Exception e) {
                // If this happens we've had a severe error somewhere.
                throw new Error (e.toString ());
            }
        }
        
        public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable  {
            System.out.println ("EventHandler invocation: " +
method.getName ());
            if (method.equals (registerMethod)) {
                handlers.add (args[0]);
                return null;
            } else if (method.equals (deregisterMethod)) {
                handlers.remove (args[0]);
                return null;
            } else {
                Iterator iter = handlers.iterator ();
                while (iter.hasNext ()) {
                    method.invoke (iter.next (), args);
                }
                
                // As events are multicast, the only allowed return
value is void.
                
                return null;
            }
        }
    }
    
    public static Event newEvent (Class delegateInterface) {
        return (Event) Proxy.newProxyInstance
(delegateInterface.getClassLoader (),
            new Class[]{ Event.class, delegateInterface }, new
EventHandler () );
    }
    
}

/**
 * Creates delegates.
 */
class DelegateFactory {
    
    static class DelegateHandler implements InvocationHandler {
        
        private final Object instance;
        private final Method delegateMethod;
        
        public DelegateHandler (Object instance, String methodName) {
            this.instance = instance;
            
            // Right now we only test on method name.
            // This could be extended to test on delegate 
            // method signature.
            
            Class instanceClass = instance.getClass ();
            Method[] methods = instanceClass.getDeclaredMethods ();
            Method method = null;
            for (int i = 0; i < methods.length; i++) {
                if (methods[i].getName ().equals (methodName)) {
                    method = methods[i];
                }
            }
            this.delegateMethod = method;
        }
                
        public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
            return delegateMethod.invoke (instance, args);
        }
    }
    
    public static Object newDelegate (Object instance, String
methodName, Class delegateInterface) {
        return Proxy.newProxyInstance (delegateInterface.getClassLoader
(),
            new Class[]{ delegateInterface }, new DelegateHandler
(instance, methodName) );
    }
    
}

// -------------------- Test Code

class Button {
    
    interface Delegate {
        public String action ();
    }
    
    public Event multicast = EventFactory.newEvent (Delegate.class);
    public Delegate unicast = null;
    
    public void fireMulticast () {
        ((Delegate) multicast).action ();
    }
    
    public void fireUnicast () {
        String result = ((Delegate) unicast).action ();
        System.out.println ("Result from unicast is " + result);
    }
}

public class Hack {
    
    public String myFirstEventHandler () {
        System.out.println ("In myFirstEventHandler.");
        return "myFirstEventHandler";
    }
    
    public String mySecondEventHandler () {
        System.out.println ("In mySecondEventHandler.");
        return "mySecondEventHandler";
    }
    
    public String myDelegate () {
        System.out.println ("In myDelegate.");
        return "delegate";
    }
    
    public void run () {
        Button button = new Button ();
        
        button.multicast.register (DelegateFactory.newDelegate (this,
"myFirstEventHandler", Button.Delegate.class));
        button.multicast.register (DelegateFactory.newDelegate (this,
"mySecondEventHandler", Button.Delegate.class));
        
        button.unicast = (Button.Delegate) DelegateFactory.newDelegate
(this, "myDelegate", Button.Delegate.class);
        
        button.fireMulticast ();
        button.fireUnicast ();
    }
    
    public static void main (String[] args) {
        new Hack ().run ();
    }
}
 


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: Wanting delegates

Posted by Leo Sutic <le...@inspireinfrastructure.com>.
And Berin, with Proxies you can have C# events as well...

Think a delegate that has an array of delegates that it calls.

> > From: Berin Loritsch [mailto:bloritsch@apache.org] 


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: Wanting delegates

Posted by Leo Sutic <le...@inspireinfrastructure.com>.

> From: Berin Loritsch [mailto:bloritsch@apache.org] 
> 
> Delegates are the key to programming intelligent agents--such 
> as the type that would be needed to determine the best set of 
> components for an assembly file.  The proper matching can be 
> performed with generic search algorithms that use specific 
> methods as parameters to the search algorithm.
> 
> I decided that it would be relatively easy to throw together 
> an inheritance based Delegate mechanism.  The class is in 
> Excalibur Util along with an example in the TestCase.
> 
> There are some limitations to the Delegate mechanism:
> 
> 1) the Object must be accessible to the 
> org.apache.excalibur.util package
>     (which means that the object is public).

Seems reasonable.
 
> 2) the method must be public--no other access level will even 
> be considered.

Seems very reasonable.

> 3) The method cannot be named the same as any of the standard 
> Object methods.

Seems reasonable.
 
> These are out of necessity and the way the reflection package 
> works. The reason the method names cannot be the same as any 
> standard Object method is that there is no other way to 
> determine what method the Delegate needs to implement.

Berin, 

I am +1 for exploring this. But I think a scratchpad is the proper 
place for it. I don't like your implementation as it is now and
I'm -1 on putting it into excalibur/util in the state it is now.

A delegate is basically a method pointer. I assume that the
difference between calls via a delegate a through an interface
is that you can name the method anything you want.

Therefore, when creating a delegate, you should be able to name
the method:

interface Interface {
  void delegate (); // This can be anything. It is the signature of the
                    // delegate method.
}

class MyClass {

  void myMethod () {
    // The method I want to delegate to.
  }

  void doDelegation {
    Interface myDelegate = 
        (Interface) Delegate.newDelegate (this, "myMethod", Interface);

    myDelegate.delegate (); // Calls myMethod.
  }

}

The Delegate.newDelegate creates a proxy etc...

This means code will be like this:

public class Button {

  public interface OnPressedHandler {
    public void action ();
  }

  OnPressedHandler onPressed = null;

  public void delegatePressedEventFromAWT () {
    onPressed.action ();
  }

  public void setOnPressed (OnPressedHandler handler) {
    onPressed = handler;
  }
}


public class ButtonUser {

  Button button1 = new Button ();
  Button button2 = new Button ();

  public void onButton1 () {
    // ---
  }

  public void onButton2 () {
    // ---
  }

  public void setup () {
    button1.setOnPressed (
        (Button.OnPressedHandler) Delegate.newDelegate 
            (this, "onButton1", Button.OnPressedHandler));

    button2.setOnPressed (
        (Button.OnPressedHandler) Delegate.newDelegate 
            (this, "onButton2", Button.OnPressedHandler));
  }
}

Warning: I have no idea if the above is feasible. (I have not
implemented it yet.) But I think so.

/LS


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>