580 likes | 602 Views
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.
E N D
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