Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Tapestry Mixins & ClassTransformations

DZone's Guide to

Tapestry Mixins & ClassTransformations

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

Tapestry‘s Class Transformation can save you a lot of time and can show you clearly why it is better than inheritance most of the time. This blog has many examples of it. I just finished a new one. Here is the scenario. I want a label to have a title attribute(simple tooltip) which is to be fetched from the message catalog of the corresponding component/page. This is not that difficult, just create a mixin. But what if you want all labels to have this feature, even the ones you have no control over like the labels in BeanEditors.

Lets go step by step. First the mixin

public class HelpText {

    @InjectContainer
    private Component component;

    @Inject
    private Environment environment;

    @SetupRender
    void setupEnvironment(MarkupWriter writer) {

        final ValidationDecorator delegate = environment.peek(ValidationDecorator.class);
        Messages containerMessages = component.getComponentResources().getContainerMessages();

        environment.push(ValidationDecorator.class,
                new HelpTextValidationDecorator(delegate,  environment, containerMessages));

    }

}

This mixin just pushes our own ValidationDecorator implementation onto the Environment. Also note that we are passing Messages of the component’s container so that any component/page containing the label is able to use its property file.

public class HelpTextValidationDecorator extends ValidationDecoratorWrapper {

    private ValidationDecorator delegate;

    private Messages messages;

    private Environment environment;

    public HelpTextValidationDecorator(ValidationDecorator delegate,
        Environment environment, Messages messages) {
        super(delegate);

        this.delegate = delegate;
        this.messages = messages;
        this.environment = environment;

    }

    @Override
    public void insideLabel(Field field, Element labelElement){
        delegate.insideLabel(field, labelElement);

        String key = field.getClientId() + "-help";
        if(messages.contains(key)) {
            labelElement.attribute("title", messages.get(key));
        }

        ValidationDecorator currentDecorator = environment.peek(ValidationDecorator.class);
        if(currentDecorator == this){
            environment.pop(ValidationDecorator.class);
        }

    }
}

This decorator delegates every method call to the original decorator except for insideLabel() call which is called just after creating the opening tag of label. We add an attribute named title to the label tag. The content of the title is obtained from the message catalog of the components container. Finally we remove the decorator from the Environment.

Now that the mixin is in place, we need a way to add this mixin to every label. Here comes the magic, Class transformation. We implement ComponentClassTransformWorker.

public class HelpTextMixinWorker implements ComponentClassTransformWorker {

    @Override
    public void transform(ClassTransformation transformation, MutableComponentModel model) {

        if (Label.class.getName().equals(transformation.getClassName())) {

            model.addMixinClassName(HelpText.class.getName());

        }

    }

}

For Tapestry 5.3+, the code is a bit different

public class HelpTextMixinWorker implements ComponentClassTransformWorker2 {
   public void transform(final PlasticClass plasticClass,
        TransformationSupport support, MutableComponentModel model) {
        if (Label.class.getName().equals(plasticClass.getClassName())) {
            model.addMixinClassName(HelpText.class.getName());
        }
   }

}

Finally, remember to contribute this to the ComponentClassTransformWorker(ComponentClassTransformWorker2 in case of 5.3+) service.

@Contribute(ComponentClassTransformWorker.class)
public static void
        provideWorkers(OrderedConfiguration<ComponentClassTransformWorker> workers) {
    workers.addInstance("HelpTextMixinWorker", HelpTextMixinWorker.class);
}

 

From http://tawus.wordpress.com/2011/08/01/tapestry-mixins-classtransformations/

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}