// Demo of hard-code and reflective proxies.
// In some places I have put a comment to
// indicate classes that would logically be public
// if I used more than one file

import java.lang.reflect.*;

/* public */
interface Foo
{
  void setValue( int x );
  int  getValue( );
}

/* public */
class FooFactory
{
  public static Foo allocateFoo( )
  {
    Foo f = new FooImpl( );
    
      // This is the call using old-style write your own
    // return new FooProxy( f );
    
      // Here is the call using Java 1.3 dynamic proxies
    return (Foo) Proxy.newProxyInstance(
                    Foo.class.getClassLoader( ),
                    new Class[] { Foo.class },
                    new FooHandler( f ) );
                   
      // Here is what the Java 1.3 is actually doing for you
    // return new GeneratedProxy( new FooHandler( f ) );
  }
  
  private FooFactory( ) { } // No FooFactory objects
}

class TestProxy
{
  public static void main( String[] args )
  {
    Foo f = FooFactory.allocateFoo( );
    f.setValue( 37 );
    System.out.println( "Foo value is " + f.getValue( ) );
  }
}


/* package visible */
class FooImpl implements Foo
{
  public void setValue( int x )
  {
    value = x;
  }
  
  public int getValue( )
  {
    return value;
  }
  
  private int value;
}

/* package visible */
class FooProxy implements Foo
{
  public FooProxy( Foo d )
  {
    delegate = d;
  }
  
  public void setValue( int x )
  {
    System.out.println( "Invoking setValue via hard coded proxy" );
    delegate.setValue( x );
  }
  
  public int getValue( )
  {
    System.out.println( "Invoking getValue via hard coded proxy" );
    return delegate.getValue( );
  }
  
  private Foo delegate;
}

/* package visible */
class FooHandler  implements InvocationHandler
{
  public FooHandler( Object d )
  {
    delegate = d;
  }
  
  public Object invoke( Object proxy, Method meth, Object[] args ) 
                        throws Throwable
  {
    System.out.println("Invoking " + meth.getName( ) + " via reflective proxy" );        
    return meth.invoke( delegate, args );
  }
    
  private Object delegate;
}

// Some stuff commented out because Proxy.getInvocation handler
// will notice that what is here  is a phony proxy.
// Commented out code is what really gets generated
/* public */
final class GeneratedProxy extends Proxy implements Foo
{
  public GeneratedProxy( InvocationHandler h )
  {
    super( h );
    handler = super.h;
  }

  public void setValue( int x )
  {
    Object ret = null;
    try
    {
      Method m = myClass.getMethod( "setValue", new Class[] { Integer.TYPE } );
      ret = handler.invoke( this, m, new Object[] { new Integer( x ) } );
    }
    catch( Throwable e )
    {
      if( e instanceof RuntimeException )
        throw (RuntimeException) e;
      if( e instanceof Error )
        throw (Error) e;
    }
  }
    
  public int getValue( )
  {
    Object ret = null;
    try
    {
      Method m = myClass.getMethod( "getValue", new Class[] { } ); 
      ret = handler.invoke( this, m, new Object[] { } );
    }
    catch( Throwable e )
    {
      if( e instanceof RuntimeException )
        throw (RuntimeException) e;
      if( e instanceof Error )
        throw (Error) e;
    }
    return ((Integer)ret).intValue( );
  }
  
  private InvocationHandler handler;
  private static final Class myClass = Foo.class;
}
