Saturday, 25. August 2007

mimicry in action II - dynamically implement an interface using Dynamic Proxy

this entry is the continuation of part 1, where we saw how to leverage Dynamic Proxy in order to let an object appear as if it would implement an arbitrary interface as long as it offers the same methods.

extensions

in this second part we'll extend the solution in order to map required methods of an interface to an object's methods, even if those methods partially bear another name (or offer sybtypes of the required arguments, even if they are placed in a different order).

a fluent interface

one fundamental goal is a simple and fluent api in order to support ease of use, allowing a simple and declarative style of usage - well, we'll see ...

for clarity, we will modify our example - imagine that class Foo has no longer a matching method echo(), but a method called reverb():

public class Foo {
    public String say( String msg ){
        return "foo said " + msg;
    }
    ...
}

now we want to (have to) map the required method echo() of interface IBar to reverb(). we'll start with thinking about a possible api extension and have some thoughts about it's implementation afterwards. a possible way to express the mapping could look like this:


barClient.speakTo(
  foo.as( IBar.class, map( "echo" ).to( "reverb" ) ) );
 

mapping method names

as you can see, we only extend the signature in order to push one (or more) mappings to the proxy, using a statically imported method map(). therefore we will use varargs in the following solution, so it's completely free to the client to apply as many mappings as needed:

public class InterfaceMimic
  implements InvocationHandler{

    public static <I> I mimic(
      Object bean,
      Class<I> asInterface,
      MethodMapping...mappings ){
        return
            (I) Proxy.newProxyInstance(
                bean.getClass().getClassLoader(),
                new Class[]{asInterface},
                new InterfaceMimic( bean, mappings ) );
    }
    
    public static MethodMapping map(
      String interfaceMethod ){
        return
          new MethodMapping( interfaceMethod );
    }
    
    private MethodMapping[] mappings =
      new MethodMapping[0];
   
    private Object proxee = null;
    
    public InterfaceMimic(
      Object proxee,
      MethodMapping...mappings ){

        this.proxee = proxee;
        this.mappings = mappings;
    }
    ...
}

we're not finished yet. you surely saw the new type MethodMapping, which now extends the signature of method mimic() (formerly as() ) as a vararg.

MethodMapping

this type will hold the whole information about the mapping. you also saw the static factory method map(), which will create a new instance of MethodMapping initializing it with the name of the method required by the interface. what's left is the mapping link to the method which have to be called on the object:

public class MethodMapping {

    private String interfaceMethod = null;
    private String beanMethod = null;
    
    public MethodMapping(
      String interfaceMethod ){
       
      this.interfaceMethod = interfaceMethod;
    }

    public MethodMapping to(
      String beanMethod, Class...argTypes ){
        this.beanMethod = beanMethod;
        return this;
    }

    protected boolean matches(
      Method method ){...}

    protected Object callMappedMethodOn(
      Object bean, Method method, Object[] args ) {...}
    ...
}

now we only have to extend the proxy in order to hold the mappings and ask if there's one when intercepting a method:

public class InterfaceMimic
  implements InvocationHandler{
...
    public Object invoke(
      Object proxy,
      Method method,
      Object[] args )
        throws Throwable {

        MethodMapping mapping =
          findMappingFor( method );
        
        return
            mapping != null ?
                mapping
                  .callMappedMethodOn(
                    proxee, method, args ) :
                callProxy( method, args );
    }

    private Object callProxy(
      Method method, Object[] args) {
        try {
            return
                proxee
                    .getClass()
                    .getDeclaredMethod(
                      method.getName(),
                      method.getParameterTypes() )
                    .invoke( proxee, args );
        }
        catch (Exception e) {
            throw new RuntimeException( e );
        }
    }

    private MethodMapping findMappingFor(
      Method method ){
        for( MethodMapping mapping : mappings ){
            if( mapping.matches( method ) )
              return mapping;
        }
        return null;
    }
}

as you can see, we first try to find a matching MethodMapping. if one exists, we call the mapped method on the object. if not, we try to call a method on the object with the same name as the required one. that's all.

