Object-Oriented Web Development with Aranea
Explore Aranea web framework for OO design, MVC patterns, and widget implementation with real examples and motivation. Learn how to enhance reusability, encapsulation, and polymorphism in web development.
Object-Oriented Web Development with Aranea
E N D
Presentation Transcript
Object-Oriented Web Development with Aranea Jevgeni Kabanov R&D lead, Webmedia, Ltd. JavaZone, Oslo, 13th September, 2006
Outline • Introduction • Aranea “Hello World!” and beyond • Applying OO to web • With real-life examples taken from Aranea-based projects • Behind the scenes • Where’s the catch? • Uniting Web Frameworks OO Web Development
Motivation • At the moment web applications are barely reusable! • Existing code cannot be reused for similar requirements without inserting if-then-else-s everywhere • Legacy migration is very hard! • Integrating applications built on different platforms is hard and often visible to user • Object-Oriented Design to the rescue! OO Web Development
Web is • Procedural (Client calls server) • Synchronized (One window – one request) • Decomposable into pages • Client is mostly stateless (Current state with result, cookies) • In general web is based around a concept of a page, which is combining data, behavior and presentation OO Web Development
GUI applications are • Mostly stateful • Mostly synchronized (one window – one thread) • Decomposable into components • Comfortable to represent using OO concepts • Model-View-Controller pattern suggest to keep data, presentation and behavior separately OO Web Development
Enter MVC Web Frameworks • Request-based: Struts, Spring MVC • Page-based: JSF, Wicket, Tapestry • Continuation/flow-based: RIFE, Spring WebFlow • AJAX-based: Echo2, GWT • … • OO-based: Wicket, Aranea OO Web Development
Problems with OO in Web • Encapsulation & Abstraction (broken) • External state management (session) • Poor contracts among components • Polymorphism (broken) • XML mappings • Implicit component creation • Components, pages & flows are typically not first class objects! OO Web Development
Enter Aranea • An Object-Oriented Web Framework • Everything is an object (component) • Objects are created by the programmer • No (XML) mappings • State is in the object (no session) • Supports • Stateless request-based services • Stateful session-based widgets • Components, pages and flows are represented by widgets OO Web Development
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. Note that we need two widgets only for demonstration purposes OO Web Development
NameWidget • init() is called when the widget life cycle begins • setViewSelector(“name”) resolves (in this case) to “name.jsp” publicclass NameWidget extends BaseUIWidget { protectedvoid init() { setViewSelector("name"); } //To be continued… } OO Web Development
name.jsp • ui:systemForm renders an HTML form • ui:eventButton renders an HTML button that submits event “hello” • Event “hello” maps to widget method “handleEventHello” (or a listener) <ui:systemForm method="GET"> Insert your name: <input type="text“ name="name"/><br/><br/> <ui:eventButton labelId="#Say hello" eventId="hello"/> </ui:systemForm> OO Web Development
NameWidget • getInputData().getGlobalData() is a map of request parameters • getFlowCtx().replace() replaces the current flow widget with the new one publicclass NameWidget extends BaseUIWidget { publicvoid handleEventHello() { String name = (String) getInputData().getGlobalData().get("name"); getFlowCtx().replace(new HelloWidget(name), null); } } OO Web Development
HelloWidget publicclass HelloWidget extends BaseUIWidget { private String name;//Widget state is in its fields public String getName() {returnthis.name;} public HelloWidget(String name) { this.name = name; } protectedvoid init() throws Exception { setViewSelector("hello"); } } hello.jsp Hello <c:out value="${widget.name}"/>! OO Web Development
Hello World! reexamined NameWidget name.jsp handleEventHello() getFlowCtx().replace(new HelloWidget(name)); HelloWidget hello.jsp OO Web Development
Reusing widgets • Widgets can be reused, let’s try to use HelloWidget inside NameWidget like this HelloWidget handleEventHello() OO Web Development
Reusing widgets • First let’s modify the HelloWidget: publicclass HelloWidget extends BaseUIWidget { private String name; public String getName() {returnthis.name;} publicvoid setName(String name) {this.name = name;} public HelloWidget(String name) { this.name = name; } protectedvoid init() throws Exception { setViewSelector("hello"); } } OO Web Development
Reusing widgets • We can use HelloWidget directly in the NameWidget: publicclass NameWidget extends BaseUIWidget { private HelloWidget helloWidget; protectedvoid init() throws Exception { helloWidget = new HelloWidget("Stranger"); addWidget("hello", helloWidget); setViewSelector("name"); } //… } OO Web Development
Reusing widgets • We can just call the instance method as usual: publicclass NameWidget extends BaseUIWidget { //… publicvoid handleEventHello() throws Exception { String name = (String) getInputData().getGlobalData().get("name"); helloWidget.setName(name); } } • This works since widget state is preserved OO Web Development
Reusing widgets • And we include the widget in the JSP <ui:systemForm method="GET"> <ui:widgetInclude id="hello"/><br/> Insert your name: <input type="text“ name="name"/><br/><br/> <ui:eventButton labelId="#Say hello" eventId="hello"/> </ui:systemForm> • <ui:widgetInclude> tag just asks widget to render itself OO Web Development
Reusing widgets • So this is what we get: HelloWidget, helloWidget <ui:widgetInclude id=“hello”/> helloWidget.setName(“Jevgeni”) OO Web Development
Real-life reuse example Widget #1 Widget #2 OO Web Development
Real-life reuse example Widget #1 Widget #2 OO Web Development
Real-life reuse example • Reusing allows composing widgets together to form a use case • The widgets may in their turn be composed of other widgets and so on • This is an implementation of the Composite pattern for the Controller • The main difference from mashup is widget being an object OO Web Development
Widgets are objects • This allows, e.g. to add three widgets of same class in one use case: publicclass UseCaseWidget extends BaseUIWidget { protectedvoid init() { addWidget("client1", new ClientEditWidget(firstClientId)); addWidget("client2", new ClientEditWidget(secondClientId)); addWidget("client3", new ClientEditWidget(thirdClientId)); } } • This also allows abstracting away from a particular widget OO Web Development
Polymorphism • Now let’s modify the NameWidget to be polymorphic: publicclass NameWidget extends BaseUIWidget { private IHelloWidget helloWidget; public NameWidget(IHelloWidget helloWidget) { this.helloWidget = helloWidget; } protectedvoid init() throws Exception { addWidget("hello", helloWidget); setViewSelector("name"); } //… } OO Web Development
Polymorphism • Where IHelloWidget is: publicinterface IHelloWidget extends Widget { publicvoid setName(String name); } • Now we can easily e.g. search Google for the inserted name: OO Web Development
Polymorphism • To do that we just make a GoogleHelloWidget: publicclass GoogleHelloWidget implements IHelloWidget { privateint hits; publicvoid setName(String name) { //Connect to Google... this.hits = //Get number of hits... } //... select JSP and render } • And we can get the previous use case withnew NameWidget(new GoogleHelloWidget()) OO Web Development
Real-life polymorphism • Polymorphism is a very powerful tool of abstraction • One of the uses of polymorphism in web is to make a use case depend on its context • E.g. context use case can assign either a generic client search, or a dropdown list component OO Web Development
Use case variant #1 Widget #1 Client search widget Widget #2 OO Web Development
Use case variant #2 Widget #1 Client select widget Widget #2 OO Web Development
Use case implementation • Implementation would look like this: publicclass UseCaseWidget extends BaseUIWidget { privateIClientWidget clientWidget; public UseCaseWidget(IClientWidget clientWidget) { this.clientWidget = clientWidget; } protectedvoid init() { addWidget("widget1", new Widget1()); addWidget("client", clientWidget); addWidget("widget2", new Widget2()); } } OO Web Development
Use case implementation • But what can IClientWidget look like? • It might be something like that: publicinterface IClientWidget extends Widget { publicboolean isFound(); public Client getClient(); } • But we don’t really know when the user selects a client! OO Web Development
Use case implementation • What we need is a callback: interface IClientWidget extends Widget { interface Callback { void clientSelected(Client client); } void setCallback(Callback callback); } • Polymorphism with callbacks makes for a very powerful abstraction OO Web Development
Use case implementation • Our use case would use callback like this: publicclass UseCaseWidget extends BaseUIWidget implements IClientWidget.Callback { private IClientWidget clientWidget; public UseCaseWidget(IClientWidget clientWidget) { this.clientWidget = clientWidget; clientWidget.setCallback(this); } void clientSelected(Client client) { //... } } Note that use case widget functions as a Mediator! OO Web Development
Flows • A different use case is when we display the search on a separate page and then return the result OO Web Development
Flows • Flows are pages which preserve nested state and can return values OO Web Development
Flows examined • Flow container is a widget that contains a stack of widgets representing flows • It provides the following interface (context) publicinterface FlowContext { void start(Widget flow, Handler handler); void replace(Widget flow) void finish(Object result); void cancel(); } • But how flows and their children can access this interface? OO Web Development
Environment • Environment allows parents to let children access their features interface Environment { Object getEntry(Object key); } Usage example: FlowContext flowCtx = (FlowContext ) //Java 5, where are you? getEnvironment().getEntry(FlowContext.class); flowCtx.start(new MyWidget()); Note that environment is context-dependent! OO Web Development
Wrapping flows • The last example (IClientWidget) was a reusable polymorphic widget providing a callback • However we might also want to wrap it in a flow: publicclassClientFlowWidgetextends BaseUIWidget implements IClientWidget.Callback { private IClientWidget clientWidget; publicClientFlowWidget(IClientWidget clientWidget) { this.clientWidget = clientWidget; clientWidget.setCallback(this); } void clientSelected(Client client) { //getFlowCtx() is just an environment lookup method getFlowCtx().finish(client); } } OO Web Development
First-class flow container • A relatively common use case is to have some kind of context set up for the use cases under it • E.g. one can have a number of use cases depending on the client being already selected • Aranea allows to do such use cases easily by creating a new flow container and adding an Environment entry OO Web Development
First-class flow container Client (or in this case patient) context Use case OO Web Development
First-class flow container • Implementation would look like this: publicclass ClientContextWidget implements ClientContext { private Client client; public ClientContextWidget(Client client) {this.client = client;} public Client getClient() {returnthis.client;} protectedvoid init() { //Add this to Environment under ClientContext.class addWidget("clientInfo", new ClientInfoWidget(client)); addWidget("flowContainer", new StandardFlowContainer(new UseCaseWidget())); } } OO Web Development
First-class flow container • Where the ClientContext is: interface ClientContext { Client getClient(); } • Now all the navigation under the ClientContextWidget will be constrained to its flow container • And all widgets under it will be able to access the selected client OO Web Development
Performance • Widget-based applications require HTTP sessions • We have support for saving state to client • For stateless operation one should use stateless services that can still reuse widgets • There are no known problems with the processing time OO Web Development
Security • Since neither widgets nor flows are identified by URLs there is no way to access them by URL/Request hacking • This removes a lot of security checks! • In fact it is common to check rights only when creating a use case widget • If one still needs bookmarking, one can use mounting service, which will map URLs explicitly OO Web Development
Back button handling • At the moment Aranea ignores the forward/back button in the default configuration for widgets • However, included client state filter supports back button as intended • We also plan to add support for • Explicit back button handling • Automated state-based back button handling OO Web Development
And more… • Multi-submit protection • Popup isolation • No problems with session • Database-backed lists • Generating query with filter conditions, order and range • Keyboard events • AJAX (both full and partial updates) OO Web Development
A word about the framework • Framework is built using the same component types as in applications • This makes it • Modular • Configurable • Extensible • In fact each of our current applications has some extensions to the framework OO Web Development
Integration • Our goal is to use Aranea component model to structure our application • And then use it as glue to integrate with all other web frameworks • In fact Aranea was specially designed with integration in mind • But before 1.0 release we had to put our energy elsewhere OO Web Development
The BIG Picture OO Web Development