2. Struts 2 High Level Design
Web Browser
Client
Controller
FilterDispatcher
Model
Action
View
Result
request
render page
invoke action
select result
3. MVC Components
Controller: It maps the requests to actions.
The FilterDispatcher acts as controller and is a servlet
filter that inspects each incoming request to determine
which Struts 2 action should handle the request.
Model: A model is the internal state of the application
composed of both the data model and the business logic.
In struts 2 action acts as model serves two roles:
First, an action is an encapsulation of the calls to business
logic into a single unit of work.
Second, the action serves as a locus of data transfer.
View: The view referred as Result is the presentation
component of the MVC pattern. It is the user interface that
presents a representation of application’s state to the user.
5. Interceptors
The invocation of action passes through the stack of
interceptors.
Every action has a stack of associated interceptors.
They are invoked and executed both before and after
the action or request processing.
They provide an architectural component in which to
define various workflow and cross-cutting tasks so
that they can be easily reused as well as separated from
other architectural concerns.
Interceptors in Struts 2 perform tasks such as data
validation, type conversion, and file uploads.
6. ValueStack and OGNL
ValueStack is a storage area that holds all of the data
associated with the processing of a request.
It is the storage area for all application domain data
that will be needed during the processing of a request.
Struts 2 keeps all its data in a convenient, central
location instead of passing it around.
OGNL is the tool that allows to access the data in the
central repository i.e. the ValueStack.
It is the expression language allowing to reference and
manipulate the data in ValueStack.
the ValueStack and OGNL are independent of any
individual framework components.
7. ActionContext
The ActionContext contains all of the data that makes up the
context in which an action occurs.
It includes the ValueStack and key servlet components, request,
session and application maps.
ValueStack is stored in ThreadLocal context called
ActionContext.
The ThreadModel makes ActionContext and hence ValueStack
accessible in a single thread of execution.
In Struts 2, the processing of each request occurs in a single
thread, as the ValueStack is available from any point in the
framework’s handling of a request.
The getInvocationContext() method of ActionInvocation returns
the ActionContext object associated with the request, confining
the programmatic access to the ActionContext from
interceptors,.
The objects in ActionContext can be accessed from view layer
pages (JSPs) via OGNL expressions.
8. Declarative architecture
The declarative architecture is one way of configuration in which
actually building Struts 2 applications is the central focus, while
other is more administrative in nature. Each perform foll tasks:
1) Configuring framework: Change the URL extension by
which the framework recognizes the requests (by default it is
action) or maximum file upload size.
2) Declaring Application framework: Defining struts2
components, wiring them to form a workflow path.
Declarative architecture is a specialized type of configuration
that allows developers to create an application’s architecture
through description rather than programmatic intervention.
The developer describes the architectural components in high-
level artifacts, such as XML files or Java annotations, from which
the system will create the runtime instance of the application.
Declarative architecture can be done in two ways: through XML-
based configuration files or through Java annotations.
9. XML-Based Declarative Architecture
XML Declarative Elements:
<action name="Register" class="learning.Register">
<result>/RegistrationSuccess.jsp</result>
<result name="input">/Registration.jsp</result>
</action>
An application can have several XML files describing
all of the components of the application working
together as a large description.
The framework uses a specific file as the entry point
into this large description called the struts.xml file in
the Java classpath.
10. Java Annotation based Architecture
Java annotations allow to add metadata directly to Java
source files.
The goal of Java annotations is to support declarative
architecture elements tools that can read metadata from a
Java class and do something useful with that information.
@Results({
@Result(name="input", value="/RegistrationSuccess.jsp" )
@Result(value="/RegistrationSuccess.jsp" )
})
public class Login implements Action {
public String execute() {
//Business logic for login
}
}
11. Struts.xml
The struts.xml file is an entry point into the XML
declarative architecture.
<struts>
<constant name="struts.devMode" value="true" />
<package name="default" namespace="/" extends="struts-
default">
<action name="Menu">
<result>/menu/Menu.jsp</result>
</action>
</package>
<include file="manning/chapterTwo/chapterTwo.xml"/>
</struts>
12. Struts.xml
A constant element is used to set framework properties.
struts.xml can also define some global actions in a default
package.
The include element pulls all of included xml document
into the declarative architecture, to create a single large
XML document.
In the action element, each result names a JSP page that is
used to render the result page.
The struts element is the mandatory document root of all
Struts 2 XML files.
The package element is an important container element for
organizing the actions, results, and other component
elements. It declares a namespace used to map the URLs to
the actions by the framework.
The URL combines the servlet context with the package
namespace and the action name
13. Top Level Working
The data is both stored in the action and in the ValueStack.
First, domain data is always stored in the action.
It allows convenient access to data from the action’s execute()
method.
The framework can access the data, the action object placed on
the ValueStack.
All properties of the action are exposed as toplevel properties of
the ValueStack itself and, is accessible via OGNL.
The form field attribute is interpreted as an OGNL expression.
The expression is used to target a property on the ValueStack.
In the incoming request, the value from the form field is
automatically moved onto that property by the framework.
The response JSP page pulls data off from the property on the
ValueStack by using an OGNL expression, inside a tag.
14. Using Annotations
The annotations are placed directly in the source code of the
actions.
The location of actions is specified in an initialization parameter
“actionPackages” to the Struts 2 FilterDispatcher in web.xml.
The action classes are marked which either implement the
com.opensymphony.xwork2.Action interface or use a naming
convention with class names ending with the word Action.
The framework makes some assumptions and generates the
package containing actions with the namespace derived from
namespace of action class.
All annotated actions in the same Java package will be added to
the same Struts 2 package/namespace.
Since annotations reside in the action class, the framework takes
the as declaration of an action with its name derived from the
java class.
The annotation comes just before the class declaration:
@Result(name="SUCCESS",
value="/chapterTwo/HelloWorld.jsp" )
15. Actions
Actions encapsulate the unit of work, by the containment of
business logic using the execute() method.
In case the logic is complex, it is placed outside in the business
component and injected into the action,
Action provide locus of data transfer from the request to the
view.
Action serves as a centralized data transfer object that can be
used to make the application data available in all tiers of the
framework.
Action merely implements JavaBeans properties for each piece of
data to carry.
Struts 2 creates a new instance of an action for each request that
maps to it unlike struts 1 were there is only one instance of an
action class.
Action returns control string for result routing or selecting the
results to be rendered.
The value of the return string must match the name of the
desired result as configured in the declarative architecture.
16. Organizing using Packages
The packages are based upon commonality of
functionality of the components.
The packages are declared in the XML files or the Java
annotations located in action class.
The package declarations can be for public actions and
for secure actions.
The declaration of the secure package is as follows:
<package name=“myPkgSecure"
namespace="/myPkg/secure"extends="struts-
default"> all secure actions </package>
17. Package Attributes
name (required): Name of the package.
namespace: Namespace for all actions in package.
The namespace is used to find the action. If action doesn’t
exists on given namespace then it is searched in default or
empty namespace.
extends: Parent package to inherit from.
It names another package whose components should be
inherited by the current package.
The current package inherits all the members of the
superclass package and can override them.
Most of the intelligent defaults are defined in a built-in
package called
struts-default which can be inherited by extending struts-
default.
abstract: If true, this package will only be used to define
inheritable components, not actions.
18. struts-default package
The struts-default package, defined in the system’s struts-default.xml file,
declares a huge set of commonly needed Struts 2 components ranging from
complete interceptor stacks to all the common result types.
Contents of the struts-default.xml file:
<package name="struts-default"> // package element
<interceptor-stack name="defaultStack"> // defaultStack
<interceptor-ref name="exception"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="static-params"/>
<interceptor-ref name="params"> // transfers data from request to action
<param name="excludeParams">dojo..*</param>
</interceptor-ref>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
……….
<default-interceptor-ref name="defaultStack"/> // default interceptor stack
……….
</package>
19. Implementing Actions
Struts 2 actions don’t have to implement the Action interface.
Any object can informally honor the contract with the
framework by simply implementing an execute() method that
returns a control string.
The com.opensymphony.xwork2.Action interface defines the
method:
String execute() throws Exception
The constants defined by the Action interface are
public static final String ERROR "error"
public static final String INPUT "input"
public static final String LOGIN "login"
public static final String NONE "none"
public static final String SUCCESS "success"
20. Implementing Actions
<action name="Name">
<result>/chapterOne/NameCollector.jsp</result>
</action>
The Name action doesn’t specify a class to provide the
action implementation because we just want to go to the
JSP page.
The Struts 2 intelligent defaults provide a default action
implementation that is inherited if we don’t specify one.
This default action has an empty execute() method that
does nothing but automatically return the Action
interface’s SUCCESS constant as its control string.
The framework must use control string to choose a result.
The default name attribute for the result element is also the
SUCCESS constant, enabling to automatically select the
action.
21. The ActionSupport class
It provides default implementations of the Action interface
and other useful interfaces, providing data validation and
localization of error messages.
Validation and text localization services are provided via a
combination of interceptors and interfaces.
The interceptors control the execution of the services while
the actions implement interfaces with methods that are
invoked by the interceptors.
The ActionSupport implements two interfaces that
coordinate with one of the interceptors from the default
stack, the DefaultWorkflowInterceptor, to provide basic
validation.
23. Basic Validation Process
The params interceptor moves the request data onto the action
object.
Then, the workflow interceptor validates the data before
accepting it into the model.
The workflow interceptor must fire after the params interceptor
has had a chance to move the data on to the action object.
When the workflow interceptor fires, it looks for a validate()
method on the action to invoke.
validate() method is exposed via the Validateable interface.
ActionSupport implements the validate() method, which is
overridden by implementation specific validation logic.
After all the validation logic has executed, control returns to the
workflow interceptor which checks to see whether any error
messages were generated by the validation logic.
If it finds errors, then the workflow interceptor will immediately
abort the request processing and return the user back to input
form, where appropriate error messages are displayed on the
form.
24. Basic Validation Process
The ValidationAware interface defines methods for storing
and retrieving error messages.
The ActionSupport class provides methods and collections
of general error messages.
addFieldError ( String fieldName, String errorMessage )
addActionError ( String errorMessage )
The workflow interceptor will use methods of
ValidationAware interface to determine whether it should
redirect the workflow back to the input page.
If it finds that errors exist, it’ll look for a result with the
name input.
25. Resource Bundles for Message Text
ActionSupport implements TextProvider interface to provide
localized message text by providing access to the messages.
ActionSupport implements TextProvider’s methods to retrieve
the messages from a properties file resource.
The TextProvider methods returns the message which is
associated with the key from the properties file, associated with
the action class.
The properties file is a simple test file containing a key with its
value and located with its Action class.
The getText() method is used to retrieve the messages from
properties files based upon a key.
ActionSupport also implements LocaleProvider with a single
method getLocale().
The TextProvider, a.k.a. ActionSupport, tries to locate a
properties file for that locale by calling getLocale() of
LocaleProvider.
26. Transferring Data using Object-
backed JavaBeans properties
The params interceptor, included in the defaultStack,
automatically transfers data from the request to our action
objects.
To enable the transfer, the developer needs to provide
JavaBeans properties on the actions, using the same names
as the form fields being submitted.
The struts 2 allows to get the already instantiated and
populated object to the service some object’s methods.
Now the validation code must use a deeper notation to
reach the data items and there is a change in the field
names in the form both at request and response sides.
<s:textfield name="user.username" label="Username"/>
27. Transferring Data using ModelDriven
actions
ModelDriven actions expose an application domain object via
the getModel() method, declared by the ModelDriven interface.
The method introduces a new interceptor which is already
present in the default stack; the data transfer still being
automatic.
The getModel() method returns the model object, which is same
as the action object.
The ModelDriven method needs to initialize the object explicitly
by the developer.
The framework obtains a reference to the model object before
the execute method of ModelDriven action is called.
The framework acquires its reference from the getter, it isn’t
aware of the changes made in the model field internally by the
action causing data inconsistency problems.
All references in the JSP pages return to the simplicity of the
original action that used the simple, individual JavaBeans
properties for data transfer.
28. File uploading
Struts 2 provides built-in help for file uploading.
The default interceptor stack includes FileUpload-
Interceptor used for file uploading.
The struts-default package contains a declaration of the
fileUpload interceptor, backed by FileUploadInterceptor
implementation class.
The interceptor is added to the defaultStack so that all
packages extending the struts-default package will
automatically have this interceptor acting on their actions.
The defaultstack places the fileUpload interceptor just
before the params interceptor.
When the fileUpload interceptor executes, it processes a
multipart request and transforms the file itself, along with
some metadata, into request parameters using a wrapper
around the servlet request.
29. FileUploadInterceptor
Request parameters of the FileUpload interceptor:
[file name from form]: File—the uploaded file itself
[file name from form]ContentType: String—the content type of the file.
[file name from form]FileName : String—the name of the uploaded file, as
stored on the server.
After the fileUpload interceptor has exposed the parts of the multipart request as
request parameters, the params interceptor is fired, and it moves all of the
request parameters onto the action object.
We set the encoding type of the form to multipart/form-data. which signals to
the framework that the request needs to be handled as an upload.
The file is submitted by the form under the name attribute provided in file tag.
Uploading multiple files with same parameter names is supported by changing
the action’s JavaBeans properties to arrays
The JSP code to upload a file:
<s:form action="ImageUpload" method="post" enctype="multipart/form-data">
<s:file name="pic" label="Picture"/>
<s:submit/>
</s:form>
30. Interceptors
Interceptors implement tasks such as cross-cutting, or
preprocessing and postprocessing.
The interceptor sits between controller and action.
The invocation of action is a layered process which always
includes the execution of a stack of interceptors prior to
and after the actual execution of the action itself.
Rather than invoke the action’s execute() method directly,
the framework creates an object called an
ActionInvocation that encapsulates the action and all of
the interceptors that have been configured to fire before
and after that action executes.
Interceptor instances are shared among actions.
Interceptors are stateless.
An interceptor just applies its processing logic to the data
of the request, which is already conveniently stored in the
various objects accessed through the ActionInvocation.
31. Action Invocation and Interceptors
The invocation of an action must first travel through the stack of
interceptors associated with that action.
The normal action ultimately executes and returns a control string that
selects the appropriate result.
After the result executes, each of the interceptors, in reverse order, gets
a chance to do some postprocessing work.
The interceptors have access to the action and other contextual values.
The Interceptors is their ability to alter the workflow of the invocation
or halt the workflow by itself returning a control string.
exception
modelDriven
fileUpload
params
workflow
Action
Result
32. ActionInvocation
ActionInvocation encapsulates all the processing details
associated with the execution of a particular action.
When the framework receives a request, it first must decide
to which action the URL maps.
An instance of this action is added to a newly created
instance of ActionInvocation.
The framework consults the declarative architecture
(created by XML or Java annotations), to discover the
interceptors to fire and their sequence.
References to these interceptors are added to the
ActionInvocation.
The ActionInvocation also holds references to other
important information like the servlet request objects and
a map of the results available to the action.
33. basicStack
The first interceptor in the stack, refers to the first
interceptor declared in the XML as reading from top of the
page down.
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
34. Interceptors Firing Mechanism
The ActionInvocation exposes the invoke() method, called by
the framework to start the execution of the action.
ActionInvocation starts the invocation process on calling the
invoke method, by executing the first interceptor in the stack.
ActionInvocation keeps track of the stage of the invocation
process and decides the appropriate interceptor in the stack to
pass control by calling that interceptor’s intercept() method.
The intercept() takes the ActionInvocation instance itself as a
parameter.
Each time invoke() is called, ActionInvocation consults its state
and executes whichever interceptor comes next in stack
(xml)order.
The interceptor calls invoke() method recursively to invoke and
execute all the subsequent interceptors until, finally, there are
no more interceptors in the stack and the action itself is fired
and executed.
35. intercept() method of TimerInterceptor
public String intercept (ActionInvocation invocation)
throws Exception {
// interceptor’s preprocessing phase
long startTime = System.currentTimeMillis();
// decide to pass control on to the rest of the interceptors.
String result = invocation.invoke();
// postprocessing phase
long executionTime = System.currentTimeMillis() -
startTime;
... log the time ...
return result;
}
36. Interceptor Execution Cycle
The three-stage conditional execution cycle of the
interceptor:
Do some preprocessing.
Pass control on to successive interceptors, and
ultimately the action, by calling invoke(), or divert
execution by itself returning a control string.
Do some postprocessing.
The intercept() method, defined by the Interceptor
interface, is the entry point into an interceptor’s
execution and receives the ActionInvocation instance.
37. Utility interceptors
TIMER: It merely records the duration of an
execution.
Position in the interceptor stack determines what this
is actually timing.
LOGGER: It provides a simple logging mechanism
that logs an entry statement during preprocessing and
an exit statement during postprocessing.
It can be useful for debugging.
Such interceptors do processing both before and after
the action executes.
38. Data transfer interceptors
PARAMS (DEFAULTSTACK): It transfers the request
parameters to properties exposed by the ValueStack.
The framework uses OGNL expressions, embedded in the
name attributes of the form’s fields, to map the data
transfer to those properties.
The action is always put on the ValueStack at the start of a
request-processing cycle and properties exposed directly
on the actions.
The model, as exposed by the ModelDriven interface, is
moved onto the ValueStack by the modelDriven
interceptor.
FILEUPLOAD ( DEFAULTSTACK ): It transforms the files
and metadata from multipart requests into regular request
parameters so that they can be set on the action just like
normal parameters.
39. Data transfer interceptors
STATIC-PARAMS (DEFAULTSTACK):
This interceptor moves parameters defined in the action
elements of the declarative architecture onto properties exposed
on the ValueStack.
In the defaultStack, the static-params interceptor fires before the
params interceptor.
Thus the request parameters overrides values from the XML
param element depending on the order of interceptors.
<action name=“oneAction" class="example.oneAction">
<param name="firstName">John</param>
<param name="lastName">Doe</param>
</action>
AUTOWIRING: It provides an integration point for using Spring
to manage the application and is technically another way to set
properties on the action.
40. Data transfer interceptors
SERVLET-CONFIG ( DEFAULTSTACK ): It provides a clean way
of injecting various objects from the Servlet API into the actions.
It works by setting the various objects on setter methods exposed
by interfaces that the action must implement. Following
interfaces are available for retrieving various objects:
■ ServletContextAware—Sets the ServletContext
■ ServletRequestAware—Sets the HttpServletRequest
■ ServletResponseAware—Sets the HttpServletResponse
■ ParameterAware—Sets a map of the request parameters
■ RequestAware—Sets a map of the request attributes
■ SessionAware—Sets a map of the session attributes
■ ApplicationAware—Sets a map of application scope properties
■ PrincipalAware—Sets the Principal object (security)
Each of these interfaces contains one method—a setter for the
resource.
The servlet-config interceptor will put these objects on your
action during the preprocessing phase.
41. Workflow interceptors
Workflow interceptors inspect the state of the processing
and conditionally intervene and alter the normal path
slightly or drastically.
WORKFLOW (DEFAULTSTACK): It works with the
actions to provide data validation and subsequent
workflow alteration if a validation error occurs.
The Workflow interceptor can take several parameters:
■ alwaysInvokeValidate (true or false; defaults to true,
which means that validate() will be invoked)
■ inputResultName (name of the result to choose if
validation fails; defaults to Action.INPUT)
■ excludeMethods (names of methods for which the
workflow interceptor shouldn’t execute, thereby omitting
validation checking for a specific entry point method on an
action)
42. excludeMethods
The workflow interceptor configured in the defaultStack is
passed a list of excludeMethods parameters, as in the
following snippet from struts-default.xml:
<interceptor-ref name="workflow">
<paramname="excludeMethods">
input,back,cancel,browse</param>
</interceptor-ref>
The exclude methods is meant to support actions that
expose methods other than execute() for various
processing tasks related to the same data object.
44. Workflow interceptors
VALIDATION (DEFAULTSTACK): The validation interceptor, is part
of the Struts 2 validation framework and provides a declarative
means to validate data.
The validation framework allows use of both XML files and Java
annotations to describe the validation rules for the data.
The validation interceptor itself executes the validation logic.
The validation interceptor is the entry point into the validation
framework’s processing.
When the validation framework does its work, it’ll store validation
errors using the same ValidationAware methods as the validate() code
does.
When the workflow interceptor checks for error messages, it doesn’t
know whether they were created by the validation framework or the
validation code invoked through the Validateable interface.
Validation interceptor fires before the workflow interceptor, and this
sequencing is handled by the defaultStack.
45. Workflow interceptors
PREPARE (DEFAULTSTACK): The prepare
interceptor provides a generic entry point for arbitrary
workflow processing.
When the prepare interceptor executes, it checks
whether the action implements the Preparable
interface, and defines the prepare() method.
If the action is Preparable, the prepare() method is
invoked allowing any sort of preprocessing to occur.
Even though the prepare interceptor has a specific
place in the defaultStack, one can define his own stack
in order to move the prepare code to a different
location in the sequence.
46. Prepare Interceptor
The prepare interceptor allows to define special prepare
methods for the different execution methods on a single
action providing more than one execution entry point on
the action.
E.g. Action method: input(), Prepare Methods:
prepareInput() and prepareDoInput().
When input() method is being invoked, the prepareInput()
method is called by the prepare interceptor.
The prepare() method itself will always be called by the
prepare interceptor regardless of the action method being
invoked unless turned off by the parameter
alwaysInvokePrepare (false) passed to prepare interceptor.
The Preparable interface is helpful for setting up resources
or values before the action is executed.
47. Workflow interceptors
MODELDRIVEN (DEFAULTSTACK):
The modelDriven interceptor is considered a workflow
interceptor as it alters the workflow of the execution by
invoking getModel(), if present, and setting the model
object on the top of the ValueStack where it receives the
parameters from the request.
By placing the model over the action in the ValueStack, the
modelDriven interceptor alters workflow.
Such concept of creating an interceptor that can
conditionally alter the effective functionality of another
interceptor without direct programmatic intervention
demonstrates the power of the layered interceptor
architecture.
48. Miscellaneous interceptors
EXCEPTION (DEFAULTSTACK): The exception
interceptor comes first in the defaultStack.
It will catch exceptions and map them, by type, to user-
defined error pages.
Its position at the top of the stack guarantees that it’ll be
able to catch all exceptions that may be generated during
all phases of action invocation as, it’ll be the last to fire
during postprocessing.
<global-results>
<result name="error">/chapterFour/Error.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception"
result="error"/>
</global-exception-mappings>
49. Miscellaneous interceptors
The exception-mapping element tells the exception interceptor which
result to render for a given exception.
The exception interceptor creates an ExceptionHolder object and place
it on top of the ValueStack.
The ExceptionHolder is a wrapper around an exception that exposes the
stack trace and the exception as JavaBeans properties (exception and
exceptionStack) accessible from a tag in error page.
TOKEN AND TOKEN-SESSION:
The token and token-session interceptors is used as part of a system to
prevent duplicate form submissions.
Duplicate posts can occur when users click Submit more than once.
The token interceptors work by passing a token in with the request that
is checked by the interceptor.
If the unique token comes to the interceptor a second time, the request
is considered a duplicate.
Both the interceptors do the same thing, differing only in the method of
handling the duplicate request.
50. Miscellaneous interceptors
SCOPED-MODELDRIVEN (DEFAULTSTACK): It
supports persistence of the action’s model object across
series of requests.
It adds to the functionality of the modelDriven interceptor
by allowing to store the model object in the session scope
for instance.
It helps to implement wizards working with a data object
across a series of requests.
EXECANDWAIT:
When a request takes a long time to execute, it’s nice to
give the user some feedback.
The execAndWait interceptor helps prevent the users from
getting antsy and provides them with some feedback.
51. Built-in stacks
The struts-default package provides built-in stacks for
the interceptors such as defaultStack to provide
convenient arrangements of the built-in interceptors.
The built-in stacks are inherited in the packages by
extending the struts-default package defined in struts-
default.xml.
The unused interceptors don’t affect the performance.
Interceptor declarations from the struts-default
package is as follows:
54. Declaring Interceptors
The interceptors element contains all the interceptor and
interceptor-stack declarations of the package.
Interceptor stacks are used to reference a sequenced chunk of
interceptors by name.
Each interceptor element declares an interceptor that can be
used in the package by mapping an interceptor implementation
class to a logical name.
The contents of the interceptor-stack element are a sequence of
interceptorref elements which point to one of the logical names
created by the interceptor elements.
The interceptor-ref elements can also pass in parameters to
configure the instance of the interceptor that is created by the
reference.
A package can declare a default set of interceptors associated
with all actions in those packages that don’t explicitly declare
their own interceptors.
The default-interceptor-ref element simply points to a logical
name, such as the defaultStack in struts default package.
55. Mapping interceptors to actions
Associating an interceptor to an action is done with an
interceptorref element.
<action name="MyAction" class="org.MyAction">
<interceptor-ref name="timer"/>
<interceptor-ref name="logger"/>
<result>Success.jsp</result>
</action>
They are fired in the order they are listed.
References to stacks and individual interceptors can be
combined to avoid repetition of the same definitions.
<interceptor-ref name="defaultStack"/>
The actions that don’t define any interceptor-refs inherit
the default interceptors, but as soon as an action declares
its own interceptors, it loses the automatic default and
must explicitly name the defaultStack in order to use it.
56. Setting and overriding parameters
The interceptor-ref element is the place to pass the parameters to
the interceptor.
<interceptor-ref name="workflow">
<param name="exMethods">input,back</param>
</interceptor-ref>
In order to reuse the defaultStack by taking a reference, but
changing the values of its parameter we use following snippet:
<action name="YourAction" class="org.act.YourAction">
<interceptor-ref name="defaultStack">
<param name="work.exMethods">doSomething</param>
</interceptor-ref>
<result>Success.jsp</result>
</action>
57. Building an Interceptor
Must implement Interceptor interface to build an
interceptor.
public interface Interceptor extends Serializable {
void destroy(); // initialize
void init(); // clean up
String intercept(ActionInvocation invocation);
}
To build interface having parameter filtering enabled
by accepting request parameters, extend the
MethodFilterInterceptor class.
58. OGNL
OGNL stands for the Object-Graph Navigation
Language.
OGNL is a technology integrated into the Struts 2
framework to help with data transfer and type
conversion.
It is the glue between the framework’s string-based
HTTP input and output and the Java-based internal
processing.
OGNL consists of two things from developer’s point of
view: an expression language and type converters.
59. Expression Language
OGNL’s expression language is used in form input field names
and JSP tags.
The OGNL expressions bind Java-side data properties to strings
in the text-based view layers, found in the name attributes of
form input fields, or in various attributes of the Struts 2 tags.
Struts 2 property tag takes a value from a property of Javaobjects
and writes it into the HTML in place of the tag.
It allows to use a simplified syntax to reference objects that
reside in the Java environment.
OGNL expressions require no special escaping and Struts 2
automatically evaluates the string as an OGNL expression in all
contexts.
In contexts where strings are most likely going to be strings, the
framework will require the OGNL escape sequence.
It helps to move data from the request parameters onto the
action’s JavaBeans properties, and from those properties out into
rendering HTML pages.
60. Type Converters
OGNL Type Converters are responsible for conversion
between the Java type of the property referenced by the
OGNL expression language to the string format of the
HTML output.
Every time data moves to or from the Java environment, a
translation must occur between the string version of that
data residing in the HTML and the appropriate Java data
type.
The built-in type converters allows to map the incoming
form fields to a wide variety of Java data types, including all
the primitives as well as a variety of collections.
61. OGNL role in framework: DATAIN
The user enters two values for the fields of the input.html and
submit the form to the framework.
When the request enters the framework, it’s exposed to the Java
language as an HttpServletRequest object.
The request parameters are stored as name/value pairs, and both
name and value are Strings.
The framework handles the transfer and type conversion of the
data from the request parameters.
The data object (User) is exposed as JavaBeans property on the
action object. With the action object on the ValueStack, the
OGNL can place the data in the data object.
The params interceptor will move the data from the request
object to the ValueStack.
OGNL handles the mapping of the name of the parameter to an
actual property on the ValueStack.
OGNL consults a set of available type converters in the
framework to handle any type conversion.
62. ValueStack
The ValueStack is a Struts 2 construct that presents an
aggregation of the properties of a stack of objects as
properties of a single virtual object.
ValueStack represents the data model exposed to the
current request and is the default object against which all
OGNL expressions are resolved
The ValueStack is a virtual object and holds a stack of
objects.
All the properties of objects in ValueStack appear as
properties of the ValueStack itself.
The properties of the higher objects in the stack cover up
similarly named properties of objects lower in the stack.
ValueStack holds the data objects and acts as a place holder
for viewing the data model throughout the various regions
of the framework mostly using OGNL expression language.
63. Built-in type converters
■ String—A string is just a string.
■ boolean/Boolean—true and false strings can be
converted to both primitive and object versions of Boolean.
■ char/Character—Primitive or object.
■ int/Integer, float/Float, long/Long, double/Double—
Primitives or objects.
■ Date—String version will be in SHORT format of current
Locale (for example, 12/10/97).
■ array—Each string element must be convertible to the
array’s type.
■ List—Populated with Strings by default.
■ Map—Populated with Strings by default
When the framework locates the Java property targeted by an
OGNL expression, it looks for a converter for that type.
If converter of such type is in the preceding list, the data is
received else require a custom type converter.
64. Multi-Valued Request Parameters
Multiple parameter values can be mapped to a single parameter name in
the incoming request.
The multivalued request parameters can be transferred to a variety of
collection-oriented data types, ranging from arrays to actual Collections.
Arrays: Struts 2 provides support for converting data to Java arrays with
the help of OGNL support.
<s:form action="ArraysDataTransferTest">
<s:textfield name="ages" label="Ages"/>
<s:textfield name="ages" label="Ages"/>
<s:textfield name="names[0]" label="names"/>
<s:textfield name="names[1]" label="names"/>
<s:submit/>
</s:form>
The ages parameter is send as single request parameter with 2 values.
The ages array is created and initialized by OGNL.
The names parameter is send as 2 parameters with distinct values. The
OGNL interprets the references to names elements in a names array
which is pre-initialized.
65. Request Parameters to Lists
Lists: Struts 2 supports automatically converting sets of request
parameters into Lists.
By default, the framework will convert request parameters into
Strings and populate the List property with those Strings.
When OGNL is informed of the element type for a given
property in a properties file (ClassName-conversion.properties),
OGNL converts List elements to corresponding property type.
With Element-weights=java.lang.Double line in property file,
<s:textfield name="weights[0]" label="weights"/> enables
each individual weights element to be converted to a Double.
It is not required to preinitialize any of the Lists, even though the
data is received from the indexed OGNL notation.
The Struts 2 type conversion mechanism can use generics-based
typing to learn the correct target type for the conversions.
The List should not be preinitialized when using the typed
element conversion mechanism supported by properties file.
66. Request Parameters to Lists
Struts 2 supports automatic conversion of a set of values from a
request into a Map property.
The Maps must have a type specified for the key object
Both the Map element and key has a default to a String if type is
not specified.
Examples of Map property is as follows:
<s:textfield name="maidenNames.mary" label="Maiden
Name"/>
<s:textfield name="maidenNames['beth']" label="Maiden
Name"/>
Examples of Map property submitting data as follows:
<s:textfield name="myUsers['chad'].username"
label="Usernames"/>
<s:textfield name="myUsers.chad.birthday" label="birthday"/>
Similar to element, specifying type for key objects involve adding
Key_myOrderedUsers=java.lang.Integer to the property file.
67. Customizing type conversion
Type conversion is a part of OGNL and all type converters must
implement the ognl.TypeConverter interface.
StrutsTypeConverter class is base class which acts as a convenient
extension point for custom type conversion. It has following abstract
methods:
public abstract Object convertFromString(Map context, String[] values,
Class toClass);
public abstract String convertToString(Map context, Object o);
The string parameter for conversion can be array of strings.
Logic consist of string parsing and object creation.
Throw a TypeConversionException in case of conversion error.
Converter can be configured to be used local to a given action or globally.
The ActionName-conversion.properties file is used to specify the
custom converter locally for a specific property with following line:
circle=manning.utils.CircleTypeConverter.
The xwork-conversion.properties file in WEB-INF/classes/ is used to
specify the custom converter globally for a specific property with
following line: manning.utils.Circle=manning.utils.CircleTypeConverter.