step-by-step legacy migration with aranea jevgeni kabanov r&d lead, aranea project lead...

64
Step-by-Step Legacy Migration with Aranea Jevgeni Kabanov R&D lead, Aranea project lead Webmedia, Ltd. [email protected]

Upload: charlotte-small

Post on 20-Jan-2016

216 views

Category:

Documents


0 download

TRANSCRIPT

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

Step-by-Step Legacy Migration with Aranea

Jevgeni KabanovR&D lead, Aranea project leadWebmedia, Ltd.

[email protected]

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

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.“

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

Our solution

1. Use Aranea web integration layer to run

different technologies side-by-side

2. Refactor the application into independent

coarse-grained components

3. Start new development immediately and

change old code only when requirements

change – step-by-step migration

Page 4: Step-by-Step Legacy Migration with Aranea Jevgeni Kabanov R&D lead, Aranea project lead Webmedia, Ltd. ekabanov@webmedia.ee
Page 5: Step-by-Step Legacy Migration with Aranea Jevgeni Kabanov R&D lead, Aranea project lead Webmedia, Ltd. ekabanov@webmedia.ee
Page 6: Step-by-Step Legacy Migration with Aranea Jevgeni Kabanov R&D lead, Aranea project lead Webmedia, Ltd. ekabanov@webmedia.ee
Page 7: Step-by-Step Legacy Migration with Aranea Jevgeni Kabanov R&D lead, Aranea project lead Webmedia, Ltd. ekabanov@webmedia.ee
Page 8: Step-by-Step Legacy Migration with Aranea Jevgeni Kabanov R&D lead, Aranea project lead Webmedia, Ltd. ekabanov@webmedia.ee

Goal

Get rid of legacy and custom

web frameworks in your

application

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

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 :)

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

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

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

Organization

Aranea Component Model

• Widgets

• Flow navigation

Aranea Integration Layer

• Struts, JSF, GWT

Step-by-step migration

• Principles

• Case study

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

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-class widgets

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

Hello World!

NameWidgetname.jspReads the name from requests and passes it to HelloWidget

HelloWidgethello.jspRenders the “Hello ${name}!” greeting, where name is given by the caller.

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

NameWidget

public class NameWidget extends BaseUIWidget { //Called on “hello” event public void handleEventHello() { String name = //reads “name” from request parameters (String) getScopedData().get("name"); getFlowCtx().replace(new HelloWidget(name)); } }

Insert your name: <input type=“text“ name=“${widgetId}.name"/><br/><br/> <ui:eventButton labelId="#Say hello" eventId="hello"/>

name.jsp:

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

HelloWidget public class 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() { return this.name; } public void handleEventBack() { getFlowCtx().replace(new NameWidget()); } }

Hello ${widget.name}! <br/><ui:eventButton labelId="#Back" eventId="back"/>

hello.jsp:

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

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>...

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

Flows

Currently we use replace() which means:

• A new instance is created every time

• We know where to return

Flow1

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

FlowsWhat we would want is to preserve the instance and nest

the new flow

Flow1

Flow2

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

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); } }

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

Including widgets

Widgets can be included, let’s try to use HelloWidget inside NameWidget like this

handleEventHello()

HelloWidget

We assume that the “back” button was removed from HelloWidget

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

Including widgets

First let’s modify the HelloWidget:

public class HelloWidget extends BaseUIWidget { private String name; public HelloWidget(String name) { this.name = name; } public String getName() { return this.name; } public void setName(String name) { this.name = name; }}

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

Including widgets

Now let’s add a HelloWidget instance

public class NameWidget extends BaseUIWidget { private HelloWidget helloWidget; protected void init() { helloWidget = new HelloWidget("Stranger"); addWidget("hello", helloWidget); }

public void handleEventHello() { String name = (String) getScopedData().get("name"); helloWidget.setName(name); } }

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

Including widgets

<ui:widgetInclude id="hello"/><br/>Insert your name: <input type="text“ name=“${widgetId}.name"/><br/><br/> <ui:eventButton labelId="#Say hello" eventId="hello"/>

And finally we include the widget in the JSP

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

Including widgets

So this is what we get:

helloWidget.setName(“Jevgeni”)

HelloWidget, helloWidget<ui:widgetInclude id=“hello”/>

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

Widgets are objects

We can include

several widgets

of same class on

one page

public class RootWidget extends BaseUIWidget { protected void init() { addWidget("hello1", new NameWidget()); addWidget("hello2", new NameWidget()); addWidget("hello3", new NameWidget()); }}

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

Flows are objects

public class RootWidget extends BaseUIWidget { protected void init() { addWidget("flowContainer1", new StandardFlowContainerWidget(new NameWidget())); addWidget("flowContainer2", new StandardFlowContainerWidget(new NameWidget())); addWidget("flowContainer3", new StandardFlowContainerWidget(new NameWidget())); }}

