Wednesday, October 25, 2006

Blocking IE7 "Security Upgrade"

Now that IE7 has been officially released from Microsoft, some of my colleagues tried it out. And not with that good results:
  • One machine had both browser installed after IE7, which it shouldn't have, but did not import Favourites from old browser
  • Another machine got a version of IE7 that keeps crashing all the time
Oh yeah, and there seems to be no way to go back to IE6 again.

Another thing is, that if you do nothing, Microsoft will simply force IE7 onto you by putting it out af a high-priority "security upgrade" through Windows Update. That sucks! Fortunately, a toolkit - actually released by Microsoft - will allow you to block that particular update.

Installed the toolkit, and will now go directly to installing the new Firefox 2.0 :-)

Monday, October 16, 2006

KISS principle applied to Tapestry pageflow

DISCLAIMER: The code described in this blog entry was actually done by my colleague Jacob von Eyben - not me. He is the inventor, designer and implementor! I just think you all should know about it too :-)

At my current work we are doing an agile project management tool for the web and I'm so lucky to be a developer on that. The technologies in that application are hibernate for the data access, spring for the model and businesslogic layer and tapestry for view layer. We are still stuck in tapestry 3 so the code examples will be from that version.

One of the things we've kind of missed when working with tapestry is a pageflow control mechanism. Something that could guide where to go next from an action. To my knowledge, there is no such thing to tapestry 3? What we did lately was invent a very simple design to make tapestry pages publish how to navigate to them. We like to think of the solution as "Tapestry pageflow following the KISS principle".

The design consist of 3 simple interfaces:
  • ForwardCallbackHandler - implementations are capable of navigating to a specific tapestry page
  • ForwardNavigator - pages implement this if they want to have an instance of a ForwardCallbackHandler get/set on it (basically, if it wants to be told how to navigate onwards after pages action have been taken)
  • ForwardCallbackProvider - pages implement this to construct ForwardCallbackHandler instances that can navigate back to that page (basically, if it wants to let others obtain a ForwardCallbackHandler instance that can navigate back to itself)
These interfaces are used in combination with a static method navigateTo(..., ForwardCallbackHandler handler) on each page that want to make public how others can navigate to it. The "..." in the method signature covers the state that the page needs to be able to navigate to itself. It could for instance be a UserStory instance, if the navigateTo method is on a ViewUserStoryPage page.

That's a lot of text, so let's see an actual example to make it more obvious what is going on. This example is taken from Plan B, and shows:
  • One page in the application is ViewIterationPage which shows iteration information like user stories assigned to iteration, time available in iteration, ...
  • Another page in the application is EditIterationPage which is a form where iteration related information can be edited
  • When user clicks "edit" action in ViewIterationPage, the code navigates to EditIterationPage and in the process gives to EditIterationPage an instance of a ForwardCallbackHandler - a handler that can navigate back to ViewIterationPage when edit action is done
  • When user clicks save in EditIterationPage, the callback handler stored on the page is activated to perform the navigation back to ViewIterationPage
Here's the code for ViewIterationPage:

public abstract class ViewIterationPage extends ... implements ForwardCallbackProvider {
class ViewIterationCallbackHandler implements ForwardCallbackHandler {
private Iteration iteration;
public ViewIterationCallbackHandler(Iteration iteration) {
this.iteration = iteration;
}
public void forward(IRequestCycle cycle) throws TapestryRedirectException {
ViewIterationPage.navigateTo(cycle, iteration);
}
}

public ForwardCallbackHandler getForwardCallbackHandler() {
return new ViewIterationCallbackHandler(getIteration());
}

public void editIteration(IRequestCycle cycle) {
EditIterationPage.navigateTo(cycle, getIteration(), getForwardCallbackHandler());
}
}

First thing to notice is that ViewIterationPage is a provider of ForwardCallbackHandler's (as a consequence of implementing ForwardCallbackProvider).

Second thing to notice is the inner class ViewIterationCallbackHandler that is responsible of navigating from somewhere back to ViewIterationPage. To be able to navigate to ViewIterationPage, it needs to be able to fullfil the contract of the ViewIterationPage.navigateTo() method, which expects a reference to the iteration that it is going to show. No problem, as the ViewIterationCallbackHandler is a class in its own, being able to hold a Iteration instance for just that and express the need for such state through its constructor.

