Tapestry Training -- From The Source

Let me help you get your team up to speed in Tapestry ... fast. Visit howardlewisship.com for details on training, mentoring and support!

Monday, May 31, 2010

Tapestry Happenings: 5.2 beta soon?, New Committers, Dynamic component

There's lots and lots going on with Tapestry right now. We're gearing up to bring Tapestry 5.2 into a beta phase ... hopefully a short one before a final GA release.

We've been busy adding new committers to the team. Not every vote has been successful, but that just shows that the system works.

Lots of people are working on a terrific refresh of the Tapestry home page and documentation. Not just new text, but a new more timely approach (based on Confluence) and a terrific new layout. Just lots of energy going on there. I can't wait for it to be ready ... it really makes Tapestry looks like the first-class citizen it is.

Meanwhile, I've been busy for my clients, writing some useful code.

I've managed to get the nightly builds of the TapX working again ... just in time. I've created an exciting new component: Dynamic.

Dynamic is targeted for use in skinning applications. Tapestry's structure makes skinning an application a little tricky, especially if you want to take a standard application and customize it for different customers. Tapestry templates are expected to be uniform across all instances of a component (in the same way that a classes's methods and fields are fixed across all instances). This makes it tricky to create a component that renders differently for different users, which is the essence of skinning. Often, you end up either simulating a JSP include and injecting a blob of raw markup content into the Tapestry DOM ... or you end up with an evil nest of conditionals and indirection.

The Tapx Dynamic component exists to mix a dynamic template file with live Tapestry components; The dynamic template is any well-formed XML document that can be represented as a Resource; mostly, it is output as-is ... until Tapestry hits an element, such as a <div>, with a special id. When the id is of the form param:block-name, the Dynamic component replaces the dynamic template element with the content of the Block parameter passed to the Dynamic component. We're really weaving Tapestry and the external template together here.

I'm working on a good, simple example here ... but anyone who has struggled with this issue will appreciate what Dynamic accomplishes. It's not unlike running SiteMesh at the Tapestry component level.

4 comments:

Soddino said...

Hi Howard,

It sounds great on Dynamic component!
What do you thing if 'template' parameter is a kind of Tapestry template? By that way, we easily add any components like If, Loop.... into the template.

It seems imposable with Tapestry when it works on the principle 1: "Static Structure, Dynamic Behavior"

In our project, we use FreeMarker as a template because it is helpful when controlling code flow with If, Switch, List... statement.

And the Dynamic component code simple as below:

public class Dynamic {
@Parameter(defaultPrefix=BindingConstants.ASSET, required=true)
private Asset template;

@Inject
private ComponentResources resources;

@Inject
private FreeMarkerService freeMarkerService;

private String outputText;

void setupRender() throws Exception {
Object model = resources.getContainer();
ByteArrayOutputStream output = new ByteArrayOutputStream();
freeMarkerService.mergeDataWithResource(template.getResource(), output, model);
outputText = output.toString("UTF-8");
}

boolean beginRender(MarkupWriter writer) {
writer.writeRaw(outputText);

return false;
}
}

Unknown said...

@Soddino

What the real Dynamic component does is render the external template just as if it were a Tapestry template, in terms of creating a DOM from it. And it caches the intermediate representation in memory until the external file changes (just like with Tapestry templates). Using something like Freemarker can also be good but serves a different purpose, and it would be very hard to merge live Tapestry content into the middle of a Freemarker template. Tapx/Dynamic does do that.

I won't be adding any complex control structures to dynamic templates, but I am considering adding support for Template expansions, as per Tapestry templates. Thye just won't be quite as efficient.

Soddino said...

Thank you for your reply, Howard.

The main idea that I wish Tapestry have one model (Component class) and many presentations (Component templates).

See an example, we have an application with 3 main functions:
1. Defining a Content Structure
For example, we define Article structure with TITLE, SUBTITLE, HOT_NEWS, PARAGRAPH1, PARAGRAPH2... fields

2. Inputting contents
System will generate a dynamic form to input content for a Content Structure.
We use Tapestry to generate the form with full Tapestry form validation. Thank Tapestry, it works so great!

3. Creating Content Templates (multi-templates) and render it
In the Content Template, the Contents is the model. We can make for Article type something like:
- Loop all ARTICLE contents, put each ARTICLE in a DIV. In template 1, the DIV have RED background color, and BLUE in template 2.
- If HOT_NEWS=true, bold the TITLE and BLUE color in template 1, but RED in template 2.
- Add Comment Form skin 1 in template 1, Comment Form skin 2 in template 2.
- bla bla...

We wished can use Tapestry template to do this task but it's failed (we must use FreeMarker template as I explained in previous comment)
And I think your Dynamic component also could not adapt in this case, even you add Template expansions. Right?

(sorry for my not native English)

Unknown said...

Hi Howard,
can you please provide an example of using Display component?