Frame2 and MacOS X

Currently, Frame2 does not work on Macs. This, of course, is due to the fact that there is no (easily) available Java 6 implementation for MacOS. I’ve been trying to decide if this is an issue or not.

Reasons why it might be an issue:

  • I use a Mac for most of development, and I hate having to drop into an emulator to work on Frame2
  • I really would like Frame2 to run on the Mac, if just for completeness.

Reasons why it probably doesn’t matter:

  • Who really runs Java webapps on Macs? Tomcat on Windows or Linux is OK, but it just feels dirty to me on the Mac.

Hopefully, there will be a version of Java 6 available for the Mac soon. At that point, I’ll probably make the necessary updates to make everything work. Until then, if you’re writing a web app and using a Mac - go with Rails.

Build Web Services with the Plugin

The Eclipse plugin has just been updated, and a new plugin has been added to the mix. The new plugin allows users to create Frame2 projects with web services support by adding all of the required libraries and initial configuration. Also in the new plugin are two wizards: one for creating new Responders and one for creating Schema mappings. The Getting Started guide has also been expanded to explain how to add web services support to the example application.

Again, the Update Manager site is the preferred method for downloading the plugins, since it will gracefully handle version and dependency conflicts.

Update Site for Eclipse:
http://frame2.megatome.com/eclipse

Sourceforge Downloads:
Main Eclipse Plugin
Web Services Eclipse Plugin (requires at least version 1.3.3 of the regular plugin)

Eclipse Plugin Nearly Ready

As the title says, the Eclipse plugin for Frame2 is almost done. Of course, “done” is a relative term. In this case, it means that the plugin has been updated to work with the latest version of the framework, including the updated DTD. Unfortunately, it also means that it still has the same limitations that previous versions have had. Specifically, the plugin still does not support creating a Frame2 project with web services support. This can be added by hand and the Frame2 plugin won’t stomp on it, but neither are there any nice wizards for the web services tasks. This limitation is the next item on my list - I’m pretty sure that I can create an optional plugin that can be downloaded that will add the web services functionality for anyone that wants it. This will also help keep the download size of the “core” plugin as small as possible.

One other feature that the plugin is missing is a contextual editor for the Frame2 configuration file. It would nice to be able to get contextual help and hints when editing the config by hand, but I don’t think I have the time in the forseeable future to research how this works in Eclipse.

The plugin will be available for download from Sourceforge and I will be creating an update site here at frame2.megatome.com that will be the preferred way of getting the plugin.

Version 1.3 is Released

Version 1.3 of Frame2 is officially available. The framework can be downloaded here, and the sample applications are available here.

Work on the Eclipse plugin continues, with a (hopeful) release date in the next week or two.

Adding Features Uncovers Old Bugs

This seems to happen to me no matter what project I’m on. I try to implement a simple (or not so simple) feature and end up exposing at least one bug that’s been hiding around for quite some time.

As an illustration, I was adding a feature to Frame2 today to allow some parameters to be passed between events within a mapping - without making developers use the HttpSession. After a couple of false starts, I had a pretty good idea of how to make the changes and starting ripping out code. I came up with several unit tests, and modifying code to make the tests pass. Pretty standard Test Driven Development…until I wrote the test that made sure event chain validation was working.

Before I explain the bug, I’ll give a high level description of how Frame2 works when submitting form data:

  1. Form is filled out by user and submitted.
  2. Frame2 looks up the appropriate event from the form action.
  3. An instance of the appropriate event is created and populated by the introspector.
  4. Based on the mapping for the event, Frame2 will then validate the event. This may involve the Commons Validator if it is enabled and/or overriding the Event.validate() method.
  5. If validation fails, the mapping must specify a location for the framework to forward back to. This is usually the same page where the data was entered.
  6. If validation passes, the framework then iterates through the list of event handlers, calling the handle() method. If handle() returns null, the framework continues to the next handler. A non-null result usually indicates an error, and the framework will forward to the location named by the result.
  7. Once all of the handlers have been invoked, the framework will default to the view specified in the mapping. Usually this is just a JSP, but Frame2 supports forwarding to events - called “chaining”.
  8. For the chained event, Frame2 is supposed to start back at step 2 and continue processing until it gets to the end of the chain.

Notice how I say “supposed to” in step 9? The framework was actually only going back to step 6, bypassing validation for all events except the first in the chain. Subtle, yes, and unlikely to be noticed by most users - but it’s still a bug. The bug has now been fixed so that the framework goes back to step 2 like it’s supposed to.

In case you’re wondering what use event chaining is, here’s an example:

  1. User enters a blog entry and submits the form.
  2. Frame2 validates the form data and begins invoking handlers.
  3. The blog entry handler persists the data, perhaps to a database.
  4. The default view for the event mapping tells the framework to forward to the “View All Blog Entries” event.
  5. The framework creates the appropriate object and begins invoking the handlers in the “View All” mapping.
  6. The “View All” handler populates all of the blog entries into the “View All” event.
  7. The default view for the “View All” mapping is a JSP page, which renders the blog entries using JSTL.

