Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Apache Struts - From Novice To Professional (2006)

.pdf
Скачиваний:
60
Добавлен:
17.08.2013
Размер:
11.68 Mб
Скачать

348

C H A P T E R 2 0 J A V A S E R V E R F A C E S A N D S T R U T S S H A L E

Listing 20-15. New <managed-bean> Declarations for the Registration Webapp

<managed-bean> <managed-bean-name>logon</managed-bean-name>

<managed-bean-class>net.thinksquared.reg.User</managed-bean-class> <managed-bean-scope>request</managed-bean-scope>

</managed-bean>

<managed-bean> <managed-bean-name>register</managed-bean-name>

<managed-bean-class>net.thinksquared.reg.User</managed-bean-class> <managed-bean-scope>request</managed-bean-scope>

</managed-bean>

As you can see, we’ve used the naming rule we discussed earlier. Also, the binding and value attributes in register.jsp and logon.jsp will have to change. Instead of using

#{used.XXX}, you have to use either #{logon.XXX} or #{register.XXX}, as appropriate.

Dialog Manager

According to the Shale website, Shale’s Dialog Manager is a “mechanism to define a ‘conversation’ with a user that requires multiple HTTP requests to implement, modeled as a state diagram.”

So, a dialog is an interaction with the user spanning multiple HTTP requests. Shale lets you model a dialog (you can define more than one dialog) in an XML file, usually called dialog-config.xml. You must declare this in your web.xml file like so:

<context-param> <param-name>org.apache.shale.dialog.CONFIGURATION</param-name> <param-value>/WEB-INF/dialog-config.xml</param-value>

</context-param>

If you have more than one dialog configuration file, simply add them to the declaration using a comma as a separator.

Each “dialog” is modeled as a state diagram. Listing 20-16 shows how we might define a couple of dialogs for the Registration webapp.

Listing 20-16. Dialogs for the Registration Webapp (dialog-config.xml)

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE dialogs PUBLIC

"-//Apache Software Foundation//DTD Shale Dialog Configuration 1.0//EN" "http://struts.apache.org/dtds/shale-dialog-config_1_0.dtd">

C H A P T E R 2 0 J A V A S E R V E R F A C E S A N D S T R U T S S H A L E

349

<dialogs>

<dialog name="Logon" start="Perform Logon">

<action name="Perform Logon" method="#{logon.Logon}"> <transition outcome="success" target="Exit"/> <transition outcome="register" target="Register User"/>

</action>

<subdialog name="Register User" dialogName="Register User"> <transition outcome="success" target="Exit"/>

</subdialog>

<end name="Exit" viewId="/success.jsp"/>

</dialog>

<dialog name="Register User" start="Registration Form">

<view name="Registration Form" viewId="/register.jsp"> <transition outcome="register" target="Perform Registration"/>

</view>

<action name="Perform Registration" method="#{register.Register}"> <transition outcome="success" target="Exit"/>

</action>

<end name="Exit" viewId="/success.jsp"/>

</dialog>

</dialogs>

The logic of Listing 20-16 should be obvious. Notice that we’ve used the new <managed-bean> declarations of Listing 20-15 here.

Note The Registration webapp doesn’t fully reveal the usefulness of Shale’s dialogs, because the user interaction spans only a couple of pages.

350

C H A P T E R 2 0 J A V A S E R V E R F A C E S A N D S T R U T S S H A L E

Notice that in Listing 20-16 all the transition information is contained in the dialog-config.xml file. But in our earlier JSF implementation, the JSP pages invoked the functions on the user backing bean directly like so:

<h:commandButton action="#{user.Logon}" ... //see Listing 20-11 <h:commandLink action="register"> ... //see Listing 20-11 <h:commandButton action="#{user.Register}" ... //see Listing 20-12

We’ll have to change these to

<h:commandButton action="dialog:Logon" ...

<h:commandLink action="dialog:Register User"> ...

<h:commandButton action="register" ...

because the navigation is now performed using Shale’s Dialog Manager, not by JSF’s default navigation handler. Notice that the action attributes now begin with dialog:XXX, with XXX the “name” of the dialog. The command button that submits the registration information (on register.jsp):

<h:commandButton action="register" ...

is different because it needs to return a logical outcome and not enter into a dialog directly:

<view name="Registration Form" viewId="/register.jsp"> <transition outcome="register" target="Perform Registration"/>

</view>

Lastly, note that you can mix both JSF-type navigation and Shale’s dialog-based navigation. All you need to do in order to enter a Shale dialog is to use a logical outcome named dialog:XXX. In our case, we’ve moved all the navigation elements from Listing 20-8 into the dialog config file, so the faces-config.xml file should now only contain the <managed-bean> declarations.

Exercise

