Pebble 2.0.0 RC2 on Java 1.4

Home, Bangkok, Thailand, 2006-11-09 00:14 +0700

#infrastructure

My site ran on Pebble 1.9 for several months until I noticed it was leaking memory and running up to 99% CPU - a Very Bad Thing when you share a host with dozens of other users. I decided to upgrade to Pebble 2, which targets Java 1.5, but the host I have has 1.4, and I couldn’t put a 1.5 JDK up there, so I had to get Pebble 2 to run on 1.4.

TimeZone Weirdness

As I was testing Pebble 2.0.0 RC2 for the first time I noticed that it now allows you to specify the timezone per blog entry which I think is fantastic as I am currently living in Thailand and have old blog posts from Australia, Japan, Cambodia and Thailand.

While I was playing around creating some test entries, I noticed that some postings were losing an hour from the time I entered. Because I had done an upgrade rather than create a new blog, I hadn’t gone into the Blog Properties page of my blog to set the timezone, and Pebble defaults to London, which from March to October is at GMT+1 due to daylight saving.

The timezone you enter in Blog Properties is what Pebble stores your entries under, and is also the zone you must use when you enter entries. Because my blog has postings from different timezones, I chose GMT as the most logical commonly applicable timezone, but this means that when I enter a blog posting, I have to subtract the GMT offset from the time for the zone I’m blogging from. Selecting the right timezone on the blog entry then causes Pebble to add that offset back on.

With the new feature of per-posting timezones, the blog-level timezone setting doesn’t really make sense anymore, and I suspect Simon will probably refactor that out of the model for the final release, or at least make it just the overridable defalt for blog postings. There’s no reason now for blog entries to be stamped with anything other than UTC time. If you are blogging from just one timezone you wouldn’t notice this wrinkle.

Monolithic Templates

The only criticism I have of Pebble is that it wants to own all requests going through your servlet container, and tends to be rather monolithic in the UI tier. All requests are rendered via a single template.jsp which uses server-side includes (yuck) to pull in chunks of UI. This is how 1.x worked, and I was hoping 2.x would blow all that away but it’s the same.

It would be beautiful if Pebble provided a Tiles-style decomposition of it’s UI elements that could be assembled into whatever form you like. A suite of custom tags could be another approach. This would mean Pebble could be integrated into a website, rather than the other way around.

For my site, one of the things I want to do is show the most recent blog entry in full on the left, with other recent entries shown in summary on the right. The standard Pebble templates don’t allow me to do that, so I have to go and modify the JSP templates and put in my own logic checks. I’d love to be able to throw a <pebble:latestentries mode=”full” /> tag on the left and a <pebble:recententries startat=”1” /> tag on the right.

Having everything routed through a single set of JSP templates also means you have to be very careful when customzing because, for example, changes you make for blog entry rendering could affect the appearance of the admin pages.

Java 1.4

Java 1.5 is not forwards compatible with 1.4, but not backwards compatible. This means if you have 1.4 classes, you can run them on 1.5, but not the other way around. Pebble’s source code uses a number of 1.5 features, most notable generics which is all through the code, so it must be compiled with Java 1.5.

One option would be to go through the code and re-write all the generics stuff to use 1.4 compatible code and then compile it with JDK 1.4. Aside from the labour involved in this approach, there is a lot of room for accidently busting something while changing the code. Pebble now has a pretty decent test suite, so that would provide some security, but taking the re-write option would mean that if some bug cropped up down the track, you wouldn’t be able to be sure that it was from the original code or the 1.4 hacked version.

I started looking around for a tool that could automate the process of re-writing 1.5 code to be 1.4 compatible when I happened across Retroweaver. This open-source tool takes classes compiled with Java 1.5, manipulates the bytecode to be 1.4 compatible, and provides the 1.5 features in a compatibility library. It sounded like a good solution for my requirements. There is still the possibility of some exotic bug creeping in as a result of the bytecode changes, but as it’s the same source code it’s possible to cross-check for any bugs using non-manipulated classes in a 1.5 environment.

With the Retroweaver distro (2.0 Beta 2) downloaded and unpacked, I altered the compile target in Pebble’s build.xml to include a call to the Retroweaver task:

<target name="compile" depends="init">
  <property name="project.classpath" refid="project.classpath" />
  <echo message="Using CLASSPATH of ${project.classpath}" />

  <javac srcdir="${src.dir}" destdir="${classes.dir}" debug="yes">
    <classpath refid="project.classpath" />
  </javac>

  <!-- Retroweave the 1.5 classes to be 1.4 compatible -->
  <property name="retroweaver.home"
    value="G:/tmp/retroweaver-2.0Beta2" />

  <taskdef name="retroweaver"
    classname="net.sourceforge.retroweaver.ant.RetroWeaverTask">
    <classpath>
      <fileset dir="${retroweaver.home}/lib" includes="**/*.jar"/>
      <fileset dir="${retroweaver.home}/release" includes="**/*.jar"/>
    </classpath>
  </taskdef>

  <retroweaver srcdir="${classes.dir}" />

</target>

With that in place, I did a clean build. The retroweaver messages seend to indicate that all was well:

compile:
    [javac] Compiling 381 source files to E:\wrk\pebble-2.0.0-RC2\build\classes
    [javac] Note: Some input files use unchecked or unsafe operations.
    [javac] Note: Recompile with -Xlint:unchecked for details.
[retroweaver] Processing 391 classe(s)
[retroweaver] 391 classe(s) weaved.

So I replaced the pebble-2.0.0-RC2.jar in my deployed Pebble instance with the new one containing the retrowoven classes. I also dropped the Retroweaver runtime library which provides the 1.5 compatibility into my Pebble instance’s WEB-INF/lib directory.

With the modified code in place, I started my Tomcat 5.5 container still using JDK 1.5. My Pebble site worked fine including navigating pages, logging in and editing.

Next I shut down Tomcat 5.5 and moved my Pebble webapp from to another 5.5 container which has the JDK 1.4 compatibility pieces added. I launched that container, again still using JDK 1.5. Again all seemed to be fine.

Finally I shutdown Tomcat, switched my JAVA_HOME to point at a JDK 1.4, and started Tomcat up again. Success! All my articles look right, my templates look right, and I can login and edit blog entries.

Using my retrowoven Pebble JAR, I am now running Pebble 2.0.0 RC2 on Java 1.4 on my Windows laptop, and on my Open BSD public host.