Top Banner
OpenSymphony WebWork Simple, Powerful Web Application Development
62

OpenSymphony WebWork Simple, Powerful Web Application Development.

Jan 11, 2016

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: OpenSymphony WebWork Simple, Powerful Web Application Development.

OpenSymphony WebWork

Simple, Powerful Web Application Development

Page 2: 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

http://www.opensymphony.com

Page 3: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 4: OpenSymphony WebWork Simple, Powerful Web Application Development.

How does WebWork use XWork?

XWork is a generic command

pattern implementation

WebWork translates between

the web world and XWork

WebWork

XWork

HTTP

ServletDispatcher

Page 5: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 6: OpenSymphony WebWork Simple, Powerful Web Application Development.

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.

Page 7: OpenSymphony WebWork Simple, Powerful Web Application Development.

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?

Page 8: OpenSymphony WebWork Simple, Powerful Web Application Development.

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;

}

Page 9: OpenSymphony WebWork Simple, Powerful Web Application Development.

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!

Page 10: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 11: OpenSymphony WebWork Simple, Powerful Web Application Development.

HelloWorldAction.javapublic 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;

}

}

Page 12: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

}

Page 13: OpenSymphony WebWork Simple, Powerful Web Application Development.

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>

Page 14: OpenSymphony WebWork Simple, Powerful Web Application Development.

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>

Page 15: OpenSymphony WebWork Simple, Powerful Web Application Development.

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>

Page 16: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 17: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

}

Page 18: OpenSymphony WebWork Simple, Powerful Web Application Development.

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…

Page 19: OpenSymphony WebWork Simple, Powerful Web Application Development.

Interceptors: Domain AOP

XWork

InterceptorInterceptor

Interceptor

Action

Result

Interceptors allow custom code into the call stack

Much of the core functionality of XWork and WebWork is implemented as Interceptors

Add custom Interceptors

Page 20: OpenSymphony WebWork Simple, Powerful Web Application Development.

TimerInterceptor

TimerInterceptor is the simplest InterceptorJust 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();

}

Page 21: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

}

}

Page 22: OpenSymphony WebWork Simple, Powerful Web Application Development.

Other InterceptorsSetting Parameters• ParameterInterceptor

• StaticParameterInterceptor

• ChainingInterceptor

• ConversionErrorInterceptor

• FileUploadInterceptor

Defining Workflow• DefaultWorkflowInterceptor

• PrepareInterceptor

• ServletConfigInterceptor

• ExecuteAndWaitInterceptor

Preventing duplicate posts• 2 types of token interceptors

Page 23: OpenSymphony WebWork Simple, Powerful Web Application Development.

Interceptor StacksInterceptors can be grouped into named

Interceptor StacksSeveral defined in webwork-default.xmldefaultStack

<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

Page 24: OpenSymphony WebWork Simple, Powerful Web Application Development.

Model-Driven vs. Field-Driven2 types of Actions possible:

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

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

Page 25: OpenSymphony WebWork Simple, Powerful Web Application Development.

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.

Page 26: OpenSymphony WebWork Simple, Powerful Web Application Development.

Making HelloWorld ModelDrivenMake the class implement ModelDriven

Change getUser() to getModel()

public class HelloWorldAction extends ActionSupport implements ModelDriven {

public Object getModel() {

return user;

}

}

Page 27: OpenSymphony WebWork Simple, Powerful Web Application Development.

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.jspHello <ww:property value="name"/>! <ww:if test="birthday != null"> <ww:property value="daysTillNextBirthday"/> days till your next birthday.

</ww:if>

Page 28: OpenSymphony WebWork Simple, Powerful Web Application Development.

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>

Page 29: OpenSymphony WebWork Simple, Powerful Web Application Development.

Looking at the ModelInterceptor

Model

ValueStack

Action

Push

ValueStack

Action

Model

The ModelInterceptor pushes the Model onto

the ValueStack

Page 30: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

ValueStack

OG

NL Ex

pressio

n

Find P

roper

ties

Find P

roper

ties

Model

Action

Page 31: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 32: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 33: OpenSymphony WebWork Simple, Powerful Web Application Development.

OGNL samples

OGNL Result

user.name getUser().getName()

user.toString() getUser().toString()

item.categories[0] First element of Categories

collection

@com.example.Test@foo

()

Calls the static foo() method on

the com.example.Test class

name in {null,”fred”} True if name is null or “fred”

categories.{name} Calls getName() on each Category in

the collection, returning a new

collection (projection)

Page 34: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 35: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 36: OpenSymphony WebWork Simple, Powerful Web Application Development.

Bundled Validators

Validator Result

RequiredField field != null

RequiredString field != null && string.length() > 0

IntRange Integer in a given range

DateRange Date in a given range

Email Valid email field

URL Valid URL field

Expression /

FieldExpressio

n

Any OGNL expression evaluates to true

eg. pet.name != “dog”

Allows you to create very powerful

validations using just XML and your

existing model

