Optimizing Tapestry 4 for development

Posted by Warner Onstine Fri, 02 May 2008 16:45:47 GMT

Periodically I will do small consulting gigs and recently had a client who wanted to know if there was a way that they could improve their development experience with Tapestry 4. Their specific problem lied in the fact that when they initially pulled up any Tapestry page it was incredibly slow to render that first time. They were not using the property org.apache.tapestry.disable-caching so that definitely wasn’t the issue.

The solutions that I came up with after doing some research and looking at their code were these:

  • Use Jetty for development
  • Convert as much of their pages (and components) to be “spec-less” as possible

Two primary reasons to use Jetty are that it allows you to more easily reload HTML changes and in general is a much more lightweight container than Tomcat, therefore getting an overall faster startup time and increasing development time. One of their own developers was already using Jetty and was seeing speed increases.

The primary reason to convert your HTML pages to be ”spec-less” (in other words no *.page file to bother with) is that reduces the overhead that Tapestry 4 puts into place to parse the XML file and figure out how all the components are wired together. Instead it puts this in either the HTML template, which it is already parsing, or in the Java class as an Annotation.

This also has the side benefit of prepping your code for converting up to Tapestry 5 as it uses no *.page files whatsoever.

Portal/Portlet work continues

Posted by Warner Onstine Sat, 29 Mar 2008 15:32:00 GMT

So I thought I’d update everyone on my progress so far with the Portal/Portlet component I’ve been working on, as well as some of the issues I’ve run into.

Normally I would have posted this to my Tapestry 101 blog but I’m going to try and consolidate my blogs together and I’m extremely tired of JRoller’s broken Textile formatting, such a pain in the ass (I have fallen in love with Markdown and code markup, it rocks!). I’ll be crossposting this, but soon I will stop updating the JRoller blog.

I now have a basic implementation of the Portal component complete and it consists of the following classes:

  • Portal.java - Stores a TreeSet of columns
  • Portal.html - Adds in the portlet controls div and some custom CSS stuff (which I’ll talk about shortly)
  • PortalColumn - Stores a TreeSet of Portlets plus some configuration for viewing (width and background color)
  • Portlet - Stores the Portlet title, content and it’s location
  • portal/scripts/
    • Portal.script - includes all the JavaScript files and does some dynamic stuff (coming up shortly)
    • prototype/scriptaculous scripts
    • portal_hooks.js - the hooks for the portal actions (close, move, etc.)
    • portal.js - the actual JavaScript for the portal functionality that can be called by the portal_hooks.js file
  • portal/css - portal.css
  • portal/images - all the images for the portal controls and rendering (rounded corners)

Ok, so that’s the basics here are some of the specifics.

Portal.script

<input-symbol key="columns" required="yes" />
<initialization>
 function init() {    
 portal = new Xilinus.Portal("#portal div", {onOverWidget: onOverWidget, onOutWidget: onOutWidget, onChange: onChange, onUpdate: onUpdate, removeEffect: Effect.SwitchOff}); 
   <foreach key="column" expression="columns">
    <foreach key="portlet" expression="column.portlets">
    portal.add(new Xilinus.Widget().setTitle('${portlet.title}').setContent('${portlet.content}'), ${column.index});
    </foreach>
   </foreach> 
   // Add controls buttons
   portal.addWidgetControls("control_buttons");
 }
 Event.observe(window, "load", init);
</initialization>

What I’m doing here is creating a new Portal (from Xilinus) and then I’m looping through each column and then each portlet inside of the column to add it’s content.

I dive into the hackish parts after the break.

Portal.html

This part contains some of the CSS hackish-ness I was hoping to avoid.

<span jwcid="@Script" script="Portal.script" columns="ognl:columns"/>
<div id="portal">
<div jwcid="@For" value="ognl:column" source="ognl:columns">

    <div jwcid="@Any" id="ognl:'widget_col_' + column.index" />
</div>
</div>

This first part just adds in the Portal.script and then declares the html div element we want to use (this element is used throughout the CSS and JavaScript files. The next piece loops over the TreeSet of columns and outputs one specially-named div for each column.

This just creates the HTML for the portlet controls (don’t know how customizable I’m going to make this yet).

Now comes the hack.

<style type="text/css">
<span jwcid="@For" value="ognl:column" source="ognl:columns" renderTag="false">
#widget_col_<span jwcid="@Insert" value="ognl:column.index"/> { 
  float:left;
  width: <span jwcid="@Insert" value="ognl:column.width"/>;  
  background:<span jwcid="@Insert" value="ognl:column.backgroundColor"/>;
}
</span>
#edit_button {
  background: url(<span jwcid="@Insert" value="ognl:editButton.buildURL()"/>);
}
#delete_button {
  background: url(<span jwcid="@Insert" value="ognl:removeButton.buildURL()"/>);
}
</style>

