1 / 52

Strutting the OpenSymphony Way: WebWork 2 Overview

Learn about WebWork 2 and XWork featuring actions, views, interceptors, validation, IoC, and a Struts comparison. See examples and key concepts explained.

veronicak
Download Presentation

Strutting the OpenSymphony Way: WebWork 2 Overview

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. WEBWORK 2 “Strutting the OpenSymphony way” Prepared by Mike Cannon-Brookes - June, 2003 mike@atlassian.com - http://www.atlassian.com

  2. Agenda • WebWork 2 & XWork overview • Actions • Views • Interceptors • Validation • Inversion of Control (IoC) • Struts Comparison

  3. WebWork 2 Overview • ‘Pull-based’ MVC framework • Focus on componentization & code reuse • Implementation of the command pattern • Second generation of WebWork • Not tied to the web! • Currently in beta - but being well used

  4. XWork • Generic command pattern framework • Commands represent a unit-of-work • Split off from Webwork 1 • Why command pattern? WebWork 2 Web WebWork 1 XWork 1 Non-web

  5. XWork provides… • Core command pattern framework for request / response environment • Interceptor framework • Action chaining • IoC componentization framework • Runtime attribute validation framework • Built-in type conversion using OGNL • Doesn’t provide: anything to do with the web!

  6. WebWork 2 provides.. • Tied to HTTP request / response • Integration with session / application scopes • Servlet-based dispatcher to turn incoming requests into action/s. • Automatically set properties of action based on request parameters • View integration (JSP, Velocity etc) • User interface / form components

  7. Actions • An Action is a command. • Each action should be a ‘unit of work’ • Actions should be simple! • Action interface has only one method: interface Action { String execute() throws Exception; } • Let’s look at small example…

  8. Basic Example: Add Pet Use case - we want to add a Pet to our system:

  9. Basic Example: Add Pet • A basic example of an action, view and configuration. • Model: Pet.java (simple bean) • Controller: AddPet.java (WW action) • View: addpet.jsp • Config: xwork.xml

  10. Basic Example: Pet Model . . . public class Pet { private long id; private String name; public long getId() … public void setId(long id) … public String getName() … public void setName(String name) … }

  11. Basic Example: AddPet action public class AddPet implements Action { protected Pet pet = new Pet(); public String execute() throws Exception { if (pet.getName() == null ) return ERROR; Registry.getPetStore().savePet(pet); return SUCCESS; } public Pet getPet() { return pet; } }

  12. Basic Example: addpet.jsp <%@ taglib uri= "webwork" prefix= "webwork" %> <html> <head><title>Add A Pet</title></head> <body> <form action= "AddPet.action"> <webwork:textfield label="Name" name="pet.name" /> <input type= "submit" value= "Add"> </form> </body> </html>

  13. Basic Example: xwork.xml <xwork> <package name="default"> . . . <action name="AddPet” class="org.petsoar...AddPet"> <interceptor-ref name="defaultStack" /> <result name="error">addpet.jsp</result> <result name="success">success.jsp</result> </action> . . . </package> </xwork>

  14. ActionSupport • Useful base class, providing: • error message support • action and field specific errors • field errors are automatically supported by views • internationalisation support • 1 resource bundle per action • pervasive UI support for retrieving messages

  15. Model-Driven vs Field-Driven • 2 types of Actions possible: • Model-driven • Action has methods returning your model classes (myAction.getPet()) • Fields in the view are fields of your model • Views refer directly to your model (property=‘pet.name’) • Excellent because it allows model reuse • Field-driven • Action has fields of its own, which are fields in the view • execute() collates fields and interacts with the model • Views refer to action fields (property=‘name’) • Useful where form is not parallel to model

  16. Action Composition • Problem: traditional MVC actions contain duplication or deep class hierarchies • Solution: A single WW action can be composed of multiple smaller reusable beans. • Before: public class Signup implements Action { public String getName(); [+ setter] public String getHomeInternationalCode(); [+ setter] public String getHomeAreaCode(); [+ setter] public String getHomeNumber(); [+ setter] public String getWorkInternationalCode(); [+ setter] public String getWorkAreaCode(); [+ setter] public String getWorkNumber(); [+ setter] ... }

  17. Action Composition • After: public class Signup implements Action { public String getName(); [+ setter] public PhoneNumber getHome(); public PhoneNumber getWork(); ... } public class PhoneNumber { public String getInternationalCode(); [+setter] public String getAreaCode(); [+setter] public String getNumber(); [+setter] } • We can also reduce duplication in our views in the same way - using UI components.

  18. Action Dispatching • A Dispatcher configures and executes an action. • WebWork has ServletDispatcher and a FilterDispatcher for the servlet environment • XWork separates the implementation and invocation of an action • ClientDispatcher allows actions created by a client to be executed on server • execute an action over RMI (ie in an applet) • execute an action via SOAP

  19. WebWork Views • Multiple supported view technologies: • JSP • Velocity • XML • JasperReports • … add your own • Not being tied to the web allows multiple pluggable ‘result types’ • - ie action chains, pooling, HTTP redirects etc

  20. View Expression Language • For expressions WW uses OGNL (Object Graph Navigation Language) • Incrementally compiled expressions - fast! • Easy to learn, powerful expression language • Componentised (so you can embed anywhere) • Embedded everywhere - views and *.xml • Independently run Open Source project - http://www.ognl.org

  21. OGNL Samples

  22. UI Components • Powerful for componentization of views • Standard form components are built in • text field, radio boxes, submit button etc. • Skinnable using ‘themes’ • multiple sets of templates to render same components • Usable from any view • JSP or Velocity at the moment

  23. JSP: <ui:textfield label="Username" name="username" /> <ui:password label="Password" name="password" /> <ui:component template="/mytemplate.vm"> <ui:param name="param1" value="value1" /> </ui> <ui:submit value="'login'" align="right" /> Velocity: #tag (TextField "label=Username" "name=username") #tag (Password "label=Password" "name=password") #bodytag (Component "template=/mytemplate.vm") #param ("name=param1" "value=value1") #end #tag (Submit "value='login'" "align=right") UI Component Usage

  24. Component Rendering • <webwork:textfield label="Name" name="project.name" /> looks as follow (with added header) : • UI components automatically present field error messages, added by validation framework or action itself:

  25. Component Rendering • Uses Velocity to actually render HTML fragments, eg in your JSP view: <webwork:textfield label="Name" name="project.name" /> renders via textfield.vm: #parse( "/decorators/xhtml/controlheader.vm" ) <input type="text" name="${tag.Name}" value="$!{tag.ActualValue}" #if($tag.Size > 0) size="${tag.Size}"#end /> #parse( "/decorators/xhtml/controlfooter.vm" )

  26. Custom components • WW allows you to easily create custom UI components • Requires writing a single Velocity template • Excellent for componentizing views (with componentized or model-driven actions) • Example: a date picker to allow users to enter dates into text fields easily…

  27. Custom component example • Here’s the form field and popup:

  28. Custom component example • View (addpet.jsp): <webwork:component label="Created After" template="datepicker.vm" name="pet.created"> <webwork:param name="'formname'" value="'editform'" /> </webwork:component> • Component template (datepicker.vm) #parse( "/decorators/xhtml/controlheader.vm" ) <script language="JavaScript" src="/decorators/datepicker.js" /> <input type="text" name="${tag.Name}" value="$!{tag.ActualValue}" /> <a href="javascript:show_calendar('${tag.Params.get("formname")}', '${tag.Name }');"><img src="/images/icons/cal.gif"></a> #parse( "/decorators/xhtml/controlfooter.vm" )

  29. Interceptors • “Practical AOP” • very simple, no external dependencies • allows you to intercept action invocations. • Help decouple and componentize your code • Interceptors are organized into ‘stacks’ • lists of interceptors applied in sequence. • applied to any action or package of actions • WebWork is mostly implemented as a series of XWork interceptors!

  30. Timing Interceptor • A simple invocation interceptor: public class TimerInterceptor implements Interceptor { . . . public String intercept(ActionInvocation dispatcher) ...{ long startTime = System.currentTimeMillis(); String result = dispatcher.invoke(); long exTime = System.currentTimeMillis() - startTime; log.info(dispatcher.getProxy().getActionName() + " ran in " + exTime + "ms."); return result; } }

  31. Logging Interceptor • A before/after processing interceptor: public class LoggingInterceptor extends AbstractInterceptor { . . . protected void before(ActionInvocation invocation) ... { log.info("Starting execution stack for action " + invocation.getProxy().getActionName()); } protected void after(ActionInvocation invocation, String result) ...{ log.info("Finishing execution stack for action " + invocation.getProxy().getActionName()); } }

  32. Complex Interceptor • Problem: notifying users of events within our application via email • Solution: an XWork interceptor + XML config file • The interceptor: • parses the config file (if not loaded yet) • intercepts the action • matches action class & result to determine if any email needs to be sent • if it does, processes a Velocity template (email body) and sends it

  33. Complex Interceptor - class public class EventNotifierInt extends AbstractInterceptor { . . . protected void after(ActionInvocation actionInvocation, String result) . . . { List listeners = getListenersFor(actionInvocation, result); for (int i = 0; i < listeners.size(); i++) { ConfEventListener l = (ConfEventListener)listeners.get(i); l.onEvent( result, actionInvocation.getAction() ); } } private void loadXmlConfiguration() ... private List getListenersFor(ActionInvocation invocation, String result) . . . }

  34. Validation Framework • Validation of action properties • Decoupled from actions • validations stored in XML files • error messages stored in actions, flow through to UI components • Pluggable validator classes • Validation is implemented as an interceptor • You control when validation happens

  35. Bundled Validators

  36. Example Validation • adduser-validation.xml <validators> <field name="username"> <field-validator type="requiredstring"> <message>Please specify a username.</message> </field-validator> </field> <field name="confirm"> <field-validator type="fieldexpression"> <param name="expression"> confirm == null || password.equals(confirm) </param> <message key="passwords.dontmatch">no i18n msg!</message> </field-validator> </field> </validators>

  37. Validator Class • checks that a String field is non-null and has a length > 0 public class RequiredStringValidator extends FieldValidatorSupport { public void validate(Action action) throws ValidationException { String fieldName = getFieldName(); Object value = this .getFieldValue(fieldName, action); if (!(value instanceof String) || value == null || "".equals((String) value)) { addFieldError(fieldName, action); } } }

  38. What is Inversion of Control? • IoC removes the onus of managing components from your business logic into a container. • Container manages lifecycles and dependencies between components. • EJB is IoC, but with a static list of services • Security, persistence and transactions • The Jakarta Avalon project is all about IoC.

  39. Advantages of IoC • Promotes simplicity and decoupling • Components describe themselves • Dependencies are discovered automatically • Adheres to Law of Demeter • Classes coupled to only what they use • Encourages smaller responsibility classes • Leads to better interface/impl separation • Unit tests become far simpler • they become ‘mini-containers’

  40. IoC in XWork • First off: IoC can be controversial - it is optional! Use it if it suits you :) • XWork and WW provide a web-native IoC architecture • Components specify only which services they require • via interfaces (eg ShoppingCartAware) • Configuration file defines component implementations and scopes.

  41. Component Scopes • WW has 4 component ‘scopes’ (lifetimes): • Application • HTTP Session • HTTP Request • XWork Action • Let’s look at an example with 2 services…

  42. IoC Example Service #1 • A ShoppingCart service - provides a user’s cart (session scoped) ShoppingCartAware.java: public interface ShoppingCartAware { public void setShoppingCart(ShoppingCart cart); } ShoppingCart.java: public interface ShoppingCart { public void addPet(Pet pet); public void removePet(Pet pet); public boolean isEmpty(); public int size(); public List getPets(); }

  43. IoC Example Service #2 • A PetStore service - provides management of our pet inventory (application scoped) PetStoreAware.java: public interface PetStoreAware { public void setPetStore(PetStore store); } PetStore.java: public interface PetStore { void savePet(Pet pet); void removePet(Pet pet); List getPets(); Pet getPet( long id); }

  44. IoC Example -Being serviced! public class AddToCart implements Action, PetStoreAware, ShoppingCartAware { . . . public void setPetStore(PetStore ps) { this.petStore = ps; } public void setShoppingCart(ShoppingCart c) { this.cart = c; } public String execute() throws Exception { if (cart == null || petId == 0) return ERROR; Pet pet = petStore.getPet(petId); cart.addPet(pet); return SUCCESS; } }

  45. IoC Example - Config • These services are configured in components.xml like so: <components> <component> <scope>application</scope> <class>org.petsoar.pets.DefaultPetStore</class> <enabler>org.petsoar.pets.PetStoreAware</enabler> </component> <component> <scope>session</scope> <class>org.petsoar.cart.SimpleShoppingCart</class> <enabler>org.petsoar.cart.ShoppingCartAware</enabler> </component> </components>

  46. Action Packaging • A package is a JAR containing: • Actions, views, interceptors, validators, i18n properties and configuration • Packages are: • namespace aware • hierarchical • inherit capabilities from super packages • Promotes componentisation

  47. Packaging Configuration • xwork.xml: <xwork> <package name="default"> . . . </package> <package name="subpackage" extends="default"> . . . </package> <include file="myotherpackage.xml" /> </xwork>

  48. Struts vs WebWork • Jakarta Struts is the 500-lb gorilla of the MVC ‘space’ • No MVC presentation complete without a Struts comparison • I’ll try to be unbiased as possible :) • Not an apples-for-apples comparison • Think of it as a list of differences

  49. WebWork Pros • Simpler framework • No more writing ‘junk code’ to fulfill Struts’ contracts • No more actionbean/formbean classes • Use simple model-driven actions and your own model • Actions are easy to unit test • Instantiate, call setters, run execute() • WW ‘plays well with others’ • Multiple view technologies well supported

  50. WebWork Pros • Simpler views • more powerful expression language • no more pages with 1000’s of Struts tags • No need to make actions thread safe • One action instantiated per request • Actions not coupled to the web • Can be invoked remotely eg ClientDispatcher & RMI • Struts has no interceptors, packages, IoC etc

More Related