of course you could now extend type MethodMapping in order to additionally gathering information about the argument types of the mapped method and / or their different order, like so:

// reorderArgs will show on the first position,
// to which argument position the first interface
// argument will map, and so on ...
foo.as(
  IBar.class,
  map( "add" )
    .to( "calc", BigDecimal.class, int.class, String.class )
    .reorderArgs( 3, 2, 1 ) ) ); 

i'll leave this exercise to you. it should be no big challenge at all. if you want to see one possible solution, take a look at the open source project Bricks4J. i comitted the complete source along with a unit test in the current cvs branch, which will show you the correct usage.

conclusion

as you now have seen, Dynamic Proxy is a valuable tool when it comes to mimic interfaces. you can easily make an object appear as if it would implement an interface, even if this object methods doesn't match exactly by name or argument types.
of course you'll face a trade off - sometimes it might by easier and more comprehensible simply to implement an adaptor for an interface than using a bulk of mappings. so it's up to you - as always - to choose the right 'weapon' ...

Posted by mario.gleichmann at 21:25:14 | Permanent Link | Comments (2) |

Saturday, 18. August 2007

mimicry in action - dynamically implement an interface using Dynamic Proxy

do you ever had that problem, that a class asks for a certain interface that your client class hasn't implemented, although all of the interfaces required methods are present in that class?

to make things clear, here's a little example:

first of all, here's a 'typical' interface (i deliberately use the prefix I to highlight that this one is an interface):

public interface IBar {
  public String echo( String s );
}

and here's a class, that will work with that interface:

public class BarCollaborator {
  public void speakTo( IBar bar ){
    System.out.println(
      "hello bar - " + bar.echo( "hello" ) );
  }
}

now you have a class Foo, that offers (by incident) a method with the same signature like the one required by the interface:

public class Foo {
  public String echo(String s) {
    return "foo " + s;
  }
}

although Foo accomplishes the contract of IBar, we can't apply an instance of Foo to BarCollaborator, because of the uncompatible types.

if you use a language like ruby, were a class doesn't rely on a certain type of a collaborator but rather on its interface (the methods an object offers - most of you will know that feature as 'duck typing': if it walks like a duck and if it talks like a duck than we will treat it like a duck), you certainly never will have a problem with that constellation.
but java is a different beast, using statically typed classes, where the type stays relevant during runtime. imagine if we could say something like this:

'apply this instance of Foo to BarCollaborator and make it appear as if it implements interface IBar'

in essence - something like

'use myFoo as IBar.class'

DynamicProxy to the rescue

well, this is possible - to a certain extend - with the help of a DynamicProxy. A DynamicProxy will 'mimic' a collection of interfaces (in this case we only need to mimic a single interface. in our conrete situation interface IBar ) to a client who will perform against those interfaces (in our concrete situation class BarCollaborator). when a client calls a method on that interface at runtime, the Proxy is called instead, having the chance to intercept the call and do whatever is necessery to complete it. regarding our context, we only try to detect the corresponding method on the target object (the instance of class Foo) and invoke it.

now here's the first simple implementation:

public class InterfaceBridgeProxy
  implements InvocationHandler {

  public static <T> T as( Class<T> asInterface, Object bean ){
    return
      (T) Proxy.newProxyInstance(
        bean.getClass().getClassLoader(),
        new Class[]{asInterface},
        new InterfaceBridgeProxy( bean ) );
  }

  private Object proxee = null;

  public InterfaceBridgeProxy( Object proxee ){
    this.proxee = proxee;
  }

  public Object invoke(
    Object proxy, Method method, Object[] args )
      throws Throwable {

    Method toInvoke = findMatchingMethod( method );
    return
      toInvoke != null?
        toInvoke.invoke( proxee, args ) : null;
  }

  private Method findMatchingMethod( Method method ){
    try {
      return
        proxee.getClass()
          .getDeclaredMethod(
            method.getName(),
            method.getParameterTypes() );
    }
    catch( Exception e) {
      return new RuntimeException(e);
    }
  }
}

