package plasticdemo.services; import java.lang.reflect.Method; import java.util.List; import org.apache.tapestry5.plastic.InstructionBuilder; import org.apache.tapestry5.plastic.InstructionBuilderCallback; import org.apache.tapestry5.plastic.PlasticClass; import org.apache.tapestry5.plastic.PlasticClassTransformer; import org.apache.tapestry5.plastic.PlasticField; import org.apache.tapestry5.plastic.PlasticManager; /** * Implementation of a ChainBuilder interface using Plastic */ public class ChainBuilderImpl implements ChainBuilder { private PlasticManager pm; /** * Constructor * @param pm plastic manager */ public ChainBuilderImpl(PlasticManager pm) { this.pm = pm; } /** * {@inheritDoc} */ @SuppressWarnings("unchecked") public <T> T build(Class<T> commandInterface, List<T> commands) { // Create a new class implementing this interface return (T) pm.createClass(Object.class, new ChainBuilderTransformer<T>(commandInterface, commands)).newInstance(); } static public class ChainBuilderTransformer<T> implements PlasticClassTransformer { private final Class<T> commandInterface; private final List<T> commands; public ChainBuilderTransformer(Class<T> commandInterface, List<T> commands) { this.commandInterface = commandInterface; this.commands = commands; } public void transform(PlasticClass pc) { // Implement the interface pc.introduceInterface(commandInterface); // Add a field which will be an array containing the commands final Object[] arrayOfCommands = commands.toArray(); final PlasticField arrayOfCommandsField = pc.introduceField(Object[].class, "_commands$" + commandInterface.getSimpleName()); arrayOfCommandsField.inject(arrayOfCommands); // For each method create chain for (Method method : commandInterface.getMethods()) { createChain(pc, arrayOfCommandsField, method); } } private void createChain(final PlasticClass pc, final PlasticField arrayOfCommandsField, final Method method) { pc.introduceMethod(method).changeImplementation(new InstructionBuilderCallback() { public void doBuild(InstructionBuilder builder) { builder.loadThis().getField(arrayOfCommandsField) .iterateArray(new InstructionBuilderCallback() { public void doBuild(InstructionBuilder builder) { builder.loadArguments().invoke(method); return; } }); builder.returnDefaultValue(); } }); } } }