Nice book written by Donald Brown, Chad Michael Davis, and Scott Stanlick
Having played with many frameworks i must admit that i have enjoyed Apache Beehieve framework in combination with weblogic 9.2 workshop as IDE.
Few points i want to share from the book
1) Frameworks such as Struts 2 strive to release the developer from the mundane concerns of the domain by providing a reusable architectural solution to the core web application workflows.
2) Apache Struts 2 is a brand-new, state-of-the-art web application framework. Struts 2 isn’t just a new release of the older Struts 1 framework. It is a completely new framework, based on the esteemed OpenSymphony WebWork framework.
3) The role of the controller is played by the Struts 2 FilterDispatcher. This important object is a servlet filter that inspects each incoming request to determine which Struts 2 action should handle the request.
4) Struts 2 goes a long way toward the goal of zero-configuration web applications.Zero-configuration aims at deriving all of an application’s metadata,such as which URL maps to which action, from convention rather
than configuration. The use of Java annotations plays an important role in this zero-configuration scheme. While zero-configuration has not quite been achieved, you can currently use annotations and conventions to drastically reduce XML-based configuration.
5) Interceptors are Struts 2 components that execute both before and after the rest of the 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.
6) THE VALUESTACK AND OGNL
While interceptors may not absorb a lot of your daily development energies, the ValueStack and OGNL will be constantly on your mind. In a nutshell, the ValueStack is a storage area that holds all of the data associated with the processing of a request.You could think of it as a piece of scratch paper where the framework does its work while solving the problems of request processing. Rather than passing the data around,
Struts 2 keeps it in a convenient, central location—the ValueStack.OGNL is the tool that allows us to access the data we put in that central repository.More specifically, it is an expression language that allows you to reference and manipulate the data on the ValueStack.
7) Struts 2 uses the ValueStack as a storage area for all application domain data that will be needed during the processing of a request. Data is moved to the ValueStack in preparation for request processing, it is manipulated there during action execution, and it is read from there when the results render their response pages.
The data in the ValueStack follows the request processing through all phases; it slices through the whole length of the framework. It can do this because it is stored in a ThreadLocal context called the ActionContext.
8) OGNL is a powerful expression language that is used to reference and manipulate properties on the ValueStack.
9) The ActionContext contains all of the data that makes up the context in which an action occurs. This includes the ValueStack but also includes stuff the framework itself will use internally, such as the request, session, and application maps from the Servlet API. You can access these objects yourself if you like; we’ll see how later in the book. For now, we just want to focus on the ActionContext as the ThreadLocal home of the ValueStack. The use of ThreadLocal makes the ActionContext, and thus the ValueStack, accessible from anywhere in the same thread of execution.Since Struts 2’s processing of each request occurs in a single thread, the ValueStack is available from any point in the framework’s handling of a request.
Typically, it is considered bad form to obtain the contents of the ActionContext yourself. The framework provides many elegant ways to interact with that data without actually touching the ActionContext, or the ValueStack, yourself. OGNL is used in many places in the framework to reference and manipulate data in the ValueStack. For instance, OGNL is used to bind HTML form fields to data objects on the ValueStack for data transfer, and to pull data into the rendering of your JSPs and other result types.The ValueStack is where your data is stored while you work with it,and that OGNL is the expression language that we, and the framework, use to target this data from various parts of the request-processing cycle.
10) By default, Struts 2 looks for URLs ending in .action, but you could configure the framework to look for .do ( the Struts 1.x default extension) or even no extension at all.
11) Intelligent defaults
Many commonly used Struts 2 components (or attributes of components) do not need to be declared by the developer. Regardless of which declaration style you choose, these components and attribute settings are already declared by the framework so that you can more quickly implement the most common portions of application functionality. Some framework components, such as interceptors and result types, may never need to be directly declared by the developer because those provided by the system handle the daily requirements of most developers. Other components,such as actions and results, will still need to be declared by the developer, but many common attribute settings can still be inherited from framework defaults.
Intelligent defaults provide out-of-the-box components that solve common domain workflows without requiring further configuration by the developer, allowing the most common application tasks to be realized with minimum development.
These predefined components are part of the Struts 2 intelligent defaults. In case you’re interested, many of these components are declared in struts-default.xml, found in the struts2-core.jar. This file uses XML to declare an entire package of intelligent default components, the struts-default package.
12) Unless we have compelling reasons, you should always extend the struts-default package in the xml file declaration file.
Example
<package name="chapterThreePublic" namespace="/chapterThree" extends="struts-default">
13) ActionSupport also provides a basic internationalization solution for the localizing message text. The com.opensymphony.xwork2.LocaleProvider interface exposes a single method, getLocale(). ActionSupport implements this interface to retrieve the user’s locale based upon the locale setting sent in by the browser.
14) ModelDriven actions
ModelDriven actions depart from the use of JavaBeans properties for exposing domain data. Instead, they expose an application domain object via the getModel() method,which is declared by the com.opensymphony.xwork2.ModelDriven interface. While this method introduces a new interface, as well as another interceptor, it’s simple in practice.The interceptor is already in the default stack; the data transfer is still automatic and even easier to work with than previous techniques.
15) As with most tasks that you find yourself doing routinely, Struts 2 provides built-in help for file uploading. In this case, the default interceptor stack includes the FileUpload-Interceptor.
16) In Struts 2, no action is invoked in isolation. The invocation of an action is a layered process that 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.
17) In the case of the workflow interceptor that has found error messages on the action, the control string is "input",which typically maps back to the form page that submitted the invalid data.
18) The 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. Next, the framework consults the declarative architecture, as created by the application’s XML or Java annotations, to discover which interceptors should fire, and in what sequence.References to these interceptors are added to the ActionInvocation.In addition to these central elements, the ActionInvocation also holds references to other important information like the servlet request objects and a map of the results available to the action. Now let’s look at how the process of invoking an action occurs.
The ActionInvocation exposes the invoke() method, which is called by the framework to start the execution of the action. When the framework calls this method, the ActionInvocation starts the invocation process by executing the first interceptor in the stack. Note that the invoke() method doesn’t always map to the first interceptor; it’s the responsibility of the ActionInvocation itself to keep track of what stage the invocation process has reached and pass control to the appropriate interceptor in the stack. It does this by calling that interceptor’s intercept() method.
19) The framework itself starts the process by making the first call to the ActionInvocation object’s invoke() method. ActionInvocation hands control over to the first interceptor in the stack by calling that interceptor’s intercept() method. Importantly, intercept() takes the ActionInvocation instance itself as a parameter. During its own processing, the interceptor will call invoke() on this object to continue the recursive process of invoking successive interceptors. Thus, in normal execution, the invocation process tunnels down through all of the interceptors until, finally, there are no more interceptors in the stack and the action fires. Again, the ActionInvocation itself maintains the state of this process internally so it always knows where it is in the stack.Now let’s look at what an interceptor can do when it fires. An interceptor has a three-stage, conditional execution cycle:
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.
Looking at some code will make these three stages more concrete. The following code snippet shows the intercept() method of the TimerInterceptor, one of the interceptors included in the struts-default package.
public String intercept(ActionInvocation invocation) throws Exception {
long startTime = System.currentTimeMillis();
String result = invocation.invoke();
long executionTime = System.currentTimeMillis() - startTime;
... log the time ...
return result;
}
20) The servlet-config interceptor provides a clean way of injecting various objects from the Servlet API into your actions. This interceptor works by setting the various objects on setter methods exposed by interfaces that the action must implement. The following interfaces are available for retrieving various objects related to the servlet environment. Your action can implement any number of these.
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)
21) Mapping interceptors to actions
Much of the time, your actions will belong to packages that extend struts-default, and you’ll be content to let them use the defaultStack of interceptors they inherit from that package. Eventually, you’ll probably want to modify, change, or perhaps just augment that default set of interceptors. To do this, you have to know how to map interceptors to your actions. Associating an interceptor to an action is done with an interceptorref element. The following code snippet shows how to associate a set of interceptors with a specific action:
<action name="MyAction" class="org.actions.myactions.MyAction">
<interceptor-ref name="timer"/>
<interceptor-ref name="logger"/>
<result>Success.jsp</result>
</action>
22) Setting and overriding parameters
Many interceptors can be parameterized. If an interceptor accepts parameters, the interceptor-ref element is the place to pass them in. We can see that the workflow interceptor in the defaultStack is parameterized to ignore requests to certain action method names, as specified in the excludeMethods parameter element.
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
23) OGNL is currently the default expression language used to reference data from the various regions of the framework in a consistent manner.OGNL stands for the Object-Graph Navigation Language.
24) Action object is placed on something called the ValueStack and that the OGNL expressions target properties on that stack object.
The # operator tells OGNL to use the named object, located in its context, as the initial object for resolving the rest of the expression.With Struts 2, the OGNL context is the ActionContext and, thankfully, there’s a session object in that context.
In MVC terms, the ValueStack is the request’s view of the application’s model data.
25) Note the similarity between the bracket syntax used to force the String attribute
to evaluate as an OGNL expression and the JSTL Expression Language syntax.
| Struts 2 OGNL Syntax | JSTL Expression Language |
|---|---|
| %{ expression } | ${ expression } |
26) THE DOUBLESELECT COMPONENT
The doubleselect component addresses the common need to link two select boxes together so that selecting one value from the first box changes the set of choices available in the second box. Such a component might link a first select box of state names to a second box of city names. If you select California in the first box, you get a list of California cities in the second box. When you change to another state, the second box automatically changes to reflect this choice.
To use the doubleselect component, you first have to tell the component which data set it should use to generate the first select box. This works just like setting up a normal select component. The same attributes are used and they function in the same fashion as before. Next, you have to specify a property that’ll refer to another data set that can be used as the second list. This property will effectively need to refer to multiple sets of data, most likely one for each item in the first list—for example, a set of cities for each state in the first list. While this can begin to sound tricky, you need to recall that all these things resolve against the ValueStack. With this in mind,everything should make perfect sense.
<pre>
<h4>Select a portfolio to view.</h4>
<s:form action="ViewPortfolio">
<s:doubleselect name="username" list='users' listKey="username"
listValue="username" doubleName="portfolioName"
doubleList="portfolios" doubleListValue="name" />
<s:submit value="View"/>
</s:form>
</pre>
27) Integration With Tiles
Apache Tiles is a framework that allows developers to build templates that simplify the development of web application user interfaces. If you’re using Tiles to manage your site layout, the Struts 2 Tiles plug-in provides a new result type that utilizes your tile definitions for rendering pages.
web.xml
<context-param>
<param-name>
org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG
</param-name>
<param-value>/tiles/myTiles.xml</param-value>
</context-param>
...
<listener>
<listener-class>
org.apache.struts2.tiles.StrutsTilesListener
</listener-class>
</listener>
The context parameter B is where we specify the location of our Tiles definitions file,and the listener C is how we bootstrap the integration. The plug-in creates a new result type that you can use to specify that Tiles should render the result.
Sample Xml File
<struts>
<package name="members" namespace="/members" extends="tiles-default">
<result-types>
<result-type
name="tiles"
class="org.apache.struts2.views.tiles.TilesResult"
default="true"/>
</result-types>
<action name="list">
<result>membersPage</result>
</action>
</package>
</struts>
Hope you enjoy reading this book.
About The Authors
Don Brown is the Technical Lead for Hosted Services at Atlassian Software Systems, with a background in the commercial and US Department of Defense sectors. He is a member of the Apache Software Foundation, and has been a Struts committer since 2003. He is also a committer on several Apache Commons projects and a frequent speaker at JavaOne, ApacheCon, and Java user groups.
Chad Davis is a J2EE developer, software consultant, and writer. He has a wide background in writing that ranges from government research and public relations to academic writing in computer science. In addition to publications in a variety of computer science journals, he has published poetry and written draft legislation at the state level.
Scott Stanlick is a corporate IT instructor with experience in embedded systems, client-server applications, and large scale distributed applications. As a musician needing a "real job" to buy musical gear, he earned a B.A. in Computer Science and has been writing software to pay for his drumming habit ever since. He builds web sites during his free time and plays shows most weekends
2 comments:
Very Informative
very nicely arranged and informative, good work
Post a Comment