|
» View this article in PDF
Part 1 | Part 2 | Part 3
Enhanced Web Tier Capabilities
Some of the most significant enhancements made in Java EE 6 appear in the web tier. As mentioned earlier, one of the
goals of Java EE 6 is to make the platform more extensible, and two key improvements in
the area of extensibility are web fragments
and shared framework pluggability. These two new features are
provided in Java EE 6 by Servlet 3.0 technology.
Servlet 3.0, JSR 315,
the latest version of Servlet technology, offers some other valuable enhancements such as
support for asynchronous processing and support for annotations.
Another important Java EE 6 web tier technology is JSF 2.0, the latest version of JSF technology. Among its benefits,
JSF 2.0 simplifies page and component authoring through Facelets, and
adds support for asynchronous JavaScript and XML (commonly referred to as Ajax), and
annotations.
Support for Web Fragments in Servlet 3.0
Web application developers often use third-party frameworks such as Apache Wicket or Spring MVC in their
applications. To use these frameworks, developers need to register the frameworks in the web application, a task
that involves configuring framework-specific artifacts such as servlets and listener classes. It's typical for developers
to register these frameworks by specifying deployment descriptors for the frameworks in the application's
web.xml file — the same file that contains deployment descriptors for the web components that
constitute the web application. Not only does this make for some very large web.xml, files but it also
makes it difficult to isolate and maintain the descriptors for the frameworks.
|
Web fragments enable web frameworks to self-register, eliminating the need
for you to register them through deployment descriptors.
|
Web fragments, a new feature of Servlet 3.0 technology, solves this problem by modularizing
deployment descriptors. A web fragment can be considered a logical segment of a web.xml file.
There can be multiple web fragments, each representing a logical segment, and the set of web fragments can be viewed
as constituting an entire web.xml file. This logical partitioning of the web.xml file
enables web frameworks to self-register to the web container. Each web framework that you use in a web application
can define in a web fragment all the artifacts that it needs, such as servlets and listeners, without requiring
you to edit or add information in the web.xml file.
Here is an example of a web fragment that registers a servlet and a listener:
<web-fragment>
<servlet>
<servlet-name>myFrameworkServlet</servlet-name>
<servlet-class>myFramework.myFrameworkServlet</servlet-class>
</servlet>
<listener>
<listener-class>myFramework.myFrameworkListener</listener-class>
</listener>
</web-fragment>
|
The <web-fragment> element identifies a web fragment. A web fragment
must be in a file named web-fragment.xml and can be placed in any location in a web
application's classpath. However, it's expected that a web framework will typically place its web fragments in the
META-INF directory of the framework's JAR file, which will typically
reside in the WEB-INF/lib directory of the web application.
You use the element <metadata-complete> in the web.xml file
to instruct the web container whether to look for web fragments
as well as annotations — see Annotations in More Types of
Java EE Components for information about annotations provided by Servlet 3.0 technology.
If you set <metadata-complete> to false, or do not specify the
<metadata-complete> element in your web.xml file, then
during deployment, the container must scan web fragments and annotations to build the effective metadata for the web application.
In response, the web container searches for web fragments and annotations in framework JAR files.
The web container then uses the configuration information in each web fragment to register the framework for use with the
web application. However, setting <metadata-complete> to true, causes the deployment descriptors to
provide all the configuration information for the web application. In this case, the web container does not search for web
fragments and annotations.
|
With its support for web fragments, Servlet 3.0 technology lets you modularize
your web.xml file.
|
Because Servlet 3.0 technology supports web fragments, you can modularize your web.xml file.
Your web application can still have the traditional, monolithic web.xml file, or it can have
a logically partitioned web.xml file that includes one or more web fragments.
However, because Servlet 3.0 enables you to modularize your deployment descriptors, the order in which these descriptors
are processed can be important. For example, the order in which the descriptors
for an application are processed affects the order in which servlets, listeners, and filters are invoked.
With Servlet 3.0, you can specify the order in which deployment descriptors are processed.
Servlet 3.0 supports absolute ordering and relative ordering of deployment descriptors. Your specify absolute ordering using
the <absolute-ordering> element in the web.xml file. You specify relative ordering
with an <ordering> element in the web-fragment.xml file.
For example, suppose your application includes two web fragments — MyFragment2 and MyFragment3,
and also includes a web.xml file. You can declare absolute ordering of the descriptors by specifying the
following in the web.xml file for the application:
<web-app>
<name>MyApp</name>
<absolute-ordering>
<name>MyFragment3</name>
<name>MyFragment2</name>
</absolute-ordering>
...
</web-app>
|
Here, the processing order would be as follows:
web.xml. The web.xml descriptor is always processed first.
MyFragment3.
MyFragment2.
Shared Framework Pluggability
Web fragments and annotations are not the only way that Servlet 3.0 allows you to extend a web application.
You can also plug in shared copies of frameworks, such as Java API for XML-Based Web Services (JAX-WS), JAX-RS and JSF,
that are built on top of the web container. Servlet 3.0 introduces a new interface called ServletContainerInitializer that
can be used to plug in a framework.
For example, here's how you can plug in a framework named A:
@HandlesTypes(AnnotationA.class)
AServletContainerInitializer implements ServletContainerInitializer
{
public void onStartup(Set<Class<A>>c, ServletContext ctx) throws ServletException {
// Framework-specific code here to initialize the runtime
// and setup the mapping etc.
ServletRegistration reg = ctx.addServlet("AServlet", "com.foo.AServlet");
reg.addServletMapping("/foo");
|
The container discovers the ServletContainerInitializer using the JAR services API. It does this when the container
or application is started. The framework implementing the ServletContainerInitializer must
bundle in the META-INF/services directory of its JAR file a file called
javax.servlet.ServletContainerInitializer that points to the implementation class of the ServletContainerInitializer.
The @HandlesTypes annotation specifies the types that the ServletContainerInitializer can handle.
Any classes of those types discovered in any JAR contained in the WEB-INF/lib directory are passed to the ServletContainerInitializer.
The ServletContainerInitializer is then able to use the same programmatic configuration APIs as ServletContextListeners.
Asynchronous Processing in Servlet 3.0
Servlet 3.0 introduces support for asynchronous processing. With this support, a servlet no longer has
to wait for a response from a resource such as a database before its thread can continue processing, that is,
the thread is not blocked. This support enables long-lived client connections such as those in chat room applications.
In these types of applications you don't want a server thread to be blocked for
a long period of time serving a request from a single client. You
want the servlet to process a request from the client and then free up the server thread
as quickly as possible for other work.
Among its benefits, support for asynchronous processing makes the use of servlets with Ajax more efficient.
|
A servlet no longer has to wait for a response from a resource such as a database
before its thread can continue processing.
|
Servlets and servlet filters that support asynchronous processing must be written with the goal
of asynchrony in mind. In particular, several long-standing
assumptions about the order in which some methods will be called do not apply for asynchronous processing. To ensure that
code written for synchronous processing won't be used in an asynchronous context, Servlet 3.0 requires you to
use the asyncSupported=true attribute.
To make a servlet asynchronous, you specify asyncSupported=true in a
@WebServlet annotation and make asynchronous requests in the servlet. You can
also mark a servlet filter as asynchronous by specifying asynchSupported=true in
a @WebFilter annotation. Only after taking these steps are taken the corresponding classes available
for asynchronous invocations.
The support for asynchronous processing also includes new ServletRequest methods, such as
startAsync(), to make an asynchronous request, and new classes, such as
AsyncContext, which provides the execution context for an asynchronous operation.
Here, for example, is a servlet that makes an asynchronous request.
@WebServlet(name="CalculatorServlet", asyncSupported=true, urlPatterns={"/calc", "/getVal"})
public class CalculatorServlet extends HttpServlet{
public void doGet(HttpServletRequest req, HttpServletResponse res) {
...
AsyncContext aCtx = req.startAsync(req, res);
}
...
}
|
Notice that the startAsync() method returns an AsyncContext object. This object holds the
request and response objects that were passed in the call to the method. At this point, the thread
that served the original request is available for other operations.
Servlet 3.0 also introduces a new listener class, AsyncListener, that notifies you when
an asynchronous operation is complete or if a timeout occurs. The AsyncContext class includes
a complete() method, with which you can commit the response after an asynchronous operation is complete.
The AsyncListener class also has a dispatch() method that forwards the
asynchronous request to the container so that other frameworks such as JSP can generate the response.
Simplified Page Authoring in JSF 2.0
JavaServer Faces technology provides a server-side component framework that simplifies the development
of user interfaces (UIs) for Java EE applications. The latest release of the technology,
JSF 2.0, JSR 314, makes UI development for
Java EE applications even easier. One area of particular improvement is page authoring. Authoring a JSF
page is much easier in JSF 2.0 through the use of the standard JavaServer Faces View Declaration Language, commonly
called Facelets.
Facelets
|
Facelets is a powerful but lightweight declaration language that you can use to
present JSF pages.
|
Facelets is a powerful but lightweight declaration language that you can use to present JSF pages. In the
Facelets approach, you use HTML-style templates to present a JSF page and to build component trees. Although JSF
can be used with different display technologies, most JSF applications use JSP as the display
technology. In other words, the UI in a JSF application is typically a JSP page that contains JSF components.
However, Facelets offers several advantages over JSP.
|
Facelets is now the preferred presentation technology for building JSF-based applications.
|
In JSP, elements in a web page are processed and rendered in a progressive order. However, JSF provides its own
processing and rendering order. This can cause unpredictable behavior when web applications are executed.
Facelets resolves this mismatch. Facelets also enables code reuse through templating
and can significantly reduce the time to develop and deploy UIs. For these reasons, Facelets is now the
preferred presentation technology for building JSF-based applications.
Facelets are usually written with XHTML markup language. This allows Facelets pages to be portable
across diverse development platforms. Here, for example, is a Facelets XHTML page that is part
of a sample JSF application provided with the
Java EE 6 Tutorial.
<xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<title>Guess Number JSF Application</title>
</head>
<body>
<h:form>
<h2>
Hi. My name is Duke. I am thinking of a number from <b>
<h:outputText value="#{UserNumberBean.minimum}"/> to
<b>
<h:outputText value="#{UserNumberBean.maximum}"/>.
<p>
Can you guess it ?
</p>
<h:graphicImage id="waveImg" url="/wave.med.gif" />
<h:inputText id="userNo"
value="#{UserNumberBean.userNumber}">
converterMessage="#{ErrMsg.userNoConvert}">
<f:validateLongRange
minimum="#{UserNumberBean.minimum}"
maximum="#{UserNumberBean.maximum}"/>
</h:inputText>
<h:commandButton id="submit"
action="success" value="submit" />
<h:message showSummary="true" showDetail="false"
style="color: red;
font-family: 'New Century Schoolbook', serif;
font-style: oblique;
text-decoration: overline"
id="errors1"
for="userNo"/>
</h2>
</h:form>
</body>
</html>
|
The page renders the UI shown in Figure 1. The UI prompts a user to guess a number that the
system — in the person of Duke, the Java technology mascot — has selected. The UI displays
the text Hi my name is Duke. I am thinking of a number from min to max. , where
min and max represent the minimum and maximum values allowable as
a guess, respectively. The UI also displays the Duke image, a text field for the user to enter a number, and a button
to submit the form.
Figure 1. A UI Created With Facelets
|
This Facelets XHTML page is not very different from an equivalent JSP page. In particular,
Facelets supports JSF and JSTL tag libraries. Facelets also includes a Facelets tag library that enables
feature-rich page templating. The namespace
declaration xmlns:ui="http://java.sun.com/jsf/facelets" is for the Facelets tag
library — although no tags in that library are used in this example. Facelets also supports the unified
expression language.
It might not be evident here what additional value Facelets
provides over JSP. To better understand the value of Facelets, lets examine two of its most powerful features:
templating and composite components.
Templating
|
Templating allows you to create a page that acts as a template for other
pages in an application.
|
With templating, you can create a page that acts as a template for other pages in an application.
This helps you avoid creating similarly constructed pages multiple times. Templating also helps maintain
a standard look and feel in an application with a large number of pages.
The Facelets tag library contains a templating tag, <ui:insert>. To implement
templating, you create a template page that includes the <ui:insert> tag.
You then create a client page that uses the template. In the client page, you use
a <ui:composition> tag to point to the template and <ui:define> tags
to specify content to insert into the template.
Here is an example of a template page.
<xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
<head>
<title><ui:insert name="title">Page Title</ui:insert</title><body>
</head>
<body>
<div>
<ui:insert name="Links"/>
</div>
<div>
<ui:insert name="Data"/>
</div>
</body>
</html>
|
Here is an example of a client page that uses the template.
<xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
<body>
<ui:composition template="/template.xhtml">
This text will not be displayed.
<ui:define name="title">
Welcome page
</ui:define>
<ui:define name="Links">
... [Links should be here]
</ui:define>
<ui:define name="Data">
... [Data should be here]
</ui:define>
</ui:composition>
This text also will not be displayed.
</body>
</html>
|
When the template is invoked by the client, it renders a page with the title Welcome Page.
The page also displays two sections: one that lists the links specified in the client, and one that shows
the data specified in the client.
Composite Components
|
Composite components makes it easy to create customized JSF components.
|
Composite components is a new feature in JSF that makes it easy to create customized JSF components. You can
create composite components by using JSF page markup, other JSF UI components, or both. And with the help of Facelets,
any XHTML page can become a composite component. In addition, composite components can have validators, converters,
and listeners attached to them just like the set of UI components provided by JSF.
After you create a composite component,
you can store it in a library and use it as needed.
Let's create a composite component that is rendered as a login panel. When a user logs in, the component reports
a login event as shown in Figure 2.
Figure 2. Composite Component
|
Here is the source code for the composite component.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
xmlns:f="http://java.sun.com/jsf/facelets">
xmlns:composite="http://java.sun.com/jsf/composite">
<h:head>
<title>This content will not be displayed in the rendered output</title>
</h:head>
<h:body>
<composite:interface>
<composite:actionSource name="loginEvent"/>
</composite:interface>
<composite:implementation>
<table>
<tr>
<td>Username: <h:inputText id="username" /> </td>
</tr>
<tr>
<td>Password: <h:inputSecret id="password" /></td>
</tr>
<tr>
<td><h:commandButton value="Login" id="loginEvent" /></td>
</tr>
</table>
</composite:implementation>
</h:body>
</html>
|
The declaration xmlns:composite="http://java.sun.com/jsf/composite"
declares the namespace for composite UI components. The <composite:interface> tag
declares the usage contract for the composite component, in other words, what a page author needs
to know to use the composite component. The <composite:attribute> tag in the usage contract
specifies a <composite:actionSource> tag. This tag indicates that the component can
expose an event, making it accessible by any page that uses the composite component.
The <composite:implementation> tag defines the implementation for the composite component.
Here the implementation is a simple table that contains JSF components for the username and password fields
and a login button.
To make the composite component available for use, you save the code in an XHTML file
and then store the file in a subdirectory of the resources directory under the application root directory.
The name of the subdirectory is taken to be the name of the resource library that contains the composite component.
The JSF runtime finds the composite component by appending .xhtml to the name of the composite component's tag.
For example, if you name the tag loginPanel, store the code for the composite component in a file named
loginPanel.xhtml.
You can then use the composite component in a web page. Here, for example, is the code for the web page shown in
Figure 2 that uses the composite component.
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:ez="http://java.sun.com/jsf/composite/ezcomp">
<head>
<title>Example 01>/title>
<style type="text/css">
.grayBox { padding: 8px; margin: 10px 0; border: 1px solid #CCC; background-color: #f9f9f9; }
</style>
</h:head>
<h:body>
<p>Usage of Login Panel Component</p>
<ui:debug hotkey="p" rendered="true"/>
<h:form>
<div id="compositeComponent" class="grayBox" style="border: 1px solid #090;">
<ez:loginPanel>
<f:actionListener for="loginEvent" type="example01.LoginActionListener" />
</ez:loginPanel>
</div>
<p><h:commandButton value="reload" /></p>
<p><h:outputText value="#{loginActionMessage}" /></p>
</h:form>
</h:body>
</html>
|
Notice the declaration xmlns:ez="http://java.sun.com/jsf/composite/ezcomp".
This specifies the namespace and prefix for the composite component. In this case, ezcomp
is the name of the subdirectory in the resources directory. JSF uses the following convention: for any namespace
URI starting with http://java.sun.com/jsf/composite/, the one and only path segment that ends the namespace URI
is taken to be the name of the resource library in which the Facelets XHTML files for the composite components are found.
The <f:actionListener> tag associates an action listener with the composite component.
The for attribute in the tag indicates that this listener is for the action event named
loginEvent on the composite component. You would also need to provide code
to process the event. For example, you might provide code that looks something like the following:
import javax.faces.component.UIComponent;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
public class LoginActionListener implements ActionListener {
public void processAction(ActionEvent event) throws AbortProcessingException {
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getRequestMap().put("loginActionMessage",
"Login event happened");
}
}
|
Support for Ajax in JSF 2.0
|
JSF 2.0 has built-in support for Ajax, making it
easier to develop dynamic web applications that take advantage of both JSF technology and Ajax.
|
JSF 2.0 has built-in support for Ajax.
With Ajax, web applications can retrieve data from the server asynchronously in the background without
interfering with the display and behavior of the existing page.
In support of Ajax, JSF's request processing cycle has been expanded to allow partial page
updates and partial view traversal. Partial view traversal allows one or more components in a view to
be visited, potentially to have them pass through either or both the execute phase or render phase of the
request processing lifecycle. This is a key feature in JSF and Ajax frameworks and it allows selected components
in the view to be processed, rendered, or both.
To use Ajax with JSF you need to access a JavaScript resource that has
the resource identifier jsf.js. The resource, which exists under the javax.faces
resource library, contains the JavaScript API that enables JSF to interact with Ajax.
The JavaScript API comprises a standard set of JavaScript functions that facilitate Ajax operations in a
JavaServer Faces framework. You rarely need to include this file directly. JSF automatically includes it
whenever you use any Ajax-enabled tags or components in your view.
You can then make an Ajax request in either of two ways. You can use the
<f:ajax> tag or you can invoke functions in the JavaScript API.
Here is an example that uses the <f:ajax> tag:
<h:commandButton id="button1">
<f:ajax execute="..." render="..."/>
</h:commandButton>
|
Here, the <f:ajax> tag is nested inside an <h:commandButton> tag. This associates the
Ajax action specified in the execute attribute with the command button rendered by the <h:commandButton> tag.
You can also specify an event attribute to identify the JavaScript DOM event to which the Ajax action applies.
If you do not specify an event attribute, JSF uses the default action for the component. In this case,
the default action is onclick, so JSF associates the Ajax request specified in the execute
attribute with the onclick event of the rendered button. When a user clicks the button, JSF submits the Ajax request
to the server.
One benefit of using the <f:ajax> tag is that you don't have to specifically load the jsf.js resource
in your page — it is done automatically for you. By comparison, if you invoke the JavaScript API, you first have to
make the jsf.js resource available to the current view, using an <h:outputScript> tag. For example:
<f:view contentType="text/html"/>
<h:head>
<meta...
<title...
</h:head>
<h:body>
...
<h:outputScript name="jsf.js" library="javax.faces" target="body"/>
...
</h:body>
...
|
You then use functions in the JavaScript API to make Ajax requests. For example, you use the JavaScript function
jsf.ajax.request to send an Ajax request to the server, as shown in the following code
example. The code includes a <h:commandButton> tag that renders a button. When a user clicks
the button, an Ajax request is submitted to the server.
<h:commandButton id="button1" value="submit">
onclick="jsf.ajax.request(this,event);" />
|
JSF 2.0's built-in support for Ajax makes it a lot easier to develop dynamic web applications
that take advantage of both JSF technology and Ajax.
More New Features in Servlet 3.0 and JSF 2.0
This section covered only some of the many new features and enhancements in
Servlet 3.0 and JSF 2.0. Another new feature of note in Servlet 3.0 enables you to
use methods in the ServletContext class to programmatically add servlets
and servlet filters to a web application during startup.
You use the addServlet() method to add a servlet
to the web application, and the addFilter() method to add a servlet filter.
The ability to programmatically add servlets and servlet filters at startup
is particularly useful to framework writers. In conjunction with the shared framework pluggability
feature by which extension libraries can discover classes listed in the @HandlesTypes annotation, with this facility
web frameworks can configure themselves with no developer intervention.
In addition, Servlet 3.0 works with a number of enhanced security features.
For example, in addition to declarative security, Servlet 3.0 offers programmatic
security through the HttpServletRequest interface. You can, for example, use the
authenticate() method of HttpServletRequest in an application to
perform username and password collection, or you can use the login() method to direct the container
to authenticate the request caller from within an unconstrained request context.
For more information about these and other features in Servlet 3.0, see
Servlet 3.0, JSR 315.
Some additional enhancements in JSF 2.0 relate to how resources are packaged and handled.
JSF 2.0 standardizes where resources are packaged. All resources now go in
a resources directory or a subdirectory. Resources are any artifacts that a component may need in order
to be rendered properly, such as CSS files or JavaScript files. Figure 3 shows part of a
NetBeans IDE project
for a JSF application. Notice the resources directory in the project and the CSS and image resources
it contains.
Figure 3. Resources in the resources Directory of a JSF Application
|
JSF 2.0 also includes new APIs for representing and handling resources.
You use the javax.faces.application.Resource class to represent a resource. You
use the javax.faces.application.ResourceHandler class to create instances of
resources as well as to serve resources to the requesting user agent.
For more information about these and other features in JSF 2.0, see
JavaServer Faces 2.0: A Complete Tour.
Also see the JSR 314: JavaServer Faces 2.0 specification.
» Continue to the next part of this article
Part 1 | Part 2 | Part 3
Comments
We welcome your participation in our community. Please keep your comments civil and on
point. You may optionally provide your email address to be notified of
replies - your information is not used for any other purpose. By submitting a comment, you agree to these Terms of Use.
|