Download the latest copy of the Shale distribution (see “Useful Links”) and implement the Registration webapp as we’ve discussed up to this point.

Integration with the Validator Framework

At the time of this writing, the integration with the Validator framework does not include the use of a validations.xml file in which you can declare your validations.

C H A P T E R 2 0 J A V A S E R V E R F A C E S A N D S T R U T S S H A L E

351

Instead, Shale’s approach to integration with the Validator framework is very similar to the MyFaces approach of creating extensions to JSF. The one big advantage Shale has is that you can create client-side validations, as you can with Struts.

For server-side validations, however, the MyFaces approach appears cleaner, at least for the moment. Shale is a moving target!

Here’s how to use Shale’s validator tags:

1.Add validator-rules.xml from the Commons Validator distribution to your WEB-INF directory. You can use the one that comes with classic Struts.

2.Put in this taglib declaration: <%@ taglib uri="http://struts.apache.org/shale/ core" prefix="s" %>.

3.Add Shale’s validators to JSF input components with <s:commonsValidator>.

If you want client-side validation, you need to add the extra attribute onsubmit='validateForm(this)' and the child tag <s:validatorScript functionName= "validateForm"/> to the <h:form>. The former invokes the JavaScript functions to validate the form, while the latter instructs Shale to paste in the JavaScript validation code.

Listing 20-17 shows how we might rewrite logon.jsp (see Listing 20-11) using Shale’s Validator framework. As usual, we’ve stripped out the <f:verbatim> tags.

Listing 20-17. logon.jsp Using Shale

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>

<%@ taglib uri="http://struts.apache.org/shale/core" prefix="s"%>

<f:loadBundle basename="net.thinksquared.reg.messages" var="reg_messages"/>

<html>

<body>

<f:view>

<h:panelGroup>

<h:messages style="color:red" globalOnly="true"/> <h:outputText value="#{reg_messages['title_reg']}"

style="font-weight:bold" />

<h:form binding="#{user.container}" onsubmit=”validateForm(this)”>

<h:outputText value="#{reg_messages['user_id']}"/>

352

C H A P T E R 2 0 J A V A S E R V E R F A C E S A N D S T R U T S S H A L E

<h:inputText id="userId"

value="#{logon.userId}" required="true">

<s:commonsValidator type="mask" mask="^[A-Za-z0-9]{5,10}$" arg="#{reg_messages['bad_user_id']}"

server="true"

client="true"/>

</h:inputText>

<h:message for="userId" />

<h:outputText value="#{reg_messages['password']}"/>

<h:inputText id="password" value="#{logon.password}" required="true">

<s:commonsValidator type="mask" mask="^[A-Za-z0-9\-\_]{5,10}$" arg="#{reg_messages['bad_user_id']}"

server="true"

client="true"/>

</h:inputText>

<h:message for="password" />

<h:commandButton action="dialog:Logon" value="#{reg_messages['logon']}"/>

<s:validatorScript functionName="validateForm"/>

</h:form>

<h:commandLink action="dialog:Register User"> <h:outputText value="#{reg_messages['new_user']}" />

</h:commandLink>

</h:panelGroup>

</f:view>

</body>

</html>

Notice that we’ve put in the changes we made in the previous two subsections.

C H A P T E R 2 0 J A V A S E R V E R F A C E S A N D S T R U T S S H A L E

353

JNDI Integration

JNDI (Java Naming and Directory Interface) is a Java Enterprise Edition feature that obtains handles to resources that are declared in either web.xml or configuration settings of an application server.

A thorough discussion of JNDI is outside the scope of this book. However, the Shale website gives a couple of simple examples, variations of which we’ll describe here.

JNDI addresses the concept of environment entries, which are simply variable declarations in web.xml. For example, suppose your webapp had to display your company’s logo on each page. You could use a message resource to store the URL, but another way is to use an environment entry (I’m not recommending this method, but just using it as an illustration).

First, you declare the environment entry in web.xml:

<env-entry>

<description>URL to company logo GIF</description> <env-entry-name>logo</env-entry-name> <env-entry-value>http://www.myco.myapp/logo.gif</env-entry-value> <env-entry-type>java.lang.String<env-entry-type>

</env-entry>

Your JSF tags can use Shale’s JNDI integration feature to access this environment entry:

<h:graphicImage value=#{jndi:logo} />

That’s it. The jndi: prefix tells Shale that the binding refers to a JNDI resource, in this case, the one environment entry named logo.

A more realistic scenario involves getting a database connection. JNDI allows you to declare data source references in web.xml. For example, you might define a data source reference to your company’s personnel database like so:

<resource-ref>

<description>MyCo Personnel Database</description> <res-ref-name>jdbc/MyCoPersonnelDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth>

</resource-ref>