now we can call BarCollaborator and apply an instance of Foo. using a static import for InterfaceBridgeProxy's static method as() will make the code a little more concise:

public static void main(String[] args) {
  BarClient barClient = new BarClient();
  Foo foo = new Foo();
  barClient.speakTo( as( IBar.class, foo ) );
}

of course we could apply a generic method as() directly to class Foo ...

public class Foo {
  public String echo(String s) {
    return "foo " + s;
  }

  public <T> T as( Class<T> interfaceMask ){
    return InterfaceBridgeProxy.as( interfaceMask );
  }
}

... making the example a little more readable:

  ...
  barClient.speakTo( foo.as( IBar.class ) )

the implemented functionality is general. now you are able to mimic an arbitrary interface for your collaborators, as long as your class offers the same methods required by the interface.

next time we will go one step further and see how to extend this mechanism to even map methods of your class to an interface which even has slightly different method names as long as the rest of the signature is matching.

stay tuned ... :o)

Posted by mario.gleichmann at 21:40:12 | Permanent Link | Comments (2) |

Wednesday, 15. August 2007

Are you pattern happy ?

i kept this secret deep inside of me for a long time. but now i can't stand any longer and so it must come out: yes ... i admit ... i was pattern happy ;o)

it startet soon after post-graduation at my first job as a consultant for a big it company. at that time i was half-baked with little experiance with respect to the design of software systems. but that should change! i wanted to be a good designer - a master designer! and deep inside of me i was afraid. afraid of producing bad design proposals. afraid that one could blame me for poorly designed software systems. and so i grabbed for every support that could help. at that time design patterns were a very hot topic. it looked like they should be the ultimate solution to all of my problems since it seems that those patterns conserved the wisdom and experiance of all those great developers - experiance that i could'nt exhibit at that time

the journey begins

and so i startet to study the gathered knowledge of the gang of four. i browsed the web. i bought books about patterns in java - volume 1 and 2 (and if there were volume 3 i had bought it, too), a book about patterns for J2EE development, architectural patterns, patterns in smalltalk (even i didn't know anything about the language at that time) - in essence patterns patterns patterns in order to compensate my inexperiance.
i startet to speak in patterns. that sounded professional and colleagues seemed to be impressed. whenever a task was given to me, i first of all tried to apply some matching patterns in order to solve the problem - it payed off when i used those pattern stereotypes inside of my uml diagrams that we had to create for our customers. yes - i was on my way to a rocking hell of a designer ...

what? me? pattern happy?

then - some day - i was meanwhile convident that a great knowledge of patterns means to be a good designer - i found another book about patterns that i had'nt heard of so far: 'Refactoring to Patterns' by Joshua Kerievsky.
it sounded (and still is) very good. it gave some considerably advices of how to apply refactorings in order to move your design to or towards well known patterns. that hit the spot for me! but wait - Joshua also talked about refactorings that moves away from patterns. i was puzzled! how could someone move voluntarily away from a pattern? then i read about 'Patterns Happy' for the first time and about the risk to over-engineer a design. could that be possible? could one over-engineer for a given problem? gentle doubt creeped in. i started to ruminate about the goal of design patterns and it hits me like a bolt from the blue: patterns aren't the goal - patterns are at most an instrument.
but if patterns are only the instrument, what are the right goals then? i started to realize a reasonable answer as i continued to read. Joshua gave a great example where it was obvious that you may lose sight of simpler ways to solve a problem. in this example a pattern based solution was applied to a small problem that - all in all - was more complicated than it needed to be. yes, the solution was very flexible, should there be future requirements. but it wasn't adequate for the given problem now and here. instead it introduced more complexity than needed so that the code wasn't simple any more, harder to read and took longer to understand.

goals

have you noticed it? the goals? simple, comprehensible code that is easy to understand (and maintain). those are surely valuable goals! and in the majority of cases it's a question of a trade off: upfront flexibility and a potential risk of a more complex code base on the one side and smaller, simpler, mostly better understandable code on the other.
and yes - as a pattern happy designer i ignored the deliberate decision for one side of those trade offs. i blindly followed the side of flexibility. not that it is the dark side, the easy side of the power per se. but i potentially was locked for the other side - i was blind for a perhaps more appropriate solution for a given problem space. yes - i was pattern happy!

how to recognize that you are pattern happy

following are some simple signs for an indication that you may be also pattern happy:

1. you cancel private events with friends because you preferably sit alone at home in your armchair and 'invent' some 'patterns'. yes, that's true. i heard of guys that are 'searching' for new patterns that they could proudly present to the pattern community.

2. 'pattern matching' almost works even at spare time.
'oh - you mean that i'm registering myself as an observer at your bookstore and you'll fire an event and give me a callback when the book arrives?
but why's the book still so expensive? is it a singleton or do you apply a special selling strategy in my case? hm, my internal state changed to doubt - perhaps i should visit all other stores in town that will apply to customers like me and collect their prices ...' ;o)