Last thing to notice in the aboce code is the implementation of the editIteration action. This is the code executed when "edit" link is clicked on view iteration page. It simply navigates to EditIterationPage by calling its navigateTo method which clearly defines that it needs an iteration to edit and a callback handler to be able to know where to navigate to, when edit is done.

Left is there only to show the important code in EditIterationPage:

public abstract class EditIterationPage extends ... implements ForwardNavigator {
public static void navigateTo(IRequestCycle cycle, Iteration iterationToEdit, ForwardCallbackHandler forwarder) {
EditIterationPage page = (EditIterationPage) cycle.getPage(PageNames.PAGE_EDIT_ITERATION);
page.setIteration(iterationToEdit);
page.setForwardCallbackHandler(forwarder);
throw new TapestryRedirectException(cycle, page);
}

public void editIteration(IRequestCycle cycle) {
// .... action code here to validate and save edited information
getForwardCallbackHandler().forward(cycle);
}
}

First thing is EditIterationPage implementing ForwardNavigator which includes the methods getForwardCallbackHandler() and setForwardCallbackHandler(). A ForwardCallbackHandler is serializable, so we can simply define a property named forwardCallbackHandler in the pages .page file and even make it persistent.

In the navigateTo method the page is responsible for getting an instance of itself from the tapestry page pool and setting the state needed for render. Notice that it is setting the ForwardCallbackHandler as state.

Finally, in the editIteration action method the last thing performed is navigating to ... somewhere. EditIterationPage does not know which page it is navigating to or which state the navigated to page expects to be able to render. It simply obtains its reference to a ForwardCallbackHandler (which it can because it itself is a ForwardNavigator) and calls forward() method, giving the cycle on.

Wouv, in conclusion, ... maybe this isn't so KISS after all :-) But then again, it is. A page that navigates away to somewhere else does not have to know where to. It also does not have to remember any state to set on the page forwarded to. There's no extra pageflow configuration file setup with small state machines and the like. Simply code. There are many shortcomings of this design too, I'm sure. But I expect it to be more than enough for many Tapestry applications out there.

Good work Jacob!

Thinking about the dark side

All the time I've been serious about computers and programming (since I was a child), I've always been a *nix person. I started out using Slackware as my first *nix OS, and since then I've tried a lot of Linux distributions, but also worked on commercial ones like AIX and Solaris. I simply just love the powerfull command prompt with all the powerfull commands to get the job done.

Well, sometimes my work as a software consultant requires me to work with other platforms, mostly Windows. Some time ago, a customer required me to work on Windows, to develop a .Net based solution using Visual Studio, C#, ASP.NET, MSSQL Server etc.

In such situations I'm used to thinking: Let me get this done so that I can come back to a stable and powerfull development environment (some *nix). But this time, I'm thinking about wiping out my ubuntu installation and NTFS formatting it. Why is this?

Well, stuff just works in Windows. My primary computer is a (Dell) laptop. Making all the nice features in a laptop work in Linux/X-Windows is hard work. For instance the provider of the wifi card in the laptop has not made specifications public, hence the need for some serious shit like ndiswrapper to get wireless working, ... it should just work out-of-the-box, dammit!

Another problem is hibernation with my laptop. I want to close the lid and be off. And in the evening I want to open the lid and see everything as it was before. I specificly do not want a kernel panic.

Oh well, ... not all just works in windoze. Here's what I have to bear over with or try to find some solution to:
  • The command prompt just sucks. Period! Not even Windows Powershell (former Monad) can help on that one. Tried Cygwin combined with Poderosa, but Poderosa seemed to have too low quality and cygwin bash falls through too often when it has to battle the windows file system
  • I just seem to be click, click, click, clicking a lot more
  • Windows file system just sucks. It is damned slow when deleting large amounts of files (which I often do when simply doing "clean" when building my software) and boy do I just hate when windows tells me some file (not which file) is still open by someone (not who) and hence it cannot complete an unlink operation. Dude - I want the file gone!
Guess it is just a matter of time before I will shift back again, but for now, I'm on windows. That will also make it easier to explore the .Net platform a bit more. Never hurted anyone to know a little about the "the dark side" :-)