Typically, you’d want to create and release the database connection in your backing beans. Listing 20-18 shows how we can use Shale’s JNDI integration to provide an implementation of init() of Listing 20-14.

354

C H A P T E R 2 0 J A V A S E R V E R F A C E S A N D S T R U T S S H A L E

Listing 20-18. An Implementation of User.init()

public void init(){ //get faces context

FacesContext context = FacesContext.getCurrentInstance();

//create _connection to database. ValueBinding vb =

context.getApplication()

.createValueBinding("#{jndi['jdbc/MyCoPersonnelDB'].connection}");

_connection = (Connection) vb.getValue(context);

}

Reusable Views with Clay

Clay is a subframework of Shale. It is essentially a custom JSF custom UI component, which acts as a stand-in for a sub-UI tree defined elsewhere. This idea should not be new to you. Tiles does something similar—you define the UI in a tiles-def.xml file, then use a Tiles tag to indicate where you want the UI placed.

Clay does the same, but provides more options for you to build the UI tree. Any meaningful exploration of Clay would require a whole chapter by itself, so I will leave it to you to explore this interesting technology on your own.

Server-Side Ajax Support

Ajax is not a single technology but refers to a broad spectrum of technologies characterized by their use of client-side JavaScripts and XML to pass data between client and server.

Server-side Ajax support (aka remoting) involves extracting data from the Model tier and serializing it as XML for delivery to the client.

Shale’s remoting support is mainly focused on the delivery of XML data to the client (e.g., the org.apache.shale.remote.ResponseWrapper class to write XML), and management of the remote sessions.

Test Framework

Unit testing is the process of incrementally building and testing your code. In the unittesting paradigm, you code a little, then test a little, and continue until your app is done. The tests you create are Java classes that you need to run in sequence, each testing portions of your code. JUnit (see “Useful Links”) is the universally used unit-testing framework of the Java world.

C H A P T E R 2 0 J A V A S E R V E R F A C E S A N D S T R U T S S H A L E

355

Believe me, unit testing can save you a lot of trouble, even on moderately complex applications. Once you’ve tried it, you’ll wonder how you ever managed to produce Java code in the past.

Unfortunately, unit testing has made little inroads into the testing of webapps. Shale supports unit testing by providing you with a set of mock objects and JUnit test case base classes. Check out the JUnit website for more details.

Exercise

Download the latest Shale distribution (see “Useful Links”) and try out the example use-cases webapp.

JSF vs. Shale vs. Struts

Ultimately, which technology you choose (JSF, Shale, or Struts) depends on your requirements. Having said that, if you’re comfortable with the Apache offerings, then you’re likely to commit to Shale over pure JSF. Shale brings so much to the table that using it over pure JSF is a no-brainer.

The Achilles’ heel of Shale is that it’s in a state of flux, like any new piece of software. At the time of this writing many of the services are marked as “Developing,” meaning they could change at any time. I certainly expect Shale to change substantially by the time you read this book. So, if you’re planning to use Shale, you should carefully research the features you need to ensure that they are fairly stable. The Struts mailing list (Shale shares this with classic Struts, so you should mark your emails with [Shale]) and the Shale documentation are good resources.

The choice between Struts and Shale is more difficult to make. If you have an existing Struts webapp, it’s advisable to continue using Struts, because the cost of porting your existing JSP pages to using JSF tags is usually prohibitive.

For new projects, it’s difficult to give a clear answer. The Struts developers themselves and those involved in JSF and Shale appear to unconditionally advocate moving to Shale or JSF. I would be more circumspect, because as you’ve seen, JSF (and therefore Shale) is more complex than Struts. It isn’t rocket science, but there’s definitely a sharp learning curve involved.

However, if you find you’ve been using strange tricks to force Struts into getting your webapp to behave like a desktop application, then Shale is definitely something you’d want to explore along with other web application frameworks like Spring.

I’ve avoided giving you a feature-by-feature comparison of Struts, JSF, and Shale. Although they are all, broadly speaking, web application frameworks, their “sweetspots” (the scenarios in which they shine) are different.

356

C H A P T E R 2 0 J A V A S E R V E R F A C E S A N D S T R U T S S H A L E

Instead, Table 20-3 compares classic Struts, JSF, and Shale to help you answer a simple question: “I’m starting a new project. Should I use Struts or Shale or JSF?” Take the ratings as being relative to each other. Please don’t take them to be absolute in any sense—“easy” for example, means “easy compared to” the other options.

Table 20-3 doesn’t take into account the Struts-Faces integration library. Even if it did, probably not much would change. Struts suffers from design issues that won’t go away easily. These deficiencies (poor extensibility, code modularity and code reuse) come to the fore when you’re developing more complex applications. The Struts-Faces library, though useful, doesn’t address architectural issues.