3. you'll use the ultimate 'big pattern hammer' even for the simplest tasks.
let me explain by a simple example. remember the fizzbuzz quiz? enumerate and print all numbers starting from 1 to 100. for all numbers that are divisible by three (without remainder) print 'fizz' instead of the number. for all numbers that are divisible by five print 'buzz'. should the number be divisible by three and five, print 'fizzbuzz'

here's a simple solution in java:

public void printFizzBuzzNumbers( int start, int end ){
    boolean fizz, buzz;
    for( int i=start; i<=end; i++ ){
        if( fizz = ( i%3 == 0 ) == true ) System.out.print( "fizz" );
        if( fizz = ( i%5 == 0 ) == true ) System.out.print( "buzz" );
        if( !( fizz || buzz ) ) System.out.print( i );
        System.out.println();
    }
}

if you should have a solution like the following hinted one in mind, you may be in slight, hard pressed to explain difficulties for your next simple design job:


public void printFizzBuzzNumbers( int start, int end ){
  // of course a singleton
 
SequenceFactory factory = SequenzeFactory.getFizzBuzzNumberInstance();
  // an internal iterator
  Sequence<FizzBuzzNumber> sequence = factory.sequenceFor( start, end );
  printNumbers( sequence );
}

public
void printNumbers( Sequence sequence ){
  finally StringWriterStrategy writer = new NewLineDecoratorWriter( new ConsoleWriter() );
  sequence.each( new ItemHandler
(){
    execOn( Number number ){
     
// a FizzBuzzNumber knows when to write 'fizz' or 'buzz' or ...
     
writer.write( number.toString() );
   
}
  });
}

ok - i may be pattern happy - and now?

meet the local support group. if it doesn't exist, found one and hope for like-minded people in your region.otherwise you're in big trouble.
no - seriously now. following are some guidelines that might help to find back to the right balance:

1. choose your instruments deliberately - become clear about the context of the given problem space and the intended goals.
what are the most valuated quality criterias?
is it flexibility over all? is it extensibility or reusability in different contexts? or is it simplicity, easy readability or clarity?
what are the intented goals und directions?
avoidance of code duplication? simplifying the complicated? communication of intention?
in which context will the solution be used?
is it a part of a core module that may stay stable for a long time? or is it used within a 'disposable' solution (maybe a prototype) where the code isn't the first benefit or of short relevance?
or is your surrounding work environment really agile, that management will give enough time for continous evaluation, continous refactoring and design evolution (avoiding the YAGNI syndrome)?

2. be rather pragmatic than dogmatic
this follows directly out of point one. don't be locked for only one possible way of a solution.
Don't blindly use patterns where a simpler solution is more appropriate.

3. don't turn of your brain!
this guideline applies actually for all kinds of activities you perform. as you've heard on other prominent location - there is no silver bullet. even not in the area of designing software. you can't turn of your brain and choose a pattern by reflex or by matching the forces of a given problem space. only the given goals and valued quality criterias will give the right direction. a solution that is perfectly right in one context might be completely over-engineered and inappropriate in another situation.

think!
maybe a pattern is the right choice.
maybe a simpler solution is the better choice.

Posted by mario.gleichmann at 20:04:13 | Permanent Link | Comments (3) |