Page 37: OpenSymphony WebWork Simple, Powerful Web Application Development.

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>

Page 38: OpenSymphony WebWork Simple, Powerful Web Application Development.

Changes to the ActionThe 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

Page 39: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 40: OpenSymphony WebWork Simple, Powerful Web Application Development.

Client-Side JavaScript Validation FlowInvoked 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

Page 41: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 42: OpenSymphony WebWork Simple, Powerful Web Application Development.

Advantages of IoCPromotes 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’

Page 43: OpenSymphony WebWork Simple, Powerful Web Application Development.

IoC in XWork / WebWork XWork provides a simple IoC container WebWork provides a hierarchy of

containers mapped to web scopes 1.Application2.Session3.Request4.XWork Action

Components specify only which services they require• via interfaces (eg ShoppingCartAware)

Configuration file defines component implementations and scopes

Page 44: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

}

Page 45: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

}

Page 46: OpenSymphony WebWork Simple, Powerful Web Application Development.

A service client Actionpublic 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;

}

}

Page 47: OpenSymphony WebWork Simple, Powerful Web Application Development.

Configuring ServicesThese 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>

Page 48: OpenSymphony WebWork Simple, Powerful Web Application Development.

Integrating with other IoC ContainersThe 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

Page 49: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 50: OpenSymphony WebWork Simple, Powerful Web Application Development.

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

Page 51: OpenSymphony WebWork Simple, Powerful Web Application Development.

UI tag rendering

UI tags use Velocity to actually render HTML fragments, eg in your JSP view:

<ww:textfield label=“Name" name=“project.name" />

renders via textfield.vm:

#parse("/$parameters.templateDir/xhtml/controlheader.vm")

#parse("/$parameters.templateDir/simple/text.vm")

#parse("/$parameters.templateDir/xhtml/controlfooter.vm")

Page 52: OpenSymphony WebWork Simple, Powerful Web Application Development.

UI tag templates

WebWork comes with default UI templates

• Show the label beside the form field

• Show the field errors above the form field

<ww:textfield label="Name" name="user.name"/>

renders as (with an error message)

Page 53: OpenSymphony WebWork Simple, Powerful Web Application Development.

Custom UI components

WW allows you to easily create custom UI

components

Requires writing a single Velocity template

Excellent for componentizing views

Example: a date picker to allow users to

enter dates into text fields easily…

Page 54: OpenSymphony WebWork Simple, Powerful Web Application Development.

A custom date picker (from Jira)

Here’s the form field and popup:

Page 55: OpenSymphony WebWork Simple, Powerful Web Application Development.

Using the custom UI componentView (addpet.jsp):<ww:component label="Created After" template="datepicker.vm"

name="pet.created">

<ww:param name="formname" value="editform" />

</ww: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" )

You can also extend the component tag like the other UI tags do create new UI tags

Page 56: OpenSymphony WebWork Simple, Powerful Web Application Development.

Reusable application modules

You can build reusable modules which can be

included in any WebWork app

Xwork.xml include allows you to merge in external

configuration

Velocity allows you to include both Actions and

templates in a jar file

Example: The WebWork configuration browser

Page 57: OpenSymphony WebWork Simple, Powerful Web Application Development.

Adding the Config Browser to your WebWork app

Add the webwork-config-browser.jar (12 Kb) to your WEB-INF/lib

Add an include in your xwork.xml

<xwork>

<include file="webwork-default.xml"/>

<include file="config-browser.xml"/>

</xwork>Add a velocity.properties file under WEB-INF• velocimacro.library = webwork.vm, tigris-macros.vm

That’s it!

Page 58: OpenSymphony WebWork Simple, Powerful Web Application Development.

The Config Browser in action

Page 59: OpenSymphony WebWork Simple, Powerful Web Application Development.

What’s coming in 2.2?

IDE plugins for Eclipse and Intellij IDEA

AJAX component theme for the JSP tags

JSR-168 Portlet support

Improved configuration API – Much better

runtime action configuration!

Even better collections and Map support

Page 60: OpenSymphony WebWork Simple, Powerful Web Application Development.

What’s coming in 2.2? (continued)

Improved productivity: better error

reporting, configuration problem reporting

Improved client-side validation calling the

server with DWR

Annotation support for validations

Request parameter filtering for security

Page 61: OpenSymphony WebWork Simple, Powerful Web Application Development.

For More Information For release downloads, see the java.net project sites:

http://xwork.dev.java.nethttp://webwork.dev.java.net

Check out the project documentation on the OpenSymphony wiki:http://wiki.opensymphony.com/space/XWorkhttp://wiki.opensymphony.com/space/WebWork2

For project issue tracking, see:http://jira.opensymphony.com/secure/Dashboard.jspa

The project mailing list is available [email protected]

And is synchronized with the Opensymphony Forums:http://forums.opensymphony.com

Questions?

Page 62: OpenSymphony WebWork Simple, Powerful Web Application Development.

Fill out your Evaluations!