We can also include

several flow containers

on one page

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

Goal

Get rid of legacy and custom

web frameworks in your

application

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

Our Solution

1. Use Aranea web integration layer to run

different technologies side-by-side

2. Refactor the application into coarse-

grained integration components

3. Start new development immediately and

change old code only when requirements

change – step-by-step migration

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

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

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

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

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

Struts Integration Problems

1. Session and request attributes share the

same namespace and can clash

2. Request parameter names will clash

already during form submission

3. Struts navigates between pages by

changing the actual URL

4. HTML limits usage of some tags

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

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

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

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

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

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

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

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

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

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

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

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>

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

HelloNameWidget & RootWidgetpublic class HelloNameWidget extends StrutsWidget { public HelloNameWidget() { super("/name.jsp"); }}

public class RootWidget extends BaseUIWidget { protected void init() { addWidget("hello1", new HelloNameWidget()); setViewSelector("root"); }}

<input name="f0.hello1.name" type="text"/> <input type="submit" onclick=“new Aranea.Struts.Form(…).submit()" value="Say hello!">

Output:

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

What will happen?

public class RootWidget extends BaseUIWidget { protected void 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"/>

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

DEMO

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

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

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

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!

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

DEMO

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

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!

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

Our Vision

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

Goal

Get rid of legacy and custom

web frameworks in your

application

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

Our Solution

1. Use Aranea web integration layer to run

different technologies side-by-side

2. Refactor the application into coarse-

grained integration components

3. Start new development immediately and

change old code only when requirements

change – step-by-step migration

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

Refactoring

1. Enable Aranea Integration and sanitize

HTML (produces working application)

2. Extract layout, menu and login

3. Split application into coarse-grained

components

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

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

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

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

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

Step 1: Integration & HTML

Application started running after initial

configuration

HTML <a> tags were used in some places,

which means encodeURL() was not applied

Some scripts accessed form fields by name

• Added a widget prefix before the name

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

Step 2: Layout, menu and login

Since login was done using SSO we left it be

We extended the Aranea MenuWidget to

implement the menu from scratch, reusing

all the old privileges

After lifting header, footer and menu to the

RootWidget turned out that Tiles were not

doing anything useful anymore and could be

eliminated

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

Step 3: How to split?

First we extract the widgets pointing to the

relevant parts of the application

Next we change all navigation/inclusion

between those parts to use Aranea API:

• Sending events to the hosting widget

• AraneaUtil.getFlowCtx(), AraneaUtil.addWidget(),

<ui:hostedWidgetInclude> used from the

embedded applications

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

Step 3: Analyze and split

After some research we decided that the

best way to split the application would be

vertically – by functionality

We ended up with five different functionality

types and about ten different widgets (some

widgets were multipurpose)

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

Step 3: Analyze and split

Some widgets were used only as flows while

others were included as components

By extracting and abstracting several

included widgets we eliminated a lot of

copy-paste

While we could further refine our

components it was good enough for starting

migration

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

Results

Five main functionality parts which could be

rewritten one by one without affecting the

others

No more Tiles

Less copy-paste

If we needed to add a sixth functionality

part we could start using JSF immediately

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

Goal

Get rid of legacy and custom

web frameworks in your

application

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

Our solution

1. Use Aranea web integration layer to run

different technologies side-by-side

2. Refactor the application into coarse-

grained integration components

3. Start new development immediately and

change old code only when requirements

change – step-by-step migration

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

Step-by-step migration

After refactoring every component is a Java

class with a particular interface/contract

The rest of the components can only interact

with it via that contract

Therefore we can just rewrite it using any

other implementation as long as the

contract is preserved

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

Case study: migration

In the case study we wanted to use Aranea,

so there was no need for further migration

Eventually we would like to lift the whole

Tax and Customs application to Aranea using

other framework features when needed

However we also have clients who prefer JSF

and Tapestry, so in those cases we would

continue

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

The Next Step

Aranea Integration solves the problem of

mashing up Java web applications

A lot of legacy applications are written in

Perl, PHP, Oracle Forms, etc

You’d also want to integrate with .NET web

applications

Aranea Remote Integration will support that!

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

Webmedia

Webmedia (www.webmedia.eu) is a Baltic

company employing over 300 people that

sponsors Aranea development

Webmedia offers complete commercial

support for Aranea MVC & Integration

In fact we now also offer support for

migrating your legacy web applications to a

platform of your choice :)

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

Final Words

Using Aranea Integration is easy

Problems might come up requiring better

understanding of Integration works

Migration is not completely painless, but it

is cheap next to the alternative

Migrated Struts Mailreader application in

the distribution is a good starting point

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

Questions

www.araneaframework.com

www.araneaframework.org