DZone
Java Zone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
  • Refcardz
  • Trend Reports
  • Webinars
  • Zones
  • |
    • Agile
    • AI
    • Big Data
    • Cloud
    • Database
    • DevOps
    • Integration
    • IoT
    • Java
    • Microservices
    • Open Source
    • Performance
    • Security
    • Web Dev
DZone > Java Zone > Tapestry Mixins & ClassTransformations

Tapestry Mixins & ClassTransformations

Taha Siddiqi user avatar by
Taha Siddiqi
·
Aug. 04, 11 · Java Zone · Interview
Like (0)
Save
Tweet
4.44K Views

Join the DZone community and get the full member experience.

Join For Free

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/
Label Container Property (programming) Inheritance (object-oriented programming) Attribute (computing) Blog Implementation

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How to Configure Git in Eclipse IDE
  • What Is URL Rewriting? | Java Servlets
  • Role of Development Team in an Agile Environment
  • 10 Steps to Become an Outstanding Java Developer

Comments

Java Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • MVB Program
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

DZone.com is powered by 

AnswerHub logo