1 / 62

OpenSymphony WebWork

OpenSymphony WebWork. Simple, Powerful Web Application Development. What is OpenSymphony?. An open source group encompassing quality enterprise Java components Many well known quality components WebWork / XWork SiteMesh OSCache OSUser OSWorkflow Quartz TestNG OGNL

owena
Download Presentation

OpenSymphony WebWork

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. OpenSymphony WebWork Simple, Powerful Web Application Development

  2. What is OpenSymphony? • An open source group encompassing quality enterprise Java components • Many well known quality components • WebWork / XWork • SiteMesh • OSCache • OSUser • OSWorkflow • Quartz • TestNG • OGNL • http://www.opensymphony.com

  3. What is WebWork? • The second generation of WebWork • A web MVC framework • A wrapper on top of a generic Command Pattern implementation (XWork) • A tag library that encourage componentization and reuse

  4. How does WebWork use XWork? • XWork is a generic command pattern implementation • WebWork translates between the web world and XWork

  5. What does XWork provide? • Command pattern implementation • Actions are command objects in XWork • Adds advanced features • Interceptors • Includes setting parameters, workflow, etc • Results • Includes one for chaining to another Action • Simple IoC (or “Dependency Injection”) container • Powerful expression language – OGNL • Flexible type conversion • Metadata driven validation framework

  6. What does WebWork add? • Adapter for HTTP request / response • Integration of Session / Application scopes • ServletDispatcher translates HTTP requests into Action execution • Request parameters passed to Action • Results for servlet redirect & dispatch, Velocity, Freemarker, JasperReports, XSLT, etc.

  7. Results: The “View” in MVC • Results are what happens after an Action • Displaying a page -> JSP / Velocity / FreeMarker / JasperReports / XSLT • Chaining to another Action • Add your own • Email? Command line output?

  8. Actions • Actions are command objects • Actions should be simple! • Actions are not tied to any web classes • Action interface has only one method: interface Action { String execute() throws Exception; }

  9. ActionSupport • Actions are only required to implement the Action interface • ActionSupport is a useful base class • Implements Action • Provides error message support • Field and Action level messages • Messages automatically used by UI tags • Provides message internationalization • Message bundle for each Action • Looks up class hierarchy • UI tags use internationalization support to find text • All features based on Interfaces, so you can implement your own from scratch!

  10. A “Hello World” example • Simple requirements • Take the users name and generate a hello message personalized for them • If the user enters a birthday, calculate how long until their birthday • Shows • Implementing an Action • Configuring WebWork • Using the taglib • Type conversion • Error messages

  11. HelloWorldAction.java public class HelloWorldAction extends ActionSupport { private User user; public User getUser() { return user; } public int getDaysTillNextBirthday() { … } public String execute() throws Exception { String name = getUser().getName(); if ((name == null) || (name.trim().equals(""))) { addFieldError("user.name", "You must enter a name."); } if (hasErrors()) { return INPUT; } return SUCCESS; } }

  12. User.java public class User { private String name; private Date birthday; public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }

  13. form.jsp <%@ taglib uri= "webwork" prefix= "webwork" %> <html> <head><title>Hello World Example</title></head> <body> <ww:form action="HelloWorld"> <ww:textfield label="Name" name="user.name"/> <ww:textfield label="Birthday" name="user.birthday"/> <ww:submit value="Say Hello"/> </ww:form> </body> </html>

  14. success.jsp <%@ taglib uri= "webwork" prefix= "webwork" %> <html> <head><title>Hello <ww:property value="user.name"/></title></head> <body> Hello <ww:property value="user.name"/>! <ww:if test="user.birthday != null"> <ww:property value="daysTillNextBirthday"/> days till your next birthday. </ww:if> </body> </html>

  15. Xwork.xml for Hello World <xwork> <include file="webwork-default.xml"/> <package name="default" extends="webwork-default" abstract="true"> <action name="main"> <result>/field/form.jsp</result> </action> </package> <package name="ex1" extends="default" namespace="/ex1"> <action name="HelloWorld" class="example.ex1.HelloWorldAction"> <interceptor-ref name="defaultStack"/> <result>/field/success.jsp</result> <result name="input" type="dispatcher">/field/form.jsp</result> </action> </package> </xwork>

  16. Unit testing Actions • XWork / WebWork shines in testability • Actions have no web dependencies, so you don’t have to set up mocks, etc. • 3 ways of testing Actions • Just create a new instance, set some properties, and execute • Use the framework directly in your tests to execute it with the Interceptors, etc. • Extend the XworkTestCase base class which defaults a lot of set up

  17. HelloWorldActionTest public void testFieldErrorAddedWhenNoUserName() throws Exception { HelloWorldAction action = new HelloWorldAction(); assertEquals(Action.INPUT, action.execute()); assertTrue(action.hasFieldErrors()); Map fieldErrors = action.getFieldErrors(); assertTrue(fieldErrors.containsKey("user.name")); List userNameErrors = (List) fieldErrors.get("user.name"); assertEquals(1, userNameErrors.size()); assertEquals("You must enter a name.",userNameErrors.get(0)); }

  18. Notes on the example • Compose page model from many objects using expression language • UI tags automatically show field error messages next to the form field • Return code from Action determines which page to display • Much of the “magic” is in the interceptors…

  19. Interceptors: Domain AOP • Interceptors allow custom code into the call stack • Much of the core functionality of XWork and WebWork is implemented as Interceptors • Add custom Interceptors

  20. TimerInterceptor • TimerInterceptor is the simplest Interceptor • Just times the execution of the Action public String intercept(ActionInvocation invocation) throws Exception { if (log.isInfoEnabled()) { long startTime = System.currentTimeMillis(); String result = invocation.invoke(); long executionTime = System.currentTimeMillis() - startTime; String namespace = invocation.getProxy().getNamespace(); … }

  21. LoggingInterceptor • LoggingInterceptor extends the AroundInterceptor • AroundInterceptor provides callbacks for before() and after() the Action is executed public class LoggingInterceptor extends AroundInterceptor { protected void after(ActionInvocation invocation, String result) throws Exception { logMessage(invocation, FINISH_MESSAGE); } protected void before(ActionInvocation invocation) throws Exception { logMessage(invocation, START_MESSAGE); } }

  22. Other Interceptors • Setting Parameters • ParameterInterceptor • StaticParameterInterceptor • ChainingInterceptor • ConversionErrorInterceptor • FileUploadInterceptor • Defining Workflow • DefaultWorkflowInterceptor • PrepareInterceptor • ServletConfigInterceptor • ExecuteAndWaitInterceptor • Preventing duplicate posts • 2 types of token interceptors

  23. Interceptor Stacks • Interceptors can be grouped into named Interceptor Stacks • Several defined in webwork-default.xml • defaultStack <interceptor-stack name="defaultStack"> <interceptor-ref name="static-params"/> <interceptor-ref name="params"/> <interceptor-ref name="conversionError"/> </interceptor-stack> • validationWorkflowStack <interceptor-stack name="validationWorkflowStack"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="validation"/> <interceptor-ref name="workflow"/> </interceptor-stack> • Stacks can be built of other stacks and interceptors

  24. Model-Driven vs. Field-Driven • 2 types of Actions possible: • Model-driven • Action has methods returning your model classes (myAction.getUser()) • Fields in the view are fields of your model • Views refer directly to your model (property=‘user.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=‘daysTillNextBirthday’) • Useful where form is not parallel to model • As we can see in our Action, the two can be mixed

  25. ModelDriven Interface • XWork / WebWork also supports model-driven Actions more directly • The ModelDriven Interface has one method: public Object getModel() • Properties of the model will be directly available, i.e. “name” instead of “user.name” • Applies to UI tags, form field names, etc.

  26. Making HelloWorld ModelDriven • Make the class implement ModelDriven • Change getUser() to getModel() public class HelloWorldAction extends ActionSupport implements ModelDriven { … public Object getModel() { return user; } }

  27. ModelDriven: Changes to the JSP • Change “user.name”, etc. to just “name” • In form.jsp <ww:textfield label="Name" name="name"/> <ww:textfield label="Birthday" name="birthday"/> • In success.jsp Hello <ww:property value="name"/>! <ww:if test="birthday != null"> <ww:property value="daysTillNextBirthday"/> days till your next birthday. </ww:if>

  28. Applying the ModelDrivenInterceptor • In xwork.xml <package name="ex2" extends="webwork-default" namespace="/ex2"> <action name="main" class="com.opensymphony.xwork.ActionSupport"> <result>/model/form.jsp</result> </action> <action name="HelloWorld" class="example.ex2.HelloWorldAction"> <interceptor-ref name="model-driven"/> <interceptor-ref name="defaultStack"/> <result>/model/success.jsp</result> <result name="input">/model/form.jsp</result> </action> </package>

  29. Looking at the ModelInterceptor • The ModelInterceptor pushes the Model onto the ValueStack

  30. What is the ValueStack? • The ValueStack builds a stack of objects • Objects are used to find property values • The ValueStack allows the expression language to find property values across multiple objects

  31. How is the ValueStack used? • The Action instance is always pushed onto the ValueStack • The Model is pushed on by the ModelInterceptor • The UI tags use it to push values on during their scope and evaluate expressions • The <ww:iterator> tag pushes the current item onto the stack • The <ww:bean> tag pushes a bean instance on • The <ww:property> tag evaluates an expression against the ValueStack • All tag attribute values are evaluated against the stack when being set onto the tag instances

  32. The OGNL expression language • For expressions WW uses OGNL (Object Graph Navigation Language) • an expression and binding language for getting and setting properties of Java objects • Normally the same expression is used for both getting and setting the value of a property • Easy to learn, yet powerful • Incrementally compiled expressions - fast! • Embedded everywhere – views, ValueStack, *.xml • Independently run Open Source project - http://www.ognl.org

  33. OGNL samples

  34. The XWork Validation Framework • Separates validation from Action classes • Allows for different validations in different contexts for the same object • Provides hooks for localized validation messages • 2 types of validators, Object level and field level

  35. HelloWorldAction-validation.xml <validators> <field name="user.name"> <field-validator type="requiredstring"> <message>You must enter a name.</message> </field-validator> </field> </validators> • Validation file in the same package as the class • Defines one field validator and the error message to add if it fails

  36. Bundled Validators

  37. Changes to xwork.xml <package name="ex3" extends="default" namespace="/ex3"> <action name="HelloWorld" class="example.ex3.HelloWorldAction"> <interceptor-ref name="validationWorkflowStack"/> <result name="success" type="dispatcher">/field/success.jsp</result> <result name="input" type="dispatcher">/field/form.jsp</result> </action> </package> • validationWorkflowStack is from webwork-default.xml <interceptor-stack name="validationWorkflowStack"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="validation"/> <interceptor-ref name="workflow"/> </interceptor-stack>

  38. Changes to the Action • The execute() method can just return SUCCESS public String execute() throws Exception { return SUCCESS; } • The validation of the “user.name” property is handled by the validation interceptor • The workflow interceptor returns INPUT if there are any errors added to the Action

  39. Client-Side JavaScript Validation • XmlHttpRequest validation on the server side • Doesn’t require two versions of each validator – all the actual validation logic happens on the server side • Provides near-instant validation feedback, just like normal JavaScript validation

  40. Client-Side JavaScript Validation Flow • Invoked using onBlur and onChange events • Asynchronous Javascript XmlHttpRequest call to the server • Uses server-side validations and returns results to the client • Any validation errors are rendered using DHTML and JavaScript

  41. 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 • Jakarta Avalon, Spring’s BeanFactory, and PicoContainer are all IoC containers

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

  43. IoC in XWork / WebWork • XWork provides a simple IoC container • WebWork provides a hierarchy of containers mapped to web scopes • Application • Session • Request • XWork Action • Components specify only which services they require • via interfaces (eg ShoppingCartAware) • Configuration file defines component implementations and scopes

  44. A ShoppingCart Service • 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(); }

  45. A PetStore Service • 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); }

  46. A service client Action 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; } }

  47. Configuring Services • 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>

  48. Integrating with other IoC Containers • The Xwork-optional project includes integrations and extension projects • Xwork-Spring provides integration with Spring’s IoC Container • Actions, Interceptors, Results, etc. can be auto-wired or configured in Spring’s application context • Integrations exist with other IoC Containers, including Pico/NanoContainer

  49. Achieving reuse with WebWork • WebWork provides many opportunities for modularizing and reusing components • Make Interceptors to do work before and after the Action is executed • Create services which are applied via IoC • Create Action base classes • Create reusable UI components • Create reusable application modules

  50. Reusable UI components • The WebWork UI tags are implemented using Velocity templates • You can provide your own templates for the tags • The <ww:component> tag lets you use any template • Examples • A date picker template • Error message template

More Related