Chaining allows the “View All” event to remain its own entity that can be invoked separately, while allowing the same functionality to be used in other places where appropriate.

By way of comparison, the feature I added allows the above sequence to be reworked like this:

  1. User enters a blog entry and submits the form.
  2. Frame2 validates the form data and begins invoking handlers.
  3. The blog entry handler persists the data, perhaps to a database.
  4. The blog entry handler sets an attribute with the new entry id into the context.
  5. The default view for the event mapping tells the framework to forward to the “View Specific Blog Entry” event.
  6. The framework creates the appropriate object and uses the context value(s) with the introspector to set some values in the event.
  7. The framework then begins invoking the handlers in the “View Specific” mapping.
  8. The “View Specific” handler looks up the entry with the specified id and sets its data into the event.
  9. The default view for the “View Specific” mapping is a JSP page, which renders the blog entry using JSTL.

Approaching the Finish Line

Frame2 is almost ready to be released as a new version. I may still make some changes, but it’s definitely in Release Candidate stage now. There are only a few things that I may add before testing the heck out of it:

  • Upgrade unit tests to JUnit 4. There are a lot of tests, especially the ones that mock a servlet container, that do a lot of repetitive work in setUp() . JUnit 4 has finally brought the ability to annotate methods to be run before and after all tests in the class with @BeforeClass and @AfterClass, respectively. Individual test setup activities can still be performed by annotating a method with @Before.
  • Fix outstanding bugs. There’s only one right now, and it’s SOAP specific, so I may or may not fix it. It may take me longer to figure out how to reproduce the problem with unit tests than it’s worth.
  • Add outstanding feature requests. Again, there’s only one, but it’s (in my opinion) a biggie - the ability to add parameters to the response when handling an event.
  • Doc updates. The web services doc needs to be written, and I’m sure all of the other doc needs a good examination.

I’ll be testing the latest build with a web application that I’ve been working on for years that I’ve come to think of as an unofficial reference implementation of Frame2. I haven’t decided yet if the web app should become part of the project on Sourceforge or not. We’ll see.

Once the testing is done and I’ve released a new version of Frame2, I plan on working on the Eclipse plugin. The poor plugin has pretty much been ignored for several years now, and it needs some attention.

A Consistent API is a Very Good Thing

I’ve been mucking around in the codebase, cleaning up pieces of the API that annoy me. Some bright person thought that it was a good idea to have a method that returns an Iterator to access a collection. I’ve been cleaning up all of these methods, changing them so that they return an actual collection - occasionally made unmodifiable through the Collections class.

Naturally, this has led to unit test failures. Almost all of the failures have been easy to fix, but once in a while one pops up that makes me scratch my head. Here’s an example:

public void testGetIfEmpty() {
assertTrue(this.errors.isEmpty());
assertNull(this.errors.get(FOO));
assertEquals(0, this.errors.get().length);
assertEquals(0, this.errors.get(FOO).length);
}

In this instance, errors is a class that aggregates individual Error objects. The get(String) method returns an array of Error objects that have the specified key, while get() retrieves all Errors. Pretty simple, right? After my changes, the test fails on the assertNull() statement, which isn’t surprising.

The failing statement read assertNull(this.errors.iterator(FOO)) before I removed the iterator() method, which tells us a bit about how the API was originally coded. The iterator(String) returned null if there were no matching entries. However, as the unit test clearly shows, get(String) returns an empty array when it doesn’t find any matching Errors. Quite the difference, and potentially confusing - the developer has to remember which method may return null.

The API has now been changed to return an empty collection instead of null when no matching errors are found. Now, a user of the API simply has to call the method and loop over the result (zero times if it’s empty) without having to make null checks.

Whoever wrote this unit test obviously knew that one method returned null while the other returned an empty array for the same input, since the test passed. I only wish that person would have looked at those lines and noticed the inconsistency, instead of leaving it for me to find.

FindBugs Is Even Cooler Than I Thought

I’ve mentioned before that I’m using FindBugs to help make sure that the Frame2 code is up to snuff. The Eclipse compiler can catch a lot of things, bug FindBugs has some neat tricks up its sleeve to find things that Eclipse can’t. FindBugs uses static analysis of the code to search for patterns that indicate possible issues. Being the Type A person that I am, I always turn on all of the possible matches and whittle the list down. Quite often, however, FindBugs will find a false positive or two. Up until now, I’ve either tried to rework the code to avoid the warning or disabled the category altogether. I’ve never liked the approach of turning off a whole category just to avoid seeing a warning or two, so I spent the morning muttering to myself how useful it would be if FindBugs allowed me to ignore certain warnings like I can do with @SuppressWarnings.

