/* * AdapterClass.oj * * An OpenJava example to support programming with the Adapter pattern. * * @author Michiaki Tatsubori * @version %VERSION% %DATE% * @see java.lang.Object * * COPYRIGHT 1999 by Michiaki Tatsubori, ALL RIGHTS RESERVED. */ package examples.adapter; import java.lang.Object; import openjava.mop.*; import openjava.ptree.*; import openjava.syntax.*; /** * The metaclass AdapterClass supports classes * implementing an adapter role of the Adapter pattern. * The target's methods with same signatures as the adaptee's are * automatically implemented into the adapter class. *

* For example, the class VectorStack: *

 * public class VectorStack instantiates AdapterClass
 *    adapts Vector in v to Stack
 * {
 *    Vector v;
 *    public VectorStack( Vector v ) {
 *        this.v = v;
 *    }
 *    public void push( Object o ) {
 *        v.addElement( o );
 *    }
 *    public Object pop() {
 *        return v.removeElementAt( v.size() - 1 );
 *    }
 * }
 * 
* would be automatically implemented with the forwarding methods * size(), isEmpty(), hashCode(), etc, which are found in both * the class Vector(adaptee) and the class Stack(target). *

* * @author Michiaki Tatsubori * @version 1.0 * @since %SOFTWARE% 1.0 * @see java.lang.Object */ public class AdapterClass instantiates Metaclass extends OJClass { public static final String KEY_ADAPTS = "adapts"; /* overrides for translation */ public void translateDefinition() throws MOPException { OJClass target = getTarget(), adaptee = getAdaptee(); if (target == null || adaptee == null) return; /* implicit forwarding to the same signature's */ OJMethod[] adapteds = adaptee.getMethods( this ); for (int i = 0; i < adapteds.length; ++i) { /* picks up the method with same signature */ OJMethod m; try { m = getTarget().getMethod( adapteds[i].getName(), adapteds[i].getParameterTypes(), this ); } catch ( NoSuchMemberException e ) { /* not match */ continue; } /* generate a forwarding method with forwarded's name */ addMethod( makeForwardingMethod( m.getName(), m ) ); } addInterface( getTarget() ); } /** * Generates a forwarding method with specified name. * * @param name generating method's name. * @param forwarded method to which the generated method forwards. * @return a generated forwarding method. */ private OJMethod makeForwardingMethod( String name, OJMethod forwarded ) throws MOPException { /* generates a new method without body */ OJMethod result = new OJMethod( this, forwarded.getModifiers().remove( OJModifier.ABSTRACT ), forwarded.getReturnType(), name, forwarded.getParameterTypes(), forwarded.getExceptionTypes(), null ); /* generates a method call and return statement */ ExpressionList params = result.getParameterVariables(); Expression expr = new MethodCall( getContainer(), name, params ); StatementList body = new StatementList(); if (forwarded.getReturnType() == OJSystem.VOID) { body.add( new ExpressionStatement( expr ) ); body.add( new ReturnStatement() ); } else { body.add( new ReturnStatement( expr ) ); } result.setBody( body ); return result; } /* extended information */ private OJClass getAdaptee() throws MOPException { ObjectList suffix = (ObjectList) getSuffix( KEY_ADAPTS ); return OJClass.forName( suffix.get( 0 ).toString() ); } private Variable getContainer() throws MOPException { ObjectList suffix = (ObjectList) getSuffix( KEY_ADAPTS ); return new Variable( suffix.get( 1 ).toString() ); } private OJClass getTarget() throws MOPException { ObjectList suffix = (ObjectList) getSuffix( KEY_ADAPTS ); return OJClass.forName( suffix.get( 2 ).toString() ); } /* override to extend syntax */ public static boolean isRegisteredKeyword( String keyword ) { return keyword.equals( KEY_ADAPTS ); } /* override to extend syntax */ public static SyntaxRule getDeclSuffixRule( String keyword ) { if (keyword.equals( KEY_ADAPTS )) { return new CompositeRule( new TypeNameRule(), new PrepPhraseRule( "in", new NameRule() ), new PrepPhraseRule( "to", new TypeNameRule() ) ); } return null; } }