Table 20-3. Comparison Matrix for Struts, JSF and Shale

Factor

Struts

JSF

Shale

Comments

 

 

(MyFaces)

 

 

 

 

 

 

 

Learning curve

Gentle

Average

Steep

Shale’s learning curve is steepest because it

 

 

 

 

introduces additional services on top of JSF.

Developing

Easy

Difficult

Average

By a “simple” webapp I mean something like

simple webapps

 

 

 

LILLDEP in complexity. Many webapps cur-

 

 

 

 

rently fall into this category. Shale, with its

 

 

 

 

Dialog Manager, improves page transition

 

 

 

 

maintenance. This is a definite plus over

 

 

 

 

pure JSF.

Developing

Very

Average

Average/Easy

By “complex” webapps I mean a webapp

complex

difficult

 

 

that (for example) replicates the full func-

webapps

 

 

 

tionality of OpenOffice Writer (or Word).

 

 

 

 

Shale, with its extensibility, and extras (like

 

 

 

 

support for Ajax, dialogs, etc.) makes life

 

 

 

 

much better.

Extensibility

Poor

Very good

Good

Struts only offers plug-ins for extensibility

 

 

 

 

(and more limited extensibility in the form of

 

 

 

 

custom loaders for the configuration file).

 

 

 

 

You can do a lot with the extensibility points

 

 

 

 

that Struts offers, but you’d have to reinvent

 

 

 

 

the wheel sometimes, as I did in Chapter 19.

 

 

 

 

Both JSF and Shale offer much more struc-

 

 

 

 

tured ways in which you can extend them.

Longevity

High

Very high

Moderate/Low

By longevity, I mean “What’s the probability

 

 

 

 

of this framework being around in five years’

 

 

 

 

time?” These are my forecasts: JSF’s survival

 

 

 

 

is assured, given Sun’s endorsement of it as a

 

 

 

 

spec, and as the only credible components-

 

 

 

 

based web framework for the Java platform.

 

 

 

 

Struts classic will probably survive because

 

 

 

 

of its huge user base. Shale might be over-

 

 

 

 

shadowed by competing technologies in the

 

 

 

 

same niche, ones that don’t pretend to be a

 

 

 

 

“Struts successor.” So it’s very unfortunate

 

 

 

 

that it’s named Struts Shale. People then

 

 

 

 

tend to think in terms of Struts classic versus

 

 

 

 

Struts Shale, when in fact, they best apply to

 

 

 

 

different niches.

C H A P T E R 2 0 J A V A S E R V E R F A C E S A N D S T R U T S S H A L E

357

Table 20-3. Comparison Matrix for Struts, JSF and Shale

Factor

Struts

JSF

Shale

Comments

 

 

(MyFaces)

 

 

 

 

 

 

 

Ease of

Easy

Easy

Difficult

If classic Struts remains backward compati-

upgrading

 

 

 

ble, then obviously it’s easy to upgrade. JSF

 

 

 

 

is a mature spec, so you shouldn’t expect

 

 

 

 

surprises there either. Shale, on the other

 

 

 

 

hand, is changing (at the time of this writing),

 

 

 

 

so you might experience difficulty upgrad-

 

 

 

 

ing to a newer version.

Code reuse

Low

High

Average

Code reuse becomes important in more com-

 

 

 

 

plex projects, so the ratings given here apply

 

 

 

 

mainly to them. JSF was built with reuse and

 

 

 

 

extensibility foremost.

Modular Code

Low

Average

Average

It’s difficult to make modular code with

 

 

 

 

Struts for complex webapps. You might have

 

 

 

 

gotten a glimpse of this in Lab 14. It’s easy to

 

 

 

 

create modular code with JSF if you know

 

 

 

 

how, but it’s also easy to make a mess of it.

 

 

 

 

Code modularity impacts maintenance and

 

 

 

 

development. The more modular the code,

 

 

 

 

the easier it is to maintain and develop. See

 

 

 

 

the answer for the question raised in Chapter 1,

 

 

 

 

given in Appendix D, for a short discussion

 

 

 

 

of this.

 

 

 

 

 

Useful Links

The official JSF specification: http://java.sun.com/j2ee/javaserverfaces/ download.html

MyFaces website: http://myfaces.apache.org/

Struts-Faces integration library download site: http://jakarta.apache.org/site/ binindex.cgi

The Sun JSF download site: http://java.sun.com/j2ee/javaserverfaces/ download.html

The official Shale website: http://struts.apache.org/struts-shale/index.html

Struts Ti website: http://struts.apache.org/struts-sandbox/struts-ti/index.html

WebWork website: www.opensymphony.com/webwork/

Struts OverDrive website: http://opensource2.atlassian.com/confluence/oss/ display/OVR/Home