Then I went and RTFM.

FindBugs has a filtering system that makes @SuppressWarnings look amateur. Here’s an example: in the SoapRequestProcessor, FindBugs marked a warning that an Exception was being caught when no Exception was being thrown. After looking at the code and verifying that the try block in question throws several different exceptions, I created a filter entry. The entry looks like this:

<Match>
<Class name="org.megatome.frame2.front.SoapRequestProcessor"/>
<Method name="getEvents"/>
<Bug pattern="REC_CATCH_EXCEPTION"/>
</Match>

This tells FindBugs to match a specific bug type in a specified method in a desired class. This entry can be used in both an inclusion or exclusion filter - I use it to exclude that warning from the results.

Here’s a more complex example:

<Match>
<Class name="~.*introspector\.Bean\d+" />
<Bug pattern="EI_EXPOSE_REP,EI_EXPOSE_REP2"/>
</Match>

There are some test classes that don’t exactly follow good rules of programming when it comes to dealing with mutability. Since they are test classes, I don’t really care to fix them. Instead I set up the filter to match all classes in an introspector package named Bean1, Bean2, etc. Simple as can be!

If you aren’t using FindBugs, you should be. Go check it out.

Unit Testing Web Applications is a Pain

I’ve finally reached the point where I hurdled my JAXB related validation issues, so another round of full unit testing is called for. Frame2 has two levels of testing:

  1. Unit tests that can be run outside of a servlet container. These include simple tests on discreet sections of the framework, and some tests written using (ironically) StrutsTestCase to simulate a servlet container.
  2. Tests that require a live servlet container. These include the TagUnit tests for checking the custom tag libraries and the Cactus tests that verify tag behavior.

The JAXB functionality is tested mainly through the first set of tests. However, as anyone who’s built a web app can attest, things work differently in a container. In this case, I’m talking specifically about loading resources. Using a getClass().getResourceAsStream() works just fine from the Ant console, but returns null when run within Tomcat. The solution, of course, is to use the ServletContext to load the resource, but obviously it’s not available when running outside of the container.

The simple solution was change the loading code to try to get at the ServletContext first, then fail to the getResourceAsStream() call. The best solution would be to refactor the appropriate unit tests so that they use the mock servlet structure - but I’m lazy today and mock objects can be quite tedious. Don’t get me wrong - I have nothing against mock objects. I would just rather get a new release of Frame2 out the door before devoting a lot of time to rewriting the test infrastructure, which is something most end users won’t care about.

JAXB: Good, Bad and Ugly

One of the biggest tasks in updating Frame2 is making sure the web services components still work. This integration was one of the major features when Frame2 was orginally developed as TurboM2 - at the time it was something that really set it apart from Struts.
I’ll be honest and say that I never had that strong of a grasp on the web services side of Frame2. As long as the unit tests kept passing, I didn’t really care. Now, however, as I muck about in the guts of the system, I’ve really come to appreciate the advances that have been made in JAXB in the last several years. That’s not to say it’s been an entirely painless process, though. Here’s what I’ve found so far:
Good

  • The JAXB Reference Implementation (RI) included with Java 6 has been greatly overhauled. The number one improvement I’ve enjoyed is the reduced number of generated files. In one case, there are now 4 files where older versions of JAXB created 35-40.
  • All of the required support jars are part of Java 6. No more downloading and installing the Web Services Developer’s Kit - not to mention repackaging it. Huge savings in space and dependencies.

Bad

  • If a schema import creates multiple classes, all of those classes extend the specified superclass. There is no either/or. For the purposes of Frame2, classes created from schemas need to extend JaxbEventBase in order to work correctly with the framework. In most cases, however, only the root element needs to extend JaxbEventBase. JAXB only allows inheritance on an all or nothing basis, so it can introduce confusion with trying to use objects that technically have the right interface, but logically should be separated.
  • JAXB schema imports create an ObjectFactory class than can be used to create other items from the schema. Unfortunately, this class is not as generic as I’d like - Frame2 tries to do a lot of generic introspection and not having a good all purpose factory has led me to write some creative code.

Ugly

  • With previous versions of JAXB, Frame2 was able to perform on-demand validation of objects against the schema. This mechanism has been superceded in favor of using Schema objects for validation. The old validation mechanism is still around, but it;s marked deprecated and optional. Apparently in Java 6, “optional” means “blows up”. Trying to create an instance of the on-demand validator throws an UnsupportedOperationException. Trying to enable validation in the JAXB unmarshaller yields the same results. Unexpected results from an “optional” operation!
  • The Frame2 JAXB infrastructure is one of those areas of the code I should spend more time in. Most of it hasn’t been touched since the product was named TurboM2, and I’m not convinced the TM2 guys followed “best” or even “pretty good” practices.