1 / 64

Step-by-Step Legacy Migration with Aranea

Step-by-Step Legacy Migration with Aranea. Jevgeni Kabanov R&D lead, Aranea project lead Webmedia, Ltd. ekabanov@webmedia.ee. Motivating scenario.

elsiejames
Download Presentation

Step-by-Step Legacy Migration with Aranea

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Step-by-Step Legacy Migration with Aranea Jevgeni Kabanov R&D lead, Aranea project lead Webmedia, Ltd. ekabanov@webmedia.ee

  2. Motivating scenario “Stakeholders have a large web application written in Struts. They consider Struts legacy and want to continue development in JSF. However rewriting all of the code would take too much time, effort and money and would halt the ongoing development.“

  3. Our solution • Use Aranea webintegrationlayer to run different technologies side-by-side • Refactor the application into independent coarse-grained components • Start new development immediately and change old code only when requirements change – step-by-step migration

  4. Goal Get rid of legacy and custom web frameworks in your application

  5. Aranea • Aranea began as an Object-Oriented MVC Web Framework • From the onset we had plans to build web integration on the same platform • Aranea Integration has been released to public yesterday :)

  6. Disclaimer • Aranea MVC is stable and used in production • Aranea Integration is beta and used in pilot migration projects • Everything is Open-Source with documentation and support available for free from araneaframework.org • Commercial support/training/consulting is provided at araneaframework.com

  7. Organization • Aranea Component Model • Widgets • Flow navigation • Aranea Integration Layer • Struts, JSF, GWT • Step-by-step migration • Principles • Case study

  8. Aranea Component Model • Every component is a first-class object • Objects are created by the programmer • No (XML) mappings • State is in the object (no scopes) • Components, pages and flows are represented by first-classwidgets

  9. Hello World! NameWidget name.jsp Reads the name from requests and passes it to HelloWidget HelloWidget hello.jsp Renders the “Hello ${name}!” greeting, where name is given by the caller.

  10. NameWidget publicclass NameWidget extends BaseUIWidget { //Called on “hello” event publicvoid handleEventHello() { Stringname = //reads “name” from request parameters (String) getScopedData().get("name"); getFlowCtx().replace(new HelloWidget(name)); } } name.jsp: Insert your name: <input type=“text“ name=“${widgetId}.name"/><br/><br/> <ui:eventButton labelId="#Say hello" eventId="hello"/>

  11. HelloWidget publicclass HelloWidget extends BaseUIWidget { private String name;//Widget state is in its fields public HelloWidget(String name) { this.name = name; //We could pass any Java object here } public String getName() { returnthis.name; } public void handleEventBack() { getFlowCtx().replace(new NameWidget()); } } hello.jsp: Hello ${widget.name}! <br/> <ui:eventButton labelId="#Back" eventId="back"/>

  12. web.xml ... <servlet> <servlet-name>araneaServlet</servlet-name> <servlet-class>AraneaSpringDispatcherServlet</servlet-class> <init-param> <param-name>araneaApplicationStart</param-name> <param-value>example.NameWidget</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>araneaServlet</servlet-name> <url-pattern>/main/*</url-pattern> </servlet-mapping> ...

  13. Flows • Currently we use replace() which means: • A new instance is created every time • We know where to return Flow1

  14. Flows • What we would want is to preserve the instance and nest the new flow Flow1 Flow2

  15. Flows • start() and finish() do exactly that: public class NameWidget extends BaseUIWidget { ... public void handleEventHello() { ... getFlowCtx().start(new HelloWidget(name)); } } public class HelloWidget extends BaseUIWidget { ... public void handleEventBack() { getFlowCtx().finish(null); } }

  16. Including widgets • Widgets can be included, let’s try to use HelloWidget inside NameWidget like this HelloWidget handleEventHello() We assume that the “back” button was removed from HelloWidget

  17. Including widgets • First let’s modify the HelloWidget: publicclass HelloWidget extends BaseUIWidget { private String name; public HelloWidget(String name) { this.name = name; } public String getName() { returnthis.name; } publicvoid setName(String name) { this.name = name; } }

  18. Including widgets • Now let’s add a HelloWidget instance publicclass NameWidget extends BaseUIWidget { privateHelloWidget helloWidget; protectedvoidinit() { helloWidget = new HelloWidget("Stranger"); addWidget("hello", helloWidget); } publicvoid handleEventHello() { String name= (String) getScopedData().get("name"); helloWidget.setName(name); } }

  19. Including widgets • And finally we include the widget in the JSP <ui:widgetInclude id="hello"/><br/> Insert your name: <input type="text“ name=“${widgetId}.name"/><br/><br/> <ui:eventButton labelId="#Say hello" eventId="hello"/>

  20. Including widgets • So this is what we get: HelloWidget, helloWidget <ui:widgetInclude id=“hello”/> helloWidget.setName(“Jevgeni”)

  21. Widgets are objects • We can include several widgets of same class on one page publicclass RootWidget extends BaseUIWidget { protectedvoid init() { addWidget("hello1", new NameWidget()); addWidget("hello2",new NameWidget()); addWidget("hello3", new NameWidget()); } }

  22. Flows are objects • We can also include several flow containers on one page publicclass RootWidget extends BaseUIWidget { protected void init() { addWidget("flowContainer1", new StandardFlowContainerWidget(new NameWidget())); addWidget("flowContainer2", new StandardFlowContainerWidget(new NameWidget())); addWidget("flowContainer3", new StandardFlowContainerWidget(new NameWidget())); } }

  23. Goal Get rid of legacy and custom web frameworks in your application

  24. Our Solution • Use Aranea webintegrationlayer to run different technologies side-by-side • Refactor the application into coarse-grained integration components • Start new development immediately and change old code only when requirements change – step-by-step migration

  25. Requirements • We want to implement widgets using any framework/technology available • This can mean running a whole application in one widget and another application in its sibling • Without any changes to the technology • In fact we want to do that retroactively, reusing existing applications

  26. Aranea Integration Layer • Integration Layer API is based around widgets: • StrutsWidget, JsfWidget, GwtWidget • Widgets receive the URI of the starting point of the subapplication • E.g. new StrutsWidget(“/Welcome.do”); • AraneaUtil gives access to all of the Aranea API from embedded applications

  27. Struts Integration Problems • Session and request attributes share the same namespace and can clash • Request parameter names will clash already during form submission • Struts navigates between pages by changing the actual URL • HTML limits usage of some tags

  28. Problem 1: Attributes • We can make request attributes local, by wrapping HttpServletRequest and saving them in a local map • Since HttpSession can only be accessed via HttpServletRequest we can do the same thing to session attributes

  29. Problem 2: Parameters • Since parameter names clash already during the submission of request we need to solve the problem in HTML • We can do it by introducing prefixes to each field name referring to the containing widget • The request wrapper restores the original names

  30. Problem 3: Navigation • We put a filter over the Struts servlet that will include the Aranea servlet • While Aranea renders the particular StrutsWidget, it will include the according action • Therefore it will render in correct place as will everything else

  31. Problem 3: Navigation • However we need to include some information that is used to render Aranea • Servlet path • Window id • Current widget id • We do that by overriding encodeURL() in request wrapper

  32. Problem 4: HTML • There are two main things we need to change in Struts HTML output: • Forms cannot be nested and must be escaped • Field names must be prefixed • These are easy to change using a lexer (not even a parser) on the output stream • To escape forms we construct a JavaScript object with the same properties/methods

  33. name.jsp & hello.jsp <html> <body> <form method="get" action="<%=response.encodeURL("hello.jsp")%>"> <input name="name" type="text"/> <input type="submit" value="Say hello!"> </form> </body> </html> <html> <body> Hello ${param.name}! <a href="<%=response.encodeURL("name.jsp")%>">Back</a> </body> </html>

  34. HelloNameWidget & RootWidget publicclass HelloNameWidget extends StrutsWidget { public HelloNameWidget() { super("/name.jsp"); } } publicclass RootWidget extends BaseUIWidget { protectedvoid init() { addWidget("hello1", new HelloNameWidget()); setViewSelector("root"); } } Output: <input name="f0.hello1.name" type="text"/> <input type="submit" onclick=“new Aranea.Struts.Form(…).submit()" value="Say hello!">

  35. What will happen? publicclass RootWidget extends BaseUIWidget { protectedvoid init() { addWidget("hello1", new HelloNameWidget()); addWidget("hello2", new HelloNameWidget()); addWidget("hello3", new HelloNameWidget()); setViewSelector("root"); } } <ui:widgetInclude id="hello1"/><br/><br/> <ui:widgetInclude id="hello2"/><br/><br/> <ui:widgetInclude id="hello3"/>

  36. DEMO

  37. Generalizing Integration • The approach taken with Struts can be easily extended to any action-based framework • Including custom ones • In fact most of it is applicable to component-based frameworks as well • However component-based frameworks will usually allow us to solve these problems simpler

  38. JSF Integration • We use the same approach to encapsulate request and session attributes • Form fields can be prefixed by overriding the naming container (form) • Navigation can be solved by overridding the view handler • No postprocessing necessary!

  39. DEMO

  40. GWT Integration • Essentially the simplest, as almost everything happens on the client side • Two problems • Using RPC to call widget methods • Restoring client-side state after a full request • Not solved yet!

  41. Our Vision

  42. Goal Get rid of legacy and custom web frameworks in your application

  43. Our Solution • Use Aranea webintegrationlayer to run different technologies side-by-side • Refactor the application into coarse-grained integration components • Start new development immediately and change old code only when requirements change – step-by-step migration

  44. Refactoring • Enable Aranea Integration and sanitize HTML (produces working application) • Extract layout, menu and login • Split application into coarse-grained components

  45. Case Study • Estonian Tax Inspection application module • Connected with Forestry and European Union directives • Part of a large application family based on common architecture that manage all tax and customs needs

  46. Technologies • MVC web framework is Struts • Presentation done using Velocity and Tiles • A lot of custom extensions to all of them • SSO using Weblogic API

More Related