Here you see I had to do some inline styles so that I could add in some new attributes for the columns, as well as images for the control buttons. I posted a query to the mailing list about 2 weeks ago, asking if there was anything like RCSS (Ruby CSS) where you could actually use Ruby to generate CSS stylesheets - which is exactly what I need here.

After talking with Howard there did not appear to be any good way of going about doing this. One solution discussed was to let the user drop in a replacement stylesheet, but to me this seems silly, they don’t need to recreate the whole style sheet.

Another solution was to create a Tapestry page that acted like a CSS file. This still holds some promise, but is technically going to be a bear to implement due to the fact that we have to change the mime-type. The kicker in all of this though is that this isn’t going to be easier in Tapestry 5, at least not right away.

The other issue that I have with implementing this is what a pain it is to work with JavaScript in this environment and now I completely understand why it wasn’t really worked with before. Customizing the JavaScript that I need to output is a truly a pain, using XML to do my looping for me feels…wrong. If there are two areas I would like to contribute to these are it - making JavaScript and CSS more first-class citizens. Outputting HTML isn’t everything you do in a Web application.

What’s left?

Not quite done with this yet. I still have the following items to clear up:

  • Need to make the Portal, Portlet, and PortalColumn classes persistable
  • Once that’s done I need to modify the JavaScript hooks so that some kind of Ajax call happens whenever a user moves a portlet, adds or removes a portlet so that their selected portlets are saved in the database
  • Need a new Page so that a user can see all possible portlets to add to their custom page
    • For this page was kind of thinking of doing a slick sliding door effect, dunno yet
  • Add in some further customizations
  • Replace default button images with ones that are easier to read/understand and fit with our internal scheme a bit better (these are customizable)

I’m trying to get this code Open-Sourced, so it may take a little bit to get this code available but it shouldn’t be too much of a problem (and we have some other cool little items we’re going to release as well - just need to clean them up).

New Job! 1

Posted by Warner Onstine Tue, 26 Feb 2008 18:25:42 GMT

Late last year I decided, kind of on a whim, to look around for a new job. I contacted one of my friends and former managers to see if they had any opportunities at VMS. It turned that while they weren’t actively advertising they were looking for people so I submitted my resume plus some of the code that I had done recently.

VMS is an interesting company that looks boring on the surface but are doing some really interesting things. They are basically a marketing company that collects advertising and news for clients. This extends to all types of media (print, TV, radio, etc.) so this has some interesting challenges for data collection and for presenting that data to users in ways that make sense to them.

VMS’s primary platform of choice is currently Tapestry 4 so that makes me happy on a number of levels. While I haven’t done any Tapestry work here yet I look forward to it very shortly.

When I started Scott mentioned that they were also looking for someone to do some UI work for them and that they really liked their last UI person who did a lot of wireframing mockups - which is something I’ve had a lot of experience with. After talking with Scott we decided to have me to half-time UI work and half-time regular programming, which I think fits in to my overall goals of where I want to go. I have been a strong advocate of Usability for a long time but have never had it be part of my job so I am very thrilled to be doing this. Plus it’s a nice change of pace :-).

I will also be looking at some of our stuff to see if we can leverage Groovy in any way (from DSLs to just plain making our jobs easier) and I look forward to evaluating Tapestry 5 soon.

New project "Chama"

Posted by Warner Onstine Fri, 08 Dec 2006 05:50:00 GMT

So, where has all this DSL stuff been leading? One of my projects that has been sitting on the back-burner for a while has been Chama. Chama was born out of the frustration of writing the same boiler-plate code over and over for database-backed sites that are run on Tapestry. While you can certainly use something like Trails I was not happy with the additional amount of configuration I needed to do in order to get the forms to look and behave the way I wanted them to.

Why not use Ruby on Rails then, or even Grails if I want to stick with the Java theme?

A variety of reasons:

  • I'm familiar with Tapestry, Hibernate, etc.
  • I'm very familiar with Java
  • I want to learn Groovy as a language
  • I don't want to switch out my deployment options to have to deal with deploying my apps to a new server and having to configure it all over again so that it'll run RoR
  • I like generators ;-), no really this is an exercise that I want to undertake and if others find value in it that's great
  • Mostly to make it easier for me to get some app ideas I've had off of the ground

What will Chama use:

  • Groovy as the primary language, with some Java thrown in where needed
  • Most likely Yaml for configuration with JYaml for dealing with it
  • Quite possibly several DSLs for each area (Model, View, Controller)

I don't know yet exactly how far I'm going to take Chama, mostly I just want to get a tool together that will help me build stuff. If others find value in it and it gets extended from there and heads in a direction I never thought about, great! All the code will be available under an Apache License once I start working on stuff. I have some tentative dates setup in my Trac instance (what?! using Python for a Java app?). Comments are welcome, and I will use this blog to announce releases as they happen, the first milestone is set for 12/22/06 (oops was tomorrow, moving to two weeks, wow it's been two weeks since I first set this up already).