Legacy app that Plays with the future..

Enabling our legacy web application for the Future using The Play Framework

Some background

At work we have an old big web application written in some strange language originally running on a mainframe web server.

It’s kind of jsp-ish with just one big script for each page – not even close to MVC.

(Related post: Taking control over legacy code)

The application is constantly being extended so it has never been realistic to stop adding features while porting the hole application to a modern platform – and many of the developers like the JSP-feeling (just dump a new file and it works…)

Some years ago I wrote an emulator for that webserver in java (using extensive precompiling and an Open Source interpreterer). First the emulator had to be 100% backward compatible but then we switched off the mainframe webserver and only used the emulator – running in Tomcat on Windows (I know: Linux is better). We also added features to the language (like include files etc… 🙂 ) using precompiling.

The only solution I saw to make it possible to introduce modern technology in the application was to make it possible to gradually rewrite parts of the application – while the old and new parts of the app could communicate and work side by side.

Over the years I’ve created many solutions to enable our “script-kidies” to stop developing in the legacy language and start using java.. But I never got them to use it..

The Solution

In the fall of 2010 after attending JavaZone I had a breakthrough: Writing the new code in Java using the Play Framework.

Earlier today we upgraded our production environment to use the new legacy-play-integrated solution.

How we did it

As I said, all parts of the application has to be able to communicate – sharing state. The legacy application is statefull (read: session stored on server) – and the play part of the app is not.

I created an “external session store” (Lets call it ESS) – when the legacy app needs to store data in Session, it stores it in the ESS and only stores an ESS-id in the Real Session. This ESS-id is writen to a cookie.

Then when the browser accesses the play part of the application, either fullframe or using “DOM-injection” using JavaScript or using iframes, Play can read the ESS-id from the cookie (since both the legacy app-part and the play-app-part is using the same domain-namespace (fixed using reverse proxy)) – Then the play app can access the ESS server-side via REST and read/store data – In this way – both parts of the app can share data realtime server-side.

The “DOM-injection”-technique was the killer feature that made it possible to convince our Team leader that we should implement all the new functionality in Play.

It works like this: The legacy app renders the full page (with menus and stuff) leaving the “main part” empy with a <div>, then it uses JQuery to fetch a page from Play and injecting the returned DOM (read: HTML with embedded JavaScript) on that <div>. When the injected DOM is rendered, its embedded JavaScript/JQuery is executed. This way the page rendered in the users browser contains no iframes and it makes the “play-part” of the application/page totally contained. This resulted in the (partial) Play app being nice and simple using some java code server side and more HTML/JQuery client-side – since most of the backend systems served data as JSON via REST.

Conclusion

My feeling is that the development team is so happy with what the Play Framework gave us, that the only Legacy code being written in the future – is to disable old code – or linking to new functionality written in Play.

In the Future?

Maybe they can be convinced to ditch Java for Scala? I hope so..

4 Responses to Legacy app that Plays with the future..

  1. Olivier Refalo

    Hi,
    Good post, I was wondering if you could share the details of “external session store”, are you using a persistent store ? memcache ? do you handle caching somehow ?

    Thank you
    Olivier

  2. Here are some details about the external session store:

    It is “external” in the sens that HttpSession (servlet) is internal.

    The legacy app we’re integrating with (http://kjetland.com/blog/2010/02/taking-control-over-legacy-code/) or “modernizing” uses its own proprietary “session store” which I had to implement in the Emulator-server-software. Since the emulator runs on Tomcat, the natural place to store this “session store” was in HttpSession.

    The Play part of the application can not access these data – since the Play app would get its own instance of HttpSession if it would connect to Tomcat..

    We needed a simple solution to share data serverside between the two apps. Our only goal was to make it possible without much work and with easy integration into the old legacy app.

    This is how I did it technically:

    The emulator uses Spring . We have a SessionStoreRepository-singleton (SSR) stored in the Spring context. SSR stores multiple SessionStores (SS) in a hash-map. When requesting a new SS from SSR, the SS get a new unique GUID. This GUID is uses as key in the hash-map.

    The legacy app stores the GUID in HttpSession, not the SS. So when the legacy app must read/write to SS, it gets the GUID from HttpSession and gets the SS from SSR in each request.

    The GUID is also written to a cookie with path “/” so it is accessible in Play also.

    In the emulator app, I created a simple REST interface to SSR using JAX-RS.

    When Play needs to read/write data to communicate serverside with the legacy app, it reads the GUID from Cookie, then use the REST interface to communicate with SSR.

    Thats it..

    No caching at all – very simple – I just had to create something to convince the Boss that we would have no integration-problems if we started doing new stuff with Play.

  3. Forgot one thing:

    The webapp that holds the emulator and the SSR, registers a callback for when the HttpSession gets invalidated(timeout), so when this happens, I remove the SS-instance from SSR.

  4. olivier refalo

    just reading this now, thank you for the details

Leave a Reply

Your email address will not be published. Required fields are marked *