The Java EE 7
Tutorial
Release 7 for Java EE Platform
E39031-01
August 2014
The Java EE 7 Tutorial, Release 7 for Java EE Platform
E39031-01
Copyright © 2014, Oracle and/or its affiliates. All rights reserved.
Primary Author:
Eric Jendrock, Ricardo Cervera-Navarro, Ian Evans, Kim Haase, William Markito
Contributing Author:
Contributor:
This software and related documentation are provided under a license agreement containing restrictions on
use and disclosure and are protected by intellectual property laws. Except as expressly permitted in your
license agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license,
transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means. Reverse
engineering, disassembly, or decompilation of this software, unless required by law for interoperability, is
prohibited.
The information contained herein is subject to change without notice and is not warranted to be error-free. If
you find any errors, please report them to us in writing.
If this is software or related documentation that is delivered to the U.S. Government or anyone licensing it
on behalf of the U.S. Government, the following notice is applicable:
U.S. GOVERNMENT RIGHTS Programs, software, databases, and related documentation and technical data
delivered to U.S. Government customers are "commercial computer software" or "commercial technical data"
pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As
such, the use, duplication, disclosure, modification, and adaptation shall be subject to the restrictions and
license terms set forth in the applicable Government contract, and, to the extent applicable by the terms of
the Government contract, the additional rights set forth in FAR 52.227-19, Commercial Computer Software
License (December 2007). Oracle America, Inc., 500 Oracle Parkway, Redwood City, CA 94065.
This software or hardware is developed for general use in a variety of information management
applications. It is not developed or intended for use in any inherently dangerous applications, including
applications that may create a risk of personal injury. If you use this software or hardware in dangerous
applications, then you shall be responsible to take all appropriate fail-safe, backup, redundancy, and other
measures to ensure its safe use. Oracle Corporation and its affiliates disclaim any liability for any damages
caused by use of this software or hardware in dangerous applications.
Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of
their respective owners.
Intel and Intel Xeon are trademarks or registered trademarks of Intel Corporation. All SPARC trademarks
are used under license and are trademarks or registered trademarks of SPARC International, Inc. AMD,
Opteron, the AMD logo, and the AMD Opteron logo are trademarks or registered trademarks of Advanced
Micro Devices. UNIX is a registered trademark of The Open Group.
This software or hardware and documentation may provide access to or information on content, products,
and services from third parties. Oracle Corporation and its affiliates are not responsible for and expressly
disclaim all warranties of any kind with respect to third-party content, products, and services. Oracle
Corporation and its affiliates will not be responsible for any loss, costs, or damages incurred due to your
access to or use of third-party content, products, or services.
Contents
Preface ........................................................................................................................................................... xxxix
Audience................................................................................................................................................. xxxix
Documentation Accessibility ............................................................................................................... xxxix
Before You Read This Book........................................................................................................................ xl
Related Documentation .............................................................................................................................. xl
Conventions ................................................................................................................................................. xl
Default Paths and File Names ................................................................................................................... xl
Part I
Introduction
1 Overview
1.1
1.2
1.3
1.3.1
1.3.2
1.3.3
1.3.3.1
1.3.3.2
1.3.3.3
1.3.3.4
1.3.3.5
1.3.4
1.3.5
1.3.6
1.4
1.4.1
1.4.2
1.5
1.5.1
1.5.2
1.5.3
1.6
1.7
1.7.1
Java EE 7 Platform Highlights................................................................................................... 1-2
Java EE Application Model ....................................................................................................... 1-2
Distributed Multitiered Applications ...................................................................................... 1-3
Security.................................................................................................................................. 1-4
Java EE Components ........................................................................................................... 1-4
Java EE Clients ..................................................................................................................... 1-5
Web Clients.................................................................................................................... 1-5
Application Clients....................................................................................................... 1-5
Applets ........................................................................................................................... 1-5
The JavaBeans Component Architecture .................................................................. 1-6
Java EE Server Communications................................................................................ 1-6
Web Components ................................................................................................................ 1-6
Business Components ......................................................................................................... 1-7
Enterprise Information System Tier.................................................................................. 1-8
Java EE Containers...................................................................................................................... 1-8
Container Services ............................................................................................................... 1-9
Container Types ................................................................................................................... 1-9
Web Services Support.............................................................................................................. 1-10
XML .................................................................................................................................... 1-11
SOAP Transport Protocol ................................................................................................ 1-11
WSDL Standard Format................................................................................................... 1-11
Java EE Application Assembly and Deployment................................................................ 1-12
Java EE 7 APIs .......................................................................................................................... 1-12
Enterprise JavaBeans Technology .................................................................................. 1-15
iii
1.7.2
Java Servlet Technology...................................................................................................
1.7.3
JavaServer Faces Technology ..........................................................................................
1.7.4
JavaServer Pages Technology .........................................................................................
1.7.5
JavaServer Pages Standard Tag Library ........................................................................
1.7.6
Java Persistence API .........................................................................................................
1.7.7
Java Transaction API ........................................................................................................
1.7.8
Java API for RESTful Web Services................................................................................
1.7.9
Managed Beans .................................................................................................................
1.7.10
Contexts and Dependency Injection for Java EE..........................................................
1.7.11
Dependency Injection for Java ........................................................................................
1.7.12
Bean Validation .................................................................................................................
1.7.13
Java Message Service API................................................................................................
1.7.14
Java EE Connector Architecture .....................................................................................
1.7.15
JavaMail API......................................................................................................................
1.7.16
Java Authorization Contract for Containers.................................................................
1.7.17
Java Authentication Service Provider Interface for Containers.................................
1.7.18
Java API for WebSocket ...................................................................................................
1.7.19
Java API for JSON Processing.........................................................................................
1.7.20
Concurrency Utilities for Java EE...................................................................................
1.7.21
Batch Applications for the Java Platform ......................................................................
1.8
Java EE 7 APIs in the Java Platform, Standard Edition 7 ...................................................
1.8.1
Java Database Connectivity API.....................................................................................
1.8.2
Java Naming and Directory Interface API ....................................................................
1.8.3
JavaBeans Activation Framework ..................................................................................
1.8.4
Java API for XML Processing..........................................................................................
1.8.5
Java Architecture for XML Binding ...............................................................................
1.8.6
Java API for XML Web Services .....................................................................................
1.8.7
SOAP with Attachments API for Java ...........................................................................
1.8.8
Java Authentication and Authorization Service...........................................................
1.8.9
Common Annotations for the Java Platform ................................................................
1.9
GlassFish Server Tools ............................................................................................................
1-15
1-16
1-16
1-17
1-17
1-17
1-17
1-17
1-18
1-18
1-18
1-18
1-18
1-19
1-19
1-19
1-19
1-20
1-20
1-20
1-20
1-20
1-21
1-21
1-21
1-21
1-22
1-22
1-22
1-22
1-22
2 Using the Tutorial Examples
2.1
Required Software ...................................................................................................................... 2-1
2.1.1
Java Platform, Standard Edition ........................................................................................ 2-1
2.1.2
Java EE 7 Software Development Kit................................................................................ 2-1
2.1.2.1
SDK Installation Tips ................................................................................................... 2-2
2.1.3
Java EE 7 Tutorial Component........................................................................................... 2-2
2.1.4
NetBeans IDE ....................................................................................................................... 2-2
2.1.4.1
To Install NetBeans IDE without GlassFish Server ................................................. 2-2
2.1.4.2
To Add GlassFish Server as a Server Using NetBeans IDE.................................... 2-3
2.1.5
Apache Maven ..................................................................................................................... 2-3
2.2
Starting and Stopping GlassFish Server .................................................................................. 2-3
2.2.1
To Start GlassFish Server Using NetBeans IDE............................................................... 2-3
2.2.2
To Stop GlassFish Server Using NetBeans IDE ............................................................... 2-3
2.2.3
To Start GlassFish Server Using the Command Line ..................................................... 2-3
2.2.4
To Stop GlassFish Server Using the Command Line ..................................................... 2-4
iv
2.3
2.3.1
2.4
2.4.1
2.5
2.6
2.7
2.7.1
2.7.1.1
2.7.1.2
2.8
2.8.1
2.8.2
2.9
2.9.1
2.9.1.1
2.9.2
2.9.2.1
Starting the Administration Console .......................................................................................
To Start the Administration Console Using NetBeans IDE...........................................
Starting and Stopping the Java DB Server...............................................................................
To Start the Database Server Using NetBeans IDE.........................................................
Building the Examples ...............................................................................................................
Tutorial Example Directory Structure .....................................................................................
Java EE 7 Maven Archetypes in the Tutorial ..........................................................................
Installing the Tutorial Archetypes ....................................................................................
Installing the Tutorial Archetypes Using NetBeans IDE ........................................
Installing the Tutorial Archetypes Using Maven ....................................................
Getting the Latest Updates to the Tutorial..............................................................................
To Update the Tutorial Using NetBeans IDE ..................................................................
To Update the Tutorial Using the Command Line.........................................................
Debugging Java EE Applications .............................................................................................
Using the Server Log ...........................................................................................................
To Use the Administration Console Log Viewer.....................................................
Using a Debugger ................................................................................................................
To Debug an Application Using a Debugger ...........................................................
2-4
2-4
2-4
2-5
2-5
2-5
2-6
2-6
2-6
2-6
2-6
2-6
2-6
2-7
2-7
2-7
2-7
2-7
Part II Platform Basics
3 Resource Creation
3.1
3.2
3.3
Resources and JNDI Naming .................................................................................................... 3-1
DataSource Objects and Connection Pools ............................................................................. 3-2
Creating Resources Administratively ...................................................................................... 3-2
4 Injection
4.1
4.2
4.3
Resource Injection ....................................................................................................................... 4-1
Dependency Injection................................................................................................................. 4-2
The Main Differences between Resource Injection and Dependency Injection................. 4-2
5 Packaging
5.1
5.2
5.2.1
5.2.2
5.3
5.4
Part III
Packaging Applications .............................................................................................................
Packaging Enterprise Beans ......................................................................................................
Packaging Enterprise Beans in EJB JAR Modules...........................................................
Packaging Enterprise Beans in WAR Modules ...............................................................
Packaging Web Archives ...........................................................................................................
Packaging Resource Adapter Archives ...................................................................................
5-1
5-2
5-3
5-3
5-4
5-5
The Web Tier
6 Getting Started with Web Applications
6.1
6.2
6.3
Web Applications........................................................................................................................ 6-1
Web Application Lifecycle......................................................................................................... 6-2
A Web Module That Uses JavaServer Faces Technology: The hello1 Example................. 6-3
v
6.3.1
To View the hello1 Web Module Using NetBeans IDE.................................................. 6-3
6.3.1.1
Introduction to Scopes ................................................................................................. 6-6
6.3.2
Packaging and Deploying the hello1 Web Module ........................................................ 6-6
6.3.2.1
To Build and Package the hello1 Web Module Using NetBeans IDE................... 6-6
6.3.2.2
To Build and Package the hello1 Web Module Using Maven ............................... 6-7
6.3.3
Viewing Deployed Web Modules ..................................................................................... 6-7
6.3.3.1
To View Deployed Web Modules Using the Administration Console ................ 6-7
6.3.3.2
To View Deployed Web Modules Using the asadmin Command ........................ 6-7
6.3.3.3
To View Deployed Web Modules Using NetBeans IDE......................................... 6-7
6.3.4
Running the Deployed hello1 Web Module .................................................................... 6-7
6.3.4.1
Dynamic Reloading of Deployed Modules .............................................................. 6-8
6.3.5
Undeploying the hello1 Web Module .............................................................................. 6-8
6.3.5.1
To Undeploy the hello1 Web Module Using NetBeans IDE .................................. 6-8
6.3.5.2
To Undeploy the hello1 Web Module Using Maven............................................... 6-8
6.4
A Web Module That Uses Java Servlet Technology: The hello2 Example ......................... 6-8
6.4.1
Mapping URLs to Web Components................................................................................ 6-9
6.4.2
Examining the hello2 Web Module................................................................................... 6-9
6.4.2.1
To View the hello2 Web Module Using NetBeans IDE .......................................... 6-9
6.4.3
Running the hello2 Example ........................................................................................... 6-11
6.4.3.1
To Run the hello2 Example Using NetBeans IDE................................................. 6-11
6.4.3.2
To Run the hello2 Example Using Maven ............................................................. 6-11
6.5
Configuring Web Applications.............................................................................................. 6-11
6.5.1
Setting Context Parameters ............................................................................................. 6-12
6.5.1.1
To Add a Context Parameter Using NetBeans IDE .............................................. 6-12
6.5.1.2
To Create a web.xml File Using NetBeans IDE..................................................... 6-12
6.5.2
Declaring Welcome Files ................................................................................................. 6-12
6.5.3
Mapping Errors to Error Screens.................................................................................... 6-13
6.5.3.1
To Set Up Error Mapping Using NetBeans IDE.................................................... 6-13
6.5.4
Declaring Resource References....................................................................................... 6-14
6.5.4.1
Declaring a Reference to a Resource....................................................................... 6-14
6.5.4.2
Declaring a Reference to a Web Service ................................................................. 6-15
6.6
Further Information about Web Applications ..................................................................... 6-15
7 JavaServer Faces Technology
7.1
7.2
7.3
7.4
7.4.1
7.4.2
7.4.3
7.4.4
7.4.5
7.5
7.6
7.6.1
7.6.2
vi
What Is a JavaServer Faces Application? ................................................................................ 7-2
JavaServer Faces Technology Benefits ..................................................................................... 7-3
A Simple JavaServer Faces Application................................................................................... 7-4
User Interface Component Model ............................................................................................ 7-5
User Interface Component Classes ................................................................................... 7-5
Component Rendering Model ........................................................................................... 7-7
Conversion Model ............................................................................................................... 7-8
Event and Listener Model .................................................................................................. 7-8
Validation Model ................................................................................................................. 7-9
Navigation Model .................................................................................................................... 7-10
The Lifecycle of a JavaServer Faces Application ................................................................. 7-13
Overview of the JavaServer Faces Lifecycle ................................................................. 7-13
Restore View Phase .......................................................................................................... 7-15
7.6.3
7.6.4
7.6.5
7.6.6
7.6.7
7.7
7.8
Apply Request Values Phase ..........................................................................................
Process Validations Phase ...............................................................................................
Update Model Values Phase ...........................................................................................
Invoke Application Phase................................................................................................
Render Response Phase ...................................................................................................
Partial Processing and Partial Rendering .............................................................................
Further Information about JavaServer Faces Technology .................................................
7-15
7-16
7-16
7-17
7-17
7-17
7-18
8 Introduction to Facelets
8.1
What Is Facelets? ......................................................................................................................... 8-1
8.2
The Lifecycle of a Facelets Application.................................................................................... 8-3
8.3
Developing a Simple Facelets Application: The guessnumber-jsf Example Application 8-3
8.3.1
Creating a Facelets Application ......................................................................................... 8-4
8.3.1.1
Developing a Managed Bean ...................................................................................... 8-4
8.3.1.2
Creating Facelets Views............................................................................................... 8-5
8.3.2
Configuring the Application .............................................................................................. 8-7
8.3.3
Running the guessnumber-jsf Facelets Example............................................................. 8-8
8.3.3.1
To Build, Package, and Deploy the guessnumber-jsf Example Using NetBeans IDE
8-8
8.3.3.2
To Build, Package, and Deploy the guessnumber-jsf Example Using Maven .... 8-8
8.3.3.3
To Run the guessnumber-jsf Example....................................................................... 8-8
8.4
Using Facelets Templates........................................................................................................... 8-8
8.5
Composite Components.......................................................................................................... 8-10
8.6
Web Resources ......................................................................................................................... 8-12
8.7
Relocatable Resources ............................................................................................................. 8-13
8.8
Resource Library Contracts .................................................................................................... 8-14
8.8.1
The hello1-rlc Example Application .............................................................................. 8-15
8.8.1.1
Configuring the hello1-rlc Example........................................................................ 8-15
8.8.1.2
The Facelets Pages for the hello1-rlc Example ...................................................... 8-16
8.8.1.3
To Build, Package, and Deploy the hello1-rlc Example Using NetBeans IDE . 8-16
8.8.1.4
To Build, Package, and Deploy the hello1-rlc Example Using Maven .............. 8-16
8.8.1.5
To Run the hello1-rlc Example ................................................................................ 8-16
8.9
HTML5-Friendly Markup....................................................................................................... 8-17
8.9.1
Using Pass-Through Elements........................................................................................ 8-17
8.9.2
Using Pass-Through Attributes ...................................................................................... 8-18
8.9.3
The reservation Example Application ........................................................................... 8-20
8.9.3.1
The Facelets Pages for the reservation Application.............................................. 8-20
8.9.3.2
The Managed Bean for the reservation Application ............................................ 8-21
8.9.3.3
To Build, Package, and Deploy the reservation Example Using NetBeans IDE .........
8-21
8.9.3.4
To Build, Package, and Deploy the reservation Example Using Maven........... 8-21
8.9.3.5
To Run the reservation Example ............................................................................. 8-22
9 Expression Language
9.1
9.2
Overview of the EL ..................................................................................................................... 9-1
Immediate and Deferred Evaluation Syntax .......................................................................... 9-2
vii
9.2.1
9.2.2
9.3
9.3.1
9.3.1.1
9.3.1.2
9.3.1.3
9.3.1.4
9.3.1.5
9.3.2
9.3.3
9.4
9.5
9.6
9.7
9.8
Immediate Evaluation......................................................................................................... 9-2
Deferred Evaluation ............................................................................................................ 9-2
Value and Method Expressions ................................................................................................ 9-3
Value Expressions................................................................................................................ 9-3
Referencing Objects ...................................................................................................... 9-3
Referencing Object Properties or Collection Elements ........................................... 9-4
Referencing Literals...................................................................................................... 9-5
Parameterized Method Calls ...................................................................................... 9-5
Where Value Expressions Can Be Used .................................................................... 9-6
Method Expressions ............................................................................................................ 9-7
Lambda Expressions ........................................................................................................... 9-7
Operations on Collection Objects ............................................................................................. 9-8
Operators...................................................................................................................................... 9-9
Reserved Words ....................................................................................................................... 9-10
Examples of EL Expressions................................................................................................... 9-11
Further Information about the Expression Language ........................................................ 9-11
10 Using JavaServer Faces Technology in Web Pages
10.1
Setting Up a Page .....................................................................................................................
10.2
Adding Components to a Page Using HTML Tag Library Tags ......................................
10.2.1
Common Component Tag Attributes ............................................................................
10.2.1.1
The id Attribute .........................................................................................................
10.2.1.2
The immediate Attribute ..........................................................................................
10.2.1.3
The rendered Attribute .............................................................................................
10.2.1.4
The style and styleClass Attributes.........................................................................
10.2.1.5
The value and binding Attributes ...........................................................................
10.2.2
Adding HTML Head and Body Tags ............................................................................
10.2.3
Adding a Form Component ............................................................................................
10.2.4
Using Text Components ..................................................................................................
10.2.4.1
Rendering a Field with the h:inputText Tag........................................................
10.2.4.2
Rendering a Password Field with the h:inputSecret Tag ..................................
10.2.4.3
Rendering a Label with the h:outputLabel Tag ..................................................
10.2.4.4
Rendering a Link with the h:outputLink Tag .....................................................
10.2.4.5
Displaying a Formatted Message with the h:outputFormat Tag .....................
10.2.5
Using Command Component Tags for Performing Actions and Navigation.......
10.2.5.1
Rendering a Button with the h:commandButton Tag ........................................
10.2.5.2
Rendering a Link with the h:commandLink Tag................................................
10.2.6
Adding Graphics and Images with the h:graphicImage Tag ...................................
10.2.7
Laying Out Components with the h:panelGrid and h:panelGroup Tags ..............
10.2.8
Displaying Components for Selecting One Value .....................................................
10.2.8.1
Displaying a Check Box Using the h:selectBooleanCheckbox Tag ..................
10.2.8.2
Displaying a Menu Using the h:selectOneMenu Tag ........................................
10.2.9
Displaying Components for Selecting Multiple Values............................................
10.2.10
Using the f:selectItem and f:selectItems Tags .............................................................
10.2.10.1
Using the f:selectItems Tag ....................................................................................
10.2.10.2
Using the f:selectItem Tag ......................................................................................
10.2.11
Displaying the Results from Selection Components .................................................
viii
10-1
10-2
10-4
10-5
10-5
10-6
10-6
10-6
10-7
10-7
10-8
10-10
10-10
10-10
10-11
10-11
10-12
10-12
10-13
10-13
10-14
10-15
10-16
10-16
10-17
10-18
10-18
10-18
10-19
Using Data-Bound Table Components........................................................................ 10-19
Displaying Error Messages with the h:message and h:messages Tags .................. 10-22
Creating Bookmarkable URLs with the h:button and h:link Tags .......................... 10-23
Using View Parameters to Configure Bookmarkable URLs .................................... 10-23
The bookmarks Example Application ......................................................................... 10-24
To Build, Package, and Deploy the bookmarks Example Using NetBeans IDE .........
10-25
10.2.16.2
To Build, Package, and Deploy the bookmarks Example Using Maven......... 10-25
10.2.16.3
To Run the bookmarks Example ........................................................................... 10-25
10.2.17
Resource Relocation Using h:outputScript and h:outputStylesheet Tags.............. 10-25
10.3
Using Core Tags ..................................................................................................................... 10-27
10.2.12
10.2.13
10.2.14
10.2.15
10.2.16
10.2.16.1
11 Using Converters, Listeners, and Validators
11.1
11.1.1
11.1.2
11.1.3
11.2
11.2.1
11.2.2
11.3
11.3.1
11.3.2
11.4
11.4.1
11.4.2
11.4.3
11.4.4
Using the Standard Converters..............................................................................................
Converting a Component's Value ..................................................................................
Using DateTimeConverter ..............................................................................................
Using NumberConverter.................................................................................................
Registering Listeners on Components ..................................................................................
Registering a Value-Change Listener on a Component..............................................
Registering an Action Listener on a Component .........................................................
Using the Standard Validators...............................................................................................
Validating a Component's Value....................................................................................
Using Validator Tags........................................................................................................
Referencing a Managed Bean Method ................................................................................
Referencing a Method That Performs Navigation.....................................................
Referencing a Method That Handles an Action Event..............................................
Referencing a Method That Performs Validation ......................................................
Referencing a Method That Handles a Value-Change Event...................................
11-1
11-2
11-3
11-4
11-6
11-6
11-7
11-8
11-9
11-9
11-10
11-11
11-11
11-11
11-12
12 Developing with JavaServer Faces Technology
12.1
Managed Beans in JavaServer Faces Technology................................................................
12.1.1
Creating a Managed Bean................................................................................................
12.1.2
Using the EL to Reference Managed Beans ..................................................................
12.2
Writing Bean Properties..........................................................................................................
12.2.1
Writing Properties Bound to Component Values ........................................................
12.2.1.1
UIInput and UIOutput Properties ..........................................................................
12.2.1.2
UIData Properties ......................................................................................................
12.2.1.3
UISelectBoolean Properties ......................................................................................
12.2.1.4
UISelectMany Properties ..........................................................................................
12.2.1.5
UISelectOne Properties .............................................................................................
12.2.1.6
UISelectItem Properties ............................................................................................
12.2.1.7
UISelectItems Properties ..........................................................................................
12.2.2
Writing Properties Bound to Component Instances....................................................
12.2.3
Writing Properties Bound to Converters, Listeners, or Validators .........................
12.3
Writing Managed Bean Methods.........................................................................................
12.3.1
Writing a Method to Handle Navigation ....................................................................
12-1
12-1
12-2
12-3
12-4
12-5
12-5
12-6
12-7
12-7
12-8
12-8
12-9
12-10
12-10
12-11
ix
12.3.2
12.3.3
12.3.4
Writing a Method to Handle an Action Event ........................................................... 12-12
Writing a Method to Perform Validation.................................................................... 12-12
Writing a Method to Handle a Value-Change Event ................................................ 12-13
13 Using Ajax with JavaServer Faces Technology
13.1
Overview of Ajax ..................................................................................................................... 13-1
13.2
Using Ajax Functionality with JavaServer Faces Technology........................................... 13-2
13.3
Using Ajax with Facelets......................................................................................................... 13-2
13.3.1
Using the f:ajax Tag .......................................................................................................... 13-3
13.4
Sending an Ajax Request ........................................................................................................ 13-4
13.4.1
Using the event Attribute ................................................................................................ 13-5
13.4.2
Using the execute Attribute............................................................................................. 13-5
13.4.3
Using the immediate Attribute ....................................................................................... 13-5
13.4.4
Using the listener Attribute............................................................................................. 13-6
13.5
Monitoring Events on the Client............................................................................................ 13-6
13.6
Handling Errors ....................................................................................................................... 13-6
13.7
Receiving an Ajax Response................................................................................................... 13-7
13.8
Ajax Request Lifecycle ............................................................................................................ 13-7
13.9
Grouping of Components ....................................................................................................... 13-8
13.10 Loading JavaScript as a Resource .......................................................................................... 13-9
13.10.1
Using JavaScript API in a Facelets Application ........................................................... 13-9
13.10.2
Using the @ResourceDependency Annotation in a Bean Class ............................... 13-10
13.11 The ajaxguessnumber Example Application ..................................................................... 13-10
13.11.1
The ajaxguessnumber Source Files............................................................................... 13-10
13.11.1.1
The ajaxgreeting.xhtml Facelets Page................................................................... 13-10
13.11.1.2
The UserNumberBean Backing Bean.................................................................... 13-11
13.11.1.3
The DukesNumberBean CDI Managed Bean...................................................... 13-12
13.11.2
Running the ajaxguessnumber Example..................................................................... 13-12
13.11.2.1
To Build, Package, and Deploy the ajaxguessnumber Example Using NetBeans
IDE 13-12
13.11.2.2
To Build, Package, and Deploy the ajaxguessnumber Example Using Maven...........
13-12
13.11.2.3
To Run the ajaxguessnumber Example ................................................................ 13-12
13.12 Further Information about Ajax in JavaServer Faces Technology.................................. 13-13
14 Composite Components: Advanced Topics and an Example
14.1
Attributes of a Composite Component................................................................................. 14-1
14.2
Invoking a Managed Bean ...................................................................................................... 14-2
14.3
Validating Composite Component Values .......................................................................... 14-2
14.4
The compositecomponentexample Example Application ................................................. 14-3
14.4.1
The Composite Component File..................................................................................... 14-3
14.4.2
The Using Page ................................................................................................................. 14-4
14.4.3
The Managed Bean ........................................................................................................... 14-4
14.4.4
Running the compositecomponentexample Example................................................. 14-5
14.4.4.1
To Build, Package, and Deploy the compositecomponentexample Example Using
NetBeans IDE 14-5
x
14.4.4.2
14.4.4.3
To Build, Package, and Deploy the compositecomponentexample Example Using
Maven 14-5
To Run the compositecomponentexample Example............................................ 14-5
15 Creating Custom UI Components and Other Custom Objects
15.1
Determining Whether You Need a Custom Component or Renderer.............................
15.1.1
When to Use a Custom Component ..............................................................................
15.1.2
When to Use a Custom Renderer ...................................................................................
15.1.3
Component, Renderer, and Tag Combinations............................................................
15.2
Understanding the Image Map Example .............................................................................
15.2.1
Why Use JavaServer Faces Technology to Implement an Image Map? ...................
15.2.2
Understanding the Rendered HTML.............................................................................
15.2.3
Understanding the Facelets Page ...................................................................................
15.2.4
Configuring Model Data..................................................................................................
15.2.5
Summary of the Image Map Application Classes........................................................
15.3
Steps for Creating a Custom Component.............................................................................
15.4
Creating Custom Component Classes ..................................................................................
15.4.1
Specifying the Component Family...............................................................................
15.4.2
Performing Encoding .....................................................................................................
15.4.3
Performing Decoding.....................................................................................................
15.4.4
Enabling Component Properties to Accept Expressions ..........................................
15.4.5
Saving and Restoring State............................................................................................
15.5
Delegating Rendering to a Renderer...................................................................................
15.5.1
Creating the Renderer Class..........................................................................................
15.5.2
Identifying the Renderer Type......................................................................................
15.6
Implementing an Event Listener .........................................................................................
15.6.1
Implementing Value-Change Listeners.......................................................................
15.6.2
Implementing Action Listeners ....................................................................................
15.7
Handling Events for Custom Components........................................................................
15.8
Defining the Custom Component Tag in a Tag Library Descriptor...............................
15.9
Using a Custom Component ................................................................................................
15.10 Creating and Using a Custom Converter ...........................................................................
15.10.1
Creating a Custom Converter .......................................................................................
15.10.2
Using a Custom Converter............................................................................................
15.11 Creating and Using a Custom Validator ............................................................................
15.11.1
Implementing the Validator Interface .........................................................................
15.11.2
Specifying a Custom Tag ...............................................................................................
15.11.3
Using a Custom Validator .............................................................................................
15.12 Binding Component Values and Instances to Managed Bean Properties .....................
15.12.1
Binding a Component Value to a Property.................................................................
15.12.2
Binding a Component Value to an Implicit Object....................................................
15.12.3
Binding a Component Instance to a Bean Property...................................................
15.13 Binding Converters, Listeners, and Validators to Managed Bean Properties ..............
15-2
15-2
15-4
15-4
15-5
15-5
15-5
15-6
15-7
15-8
15-9
15-9
15-12
15-12
15-14
15-14
15-15
15-16
15-17
15-18
15-18
15-19
15-20
15-20
15-21
15-22
15-23
15-24
15-26
15-27
15-28
15-29
15-30
15-31
15-32
15-33
15-34
15-35
16 Configuring JavaServer Faces Applications
16.1
Using Annotations to Configure Managed Beans .............................................................. 16-1
xi
16.1.1
Using Managed Bean Scopes .......................................................................................... 16-2
16.2
Application Configuration Resource File............................................................................. 16-3
16.2.1
Configuring Eager Application-Scoped Managed Beans ........................................... 16-4
16.2.2
Ordering of Application Configuration Resource Files .............................................. 16-4
16.3
Using Faces Flows.................................................................................................................... 16-5
16.3.1
Packaging Flows in an Application ............................................................................... 16-7
16.3.2
The Simplest Possible Flow: The simple-flow Example Application ....................... 16-7
16.3.2.1
To Build, Package, and Deploy the simple-flow Example Using NetBeans IDE........
16-8
16.3.2.2
To Build, Package, and Deploy the simple-flow Example Using Maven ......... 16-9
16.3.2.3
To Run the simple-flow Example............................................................................ 16-9
16.3.3
The checkout-module Example Application ................................................................ 16-9
16.3.3.1
The Facelets Pages for the checkout-module Example ...................................... 16-10
16.3.3.2
Using a Configuration File to Configure a Flow................................................. 16-11
16.3.3.3
Using a Java Class to Configure a Flow ............................................................... 16-12
16.3.3.4
The Flow-Scoped Managed Beans ........................................................................ 16-13
16.3.3.5
To Build, Package, and Deploy the checkout-module Example Using NetBeans
IDE 16-13
16.3.3.6
To Build, Package, and Deploy the checkout-module Example Using Maven...........
16-14
16.3.3.7
To Run the checkout-module Example ................................................................ 16-14
16.4
Configuring Managed Beans................................................................................................ 16-14
16.4.1
Using the managed-bean Element ............................................................................... 16-15
16.4.2
Initializing Properties Using the managed-property Element................................. 16-17
16.4.2.1
Referencing a Java Enum Type.............................................................................. 16-17
16.4.2.2
Referencing a Context Initialization Parameter .................................................. 16-17
16.4.2.3
Initializing Map Properties .................................................................................... 16-18
16.4.2.4
Initializing Array and List Properties................................................................... 16-19
16.4.2.5
Initializing Managed Bean Properties .................................................................. 16-19
16.4.3
Initializing Maps and Lists ............................................................................................ 16-21
16.5
Registering Application Messages ...................................................................................... 16-21
16.5.1
Using FacesMessage to Create a Message................................................................... 16-22
16.5.2
Referencing Error Messages.......................................................................................... 16-23
16.6
Using Default Validators ...................................................................................................... 16-24
16.7
Registering a Custom Validator........................................................................................... 16-24
16.8
Registering a Custom Converter ......................................................................................... 16-25
16.9
Configuring Navigation Rules ............................................................................................. 16-25
16.10 Registering a Custom Renderer with a Render Kit........................................................... 16-27
16.11 Registering a Custom Component ...................................................................................... 16-29
16.12 Basic Requirements of a JavaServer Faces Application.................................................... 16-29
16.12.1
Configuring an Application with a Web Deployment Descriptor .......................... 16-30
16.12.1.1
Identifying the Servlet for Lifecycle Processing.................................................. 16-31
16.12.1.2
To Specify a Path to an Application Configuration Resource File ................... 16-32
16.12.1.3
To Specify Where State Is Saved ........................................................................... 16-32
16.12.2
Configuring Project Stage.............................................................................................. 16-33
16.12.3
Including the Classes, Pages, and Other Resources .................................................. 16-33
xii
17 Java Servlet Technology
17.1
What Is a Servlet?.....................................................................................................................
17.2
Servlet Lifecycle........................................................................................................................
17.2.1
Handling Servlet Lifecycle Events .................................................................................
17.2.1.1
Defining the Listener Class ......................................................................................
17.2.2
Handling Servlet Errors ...................................................................................................
17.3
Sharing Information ................................................................................................................
17.3.1
Using Scope Objects .........................................................................................................
17.3.2
Controlling Concurrent Access to Shared Resources..................................................
17.4
Creating and Initializing a Servlet.........................................................................................
17.5
Writing Service Methods ........................................................................................................
17.5.1
Getting Information from Requests ...............................................................................
17.5.2
Constructing Responses...................................................................................................
17.6
Filtering Requests and Responses .........................................................................................
17.6.1
Programming Filters ........................................................................................................
17.6.2
Programming Customized Requests and Responses..................................................
17.6.3
Specifying Filter Mappings .............................................................................................
17.6.3.1
To Specify Filter Mappings Using NetBeans IDE.................................................
17.7
Invoking Other Web Resources ...........................................................................................
17.7.1
Including Other Resources in the Response ...............................................................
17.7.2
Transferring Control to Another Web Component ...................................................
17.8
Accessing the Web Context ..................................................................................................
17.9
Maintaining Client State .......................................................................................................
17.9.1
Accessing a Session ........................................................................................................
17.9.2
Associating Objects with a Session ..............................................................................
17.9.3
Session Management......................................................................................................
17.9.3.1
To Set the Timeout Period Using NetBeans IDE.................................................
17.9.4
Session Tracking .............................................................................................................
17.10 Finalizing a Servlet ................................................................................................................
17.10.1
Tracking Service Requests .............................................................................................
17.10.2
Notifying Methods to Shut Down................................................................................
17.10.3
Creating Polite Long-Running Methods .....................................................................
17.11 Uploading Files with Java Servlet Technology..................................................................
17.11.1
The @MultipartConfig Annotation ..............................................................................
17.11.2
The getParts and getPart Methods ...............................................................................
17.12 Asynchronous Processing.....................................................................................................
17.12.1
Asynchronous Processing in Servlets ..........................................................................
17.12.2
Waiting for a Resource...................................................................................................
17.13 Nonblocking I/O ...................................................................................................................
17.13.1
Reading a Large HTTP POST Request Using Nonblocking I/O.............................
17.14 Protocol Upgrade Processing ...............................................................................................
17.15 The mood Example Application..........................................................................................
17.15.1
Components of the mood Example Application........................................................
17.15.2
Running the mood Example .........................................................................................
17.15.2.1
To Run the mood Example Using NetBeans IDE ...............................................
17.15.2.2
To Run the mood Example Using Maven............................................................
17.16 The fileupload Example Application ..................................................................................
17-1
17-2
17-2
17-2
17-3
17-3
17-4
17-4
17-4
17-5
17-5
17-6
17-7
17-7
17-8
17-9
17-9
17-10
17-11
17-11
17-11
17-12
17-12
17-12
17-12
17-13
17-13
17-13
17-14
17-14
17-15
17-15
17-15
17-16
17-16
17-17
17-18
17-19
17-21
17-21
17-23
17-23
17-24
17-24
17-24
17-25
xiii
Architecture of the fileupload Example Application ................................................ 17-25
Running the fileupload Example.................................................................................. 17-27
To Build, Package, and Deploy the fileupload Example Using NetBeans IDE...........
17-27
17.16.2.2
To Build, Package, and Deploy the fileupload Example Using Maven .......... 17-28
17.16.2.3
To Run the fileupload Example............................................................................. 17-28
17.17 The dukeetf Example Application....................................................................................... 17-28
17.17.1
Architecture of the dukeetf Example Application ..................................................... 17-28
17.17.1.1
The Servlet ................................................................................................................ 17-29
17.17.1.2
The Enterprise Bean ................................................................................................ 17-30
17.17.1.3
The HTML Page....................................................................................................... 17-31
17.17.2
Running the dukeetf Example Application ................................................................ 17-31
17.17.2.1
To Run the dukeetf Example Application Using NetBeans IDE ...................... 17-31
17.17.2.2
To Run the dukeetf Example Application Using Maven................................... 17-32
17.18 Further Information about Java Servlet Technology ........................................................ 17-32
17.16.1
17.16.2
17.16.2.1
18 Java API for WebSocket
18.1
Introduction to WebSocket .....................................................................................................
18.2
Creating WebSocket Applications in the Java EE Platform...............................................
18.3
Programmatic Endpoints ........................................................................................................
18.4
Annotated Endpoints ..............................................................................................................
18.5
Sending and Receiving Messages..........................................................................................
18.5.1
Sending Messages.............................................................................................................
18.5.1.1
Sending Messages to All Peers Connected to an Endpoint.................................
18.5.2
Receiving Messages ..........................................................................................................
18.6
Maintaining Client State .........................................................................................................
18.7
Using Encoders and Decoders ...............................................................................................
18.7.1
Implementing Encoders to Convert Java Objects into WebSocket Messages..........
18.7.2
Implementing Decoders to Convert WebSocket Messages into Java Objects .........
18.8
Path Parameters .......................................................................................................................
18.9
Handling Errors .....................................................................................................................
18.10 Specifying an Endpoint Configurator Class ......................................................................
18.11 The dukeetf2 Example Application.....................................................................................
18.11.1
Architecture of the dukeetf2 Sample Application .....................................................
18.11.1.1
The Endpoint............................................................................................................
18.11.1.2
The Enterprise Bean ................................................................................................
18.11.1.3
The HTML Page.......................................................................................................
18.11.2
Running the dukeetf2 Example Application ..............................................................
18.11.2.1
To Run the dukeetf2 Example Application Using NetBeans IDE ....................
18.11.2.2
To Run the dukeetf2 Example Application Using Maven.................................
18.12 The websocketbot Example Application ............................................................................
18.12.1
Architecture of the websocketbot Example Application ..........................................
18.12.1.1
The CDI Bean ...........................................................................................................
18.12.1.2
The WebSocket Endpoint .......................................................................................
18.12.1.3
The Application Messages .....................................................................................
18.12.1.4
The Encoder Classes................................................................................................
18.12.1.5
The Message Decoder .............................................................................................
xiv
18-1
18-2
18-3
18-4
18-5
18-5
18-6
18-6
18-6
18-7
18-7
18-8
18-9
18-10
18-10
18-11
18-11
18-12
18-12
18-13
18-14
18-14
18-14
18-14
18-15
18-15
18-15
18-17
18-17
18-18
18.12.1.6
The HTML Page.......................................................................................................
18.12.2
Running the websocketbot Example Application .....................................................
18.12.2.1
To Run the websocketbot Example Application Using NetBeans IDE ...........
18.12.2.2
To Run the websocketbot Example Application Using Maven........................
18.12.2.3
To Test the websocketbot Example Application.................................................
18.13 Further Information about WebSocket ...............................................................................
18-18
18-19
18-19
18-19
18-19
18-20
19 JSON Processing
19.1
Introduction to JSON...............................................................................................................
19.1.1
JSON Syntax ......................................................................................................................
19.1.2
Uses of JSON .....................................................................................................................
19.1.3
Generating and Parsing JSON Data ...............................................................................
19.2
JSON Processing in the Java EE Platform.............................................................................
19.3
Using the Object Model API...................................................................................................
19.3.1
Creating an Object Model from JSON Data..................................................................
19.3.2
Creating an Object Model from Application Code......................................................
19.3.3
Navigating an Object Model ...........................................................................................
19.3.4
Writing an Object Model to a Stream ............................................................................
19.4
Using the Streaming API ........................................................................................................
19.4.1
Reading JSON Data Using a Parser................................................................................
19.4.2
Writing JSON Data Using a Generator..........................................................................
19.5
JSON in Java EE RESTful Web Services ...............................................................................
19.6
The jsonpmodel Example Application .................................................................................
19.6.1
Components of the jsonpmodel Example Application ...............................................
19.6.2
Running the jsonpmodel Example Application .........................................................
19.6.2.1
To Run the jsonpmodel Example Application Using NetBeans IDE...............
19.6.2.2
To Run the jsonpmodel Example Application Using Maven ...........................
19.7
The jsonpstreaming Example Application .........................................................................
19.7.1
Components of the jsonpstreaming Example Application.......................................
19.7.2
Running the jsonpstreaming Example Application ..................................................
19.7.2.1
To Run the jsonpstreaming Example Application Using NetBeans IDE ........
19.7.2.2
To Run the jsonpstreaming Example Application Using Maven.....................
19.8
Further Information about the Java API for JSON Processing........................................
19-1
19-1
19-2
19-2
19-3
19-4
19-4
19-4
19-5
19-6
19-7
19-7
19-8
19-9
19-9
19-9
19-10
19-10
19-10
19-10
19-11
19-11
19-11
19-11
19-12
20 Internationalizing and Localizing Web Applications
20.1
20.2
20.2.1
20.2.2
20.2.3
20.3
20.4
20.4.1
20.4.2
Java Platform Localization Classes........................................................................................
Providing Localized Messages and Labels ..........................................................................
Establishing the Locale.....................................................................................................
Setting the Resource Bundle............................................................................................
Retrieving Localized Messages.......................................................................................
Date and Number Formatting................................................................................................
Character Sets and Encodings................................................................................................
Character Sets ....................................................................................................................
Character Encoding ..........................................................................................................
20-1
20-2
20-2
20-3
20-3
20-4
20-4
20-4
20-5
Part IV Bean Validation
xv
21 Introduction to Bean Validation
21.1
21.2
21.3
21.3.1
21.3.2
21.3.3
21.4
Using Bean Validation Constraints .......................................................................................
Validating Null and Empty Strings.......................................................................................
Validating Constructors and Methods .................................................................................
Cross-Parameter Constraints ..........................................................................................
Identifying Parameter Constraint Violations ...............................................................
Adding Constraints to Method Return Values ............................................................
Further Information about Bean Validation ........................................................................
21-1
21-4
21-5
21-5
21-6
21-6
21-6
22 Bean Validation: Advanced Topics
22.1
Creating Custom Constraints.................................................................................................
22.1.1
Using the Built-In Constraints to Make a New Constraint.........................................
22.1.2
Removing Ambiguity in Constraint Targets ................................................................
22.2
Customizing Validator Messages ..........................................................................................
22.2.1
The ValidationMessages Resource Bundle ...................................................................
22.2.1.1
Localizing Validation Messages ..............................................................................
22.3
Grouping Constraints.............................................................................................................
22.3.1
Customizing Group Validation Order ..........................................................................
22.4
Using Method Constraints in Type Hierarchies..................................................................
22.4.1
Rules for Using Method Constraints in Type Hierarchies .........................................
22-1
22-1
22-2
22-2
22-2
22-3
22-3
22-3
22-4
22-5
Part V Contexts and Dependency Injection for Java EE
23 Introduction to Contexts and Dependency Injection for Java EE
Getting Started.......................................................................................................................... 23-2
Overview of CDI ...................................................................................................................... 23-3
About Beans.............................................................................................................................. 23-4
About CDI Managed Beans.................................................................................................... 23-4
Beans as Injectable Objects...................................................................................................... 23-5
Using Qualifiers ....................................................................................................................... 23-5
Injecting Beans.......................................................................................................................... 23-6
Using Scopes............................................................................................................................. 23-7
Giving Beans EL Names.......................................................................................................... 23-8
Adding Setter and Getter Methods ....................................................................................... 23-9
Using a Managed Bean in a Facelets Page............................................................................ 23-9
Injecting Objects by Using Producer Methods .................................................................. 23-10
Configuring a CDI Application ........................................................................................... 23-10
Using the @PostConstruct and @PreDestroy Annotations with CDI Managed Bean Classes
23-11
23.14.1
To Initialize a Managed Bean Using the @PostConstruct Annotation ................... 23-11
23.14.2
To Prepare for the Destruction of a Managed Bean Using the @PreDestroy Annotation
23-11
23.15 Further Information about CDI ........................................................................................... 23-12
23.1
23.2
23.3
23.4
23.5
23.6
23.7
23.8
23.9
23.10
23.11
23.12
23.13
23.14
24 Running the Basic Contexts and Dependency Injection Examples
24.1
xvi
The simplegreeting CDI Example ......................................................................................... 24-1
The simplegreeting Source Files ..................................................................................... 24-1
The Facelets Template and Page..................................................................................... 24-2
Running the simplegreeting Example ........................................................................... 24-3
To Build, Package, and Run the simplegreeting Example Using NetBeans IDE ........
24-3
24.1.3.2
To Build, Package, and Deploy the simplegreeting Example Using Maven .... 24-4
24.1.3.3
To Run the simplegreeting Example ...................................................................... 24-4
24.2
The guessnumber-cdi CDI Example ..................................................................................... 24-4
24.2.1
The guessnumber-cdi Source Files................................................................................. 24-4
24.2.1.1
The @MaxNumber and @Random Qualifier Interfaces....................................... 24-5
24.2.1.2
The Generator Managed Bean ................................................................................. 24-5
24.2.1.3
The UserNumberBean Managed Bean ................................................................... 24-6
24.2.2
The Facelets Page .............................................................................................................. 24-8
24.2.3
Running the guessnumber-cdi Example ....................................................................... 24-9
24.2.3.1
To Build, Package, and Deploy the guessnumber-cdi Example Using NetBeans
IDE 24-9
24.2.3.2
To Build, Package, and Deploy the guessnumber-cdi Example Using Maven ...........
24-10
24.2.3.3
To Run the guessnumber Example ....................................................................... 24-10
24.1.1
24.1.2
24.1.3
24.1.3.1
25 Contexts and Dependency Injection for Java EE: Advanced Topics
25.1
Packaging CDI Applications .................................................................................................. 25-1
25.2
Using Alternatives in CDI Applications............................................................................... 25-2
25.2.1
Using Specialization ......................................................................................................... 25-3
25.3
Using Producer Methods, Producer Fields, and Disposer Methods in CDI Applications ......
25-4
25.3.1
Using Producer Methods................................................................................................. 25-4
25.3.2
Using Producer Fields to Generate Resources ............................................................. 25-5
25.3.3
Using a Disposer Method ................................................................................................ 25-5
25.4
Using Predefined Beans in CDI Applications...................................................................... 25-5
25.5
Using Events in CDI Applications......................................................................................... 25-7
25.5.1
Defining Events................................................................................................................. 25-7
25.5.2
Using Observer Methods to Handle Events ................................................................. 25-7
25.5.3
Firing Events...................................................................................................................... 25-8
25.6
Using Interceptors in CDI Applications ............................................................................... 25-9
25.7
Using Decorators in CDI Applications ............................................................................... 25-10
25.8
Using Stereotypes in CDI Applications .............................................................................. 25-12
26 Running the Advanced Contexts and Dependency Injection Examples
26.1
The encoder Example: Using Alternatives...........................................................................
26.1.1
The Coder Interface and Implementations ...................................................................
26.1.2
The encoder Facelets Page and Managed Bean............................................................
26.1.3
Running the encoder Example........................................................................................
26.1.3.1
To Build, Package, and Deploy the encoder Example Using NetBeans IDE ....
26.1.3.2
To Run the encoder Example Using NetBeans IDE .............................................
26.1.3.3
To Build, Package, and Deploy the encoder Example Using Maven ................
26.1.3.4
To Run the encoder Example Using Maven ..........................................................
26-1
26-1
26-2
26-3
26-4
26-4
26-4
26-5
xvii
The producermethods Example: Using a Producer Method to Choose a Bean
Implementation 26-5
26.2.1
Components of the producermethods Example .......................................................... 26-6
26.2.2
Running the producermethods Example ...................................................................... 26-7
26.2.2.1
To Build, Package, and Deploy the producermethods Example Using NetBeans
IDE 26-7
26.2.2.2
To Build, Package, and Deploy the producermethods Example Using Maven 26-7
26.2.2.3
To Run the producermethods Example ................................................................. 26-7
26.3
The producerfields Example: Using Producer Fields to Generate Resources ................ 26-8
26.3.1
The Producer Field for the producerfields Example ................................................... 26-8
26.3.2
The producerfields Entity and Session Bean ................................................................ 26-9
26.3.3
The producerfields Facelets Pages and Managed Bean ............................................ 26-10
26.3.4
Running the producerfields Example.......................................................................... 26-12
26.3.4.1
To Build, Package, and Deploy the producerfields Example Using NetBeans IDE ...
26-12
26.3.4.2
To Build, Package, and Deploy the producerfields Example Using Maven... 26-13
26.3.4.3
To Run the producerfields Example ..................................................................... 26-13
26.4
The billpayment Example: Using Events and Interceptors ............................................. 26-13
26.4.1
The PaymentEvent Event Class .................................................................................... 26-13
26.4.2
The PaymentHandler Event Listener .......................................................................... 26-14
26.4.3
The billpayment Facelets Pages and Managed Bean................................................. 26-15
26.4.4
The LoggedInterceptor Interceptor Class ................................................................... 26-17
26.4.5
Running the billpayment Example .............................................................................. 26-18
26.4.5.1
To Build, Package, and Deploy the billpayment Example Using NetBeans IDE........
26-18
26.4.5.2
To Build, Package, and Deploy the billpayment Example Using Maven ....... 26-18
26.4.5.3
To Run the billpayment Example.......................................................................... 26-18
26.5
The decorators Example: Decorating a Bean ..................................................................... 26-19
26.5.1
Components of the decorators Example ..................................................................... 26-19
26.5.2
Running the decorators Example ................................................................................. 26-20
26.5.2.1
To Build, Package, and Deploy the decorators Example Using NetBeans IDE ..........
26-20
26.5.2.2
To Build, Package, and Deploy the decorators Example Using Maven .......... 26-20
26.5.2.3
To Run the decorators Example ............................................................................ 26-21
26.2
Part VI
Web Services
27 Introduction to Web Services
27.1
What Are Web Services? .........................................................................................................
27.2
Types of Web Services.............................................................................................................
27.2.1
"Big" Web Services ............................................................................................................
27.2.2
RESTful Web Services ......................................................................................................
27.3
Deciding Which Type of Web Service to Use ......................................................................
27-1
27-1
27-1
27-2
27-3
28 Building Web Services with JAX-WS
28.1
Creating a Simple Web Service and Clients with JAX-WS ................................................ 28-2
28.1.1
Requirements of a JAX-WS Endpoint ............................................................................ 28-2
xviii
28.1.2
Coding the Service Endpoint Implementation Class ..................................................
28.1.3
Building, Packaging, and Deploying the Service.........................................................
28.1.3.1
To Build, Package, and Deploy the Service Using NetBeans IDE......................
28.1.3.2
To Build, Package, and Deploy the Service Using Maven ..................................
28.1.4
Testing the Methods of a Web Service Endpoint .........................................................
28.1.4.1
To Test the Service without a Client .......................................................................
28.1.5
A Simple JAX-WS Application Client............................................................................
28.1.5.1
Coding the Application Client.................................................................................
28.1.5.2
Running the Application Client ..............................................................................
28.1.6
A Simple JAX-WS Web Client ........................................................................................
28.1.6.1
Coding the Servlet .....................................................................................................
28.1.6.2
Running the Web Client ...........................................................................................
28.2
Types Supported by JAX-WS .................................................................................................
28.2.1
Schema-to-Java Mapping.................................................................................................
28.2.2
Java-to-Schema Mapping.................................................................................................
28.3
Web Services Interoperability and JAX-WS.......................................................................
28.4
Further Information about JAX-WS ....................................................................................
28-3
28-3
28-4
28-4
28-4
28-4
28-5
28-5
28-6
28-6
28-6
28-8
28-9
28-9
28-9
28-10
28-10
29 Building RESTful Web Services with JAX-RS
29.1
What Are RESTful Web Services? .........................................................................................
29.2
Creating a RESTful Root Resource Class..............................................................................
29.2.1
Developing RESTful Web Services with JAX-RS .........................................................
29.2.2
Overview of a JAX-RS Application ................................................................................
29.2.3
The @Path Annotation and URI Path Templates .........................................................
29.2.4
Responding to HTTP Methods and Requests ..............................................................
29.2.4.1
The Request Method Designator Annotations......................................................
29.2.4.2
Using Entity Providers to Map HTTP Response and Request Entity Bodies...
29.2.5
Using @Consumes and @Produces to Customize Requests and Responses ...........
29.2.5.1
The @Produces Annotation......................................................................................
29.2.5.2
The @Consumes Annotation..................................................................................
29.2.6
Extracting Request Parameters .....................................................................................
29.2.7
Configuring JAX-RS Applications................................................................................
29.2.7.1
Configuring a JAX-RS Application Using a Subclass of Application ..............
29.2.7.2
Configuring the Base URI in web.xml..................................................................
29.3
Example Applications for JAX-RS .......................................................................................
29.3.1
Creating a Simple RESTful Web Service .....................................................................
29.3.1.1
To Create a RESTful Web Service Using NetBeans IDE ....................................
29.3.2
The rsvp Example Application .....................................................................................
29.3.2.1
Components of the rsvp Example Application...................................................
29.3.2.2
Running the rsvp Example Application...............................................................
29.3.3
Real-World Examples.....................................................................................................
29.4
Further Information about JAX-RS......................................................................................
29-1
29-2
29-2
29-4
29-5
29-6
29-7
29-8
29-9
29-9
29-10
29-11
29-14
29-14
29-15
29-15
29-15
29-15
29-16
29-16
29-17
29-18
29-19
30 Accessing REST Resources with the JAX-RS Client API
30.1
Overview of the Client API .................................................................................................... 30-1
30.1.1
Creating a Basic Client Request Using the Client API ................................................ 30-1
xix
30.1.1.1
Obtaining the Client Instance ..................................................................................
30.1.1.2
Setting the Client Target ...........................................................................................
30.1.1.3
Setting Path Parameters in Targets .........................................................................
30.1.1.4
Invoking the Request ................................................................................................
30.2
Using the Client API in the JAX-RS Example Applications ..............................................
30.2.1
The Client API in the rsvp Example Application ........................................................
30.2.2
The Client API in the customer Example Application ................................................
30.3
Advanced Features of the Client API ...................................................................................
30.3.1
Configuring the Client Request ......................................................................................
30.3.1.1
Setting Message Headers in the Client Request....................................................
30.3.1.2
Setting Cookies in the Client Request.....................................................................
30.3.1.3
Adding Filters to the Client......................................................................................
30.3.2
Asynchronous Invocations in the Client API ...............................................................
30.3.2.1
Using Custom Callbacks in Asynchronous Invocations......................................
30-2
30-2
30-2
30-3
30-4
30-4
30-5
30-6
30-6
30-6
30-7
30-7
30-8
30-9
31 JAX-RS: Advanced Topics and an Example
31.1
Annotations for Field and Bean Properties of Resource Classes ......................................
31.1.1
Extracting Path Parameters .............................................................................................
31.1.2
Extracting Query Parameters..........................................................................................
31.1.3
Extracting Form Data .......................................................................................................
31.1.4
Extracting the Java Type of a Request or Response.....................................................
31.2
Validating Resource Data with Bean Validation.................................................................
31.2.1
Using Constraint Annotations on Resource Methods.................................................
31.2.2
Validating Entity Data .....................................................................................................
31.2.3
Validation Exception Handling and Response Codes ................................................
31.3
Subresources and Runtime Resource Resolution................................................................
31.3.1
Subresource Methods.......................................................................................................
31.3.2
Subresource Locators .......................................................................................................
31.4
Integrating JAX-RS with EJB Technology and CDI ............................................................
31.5
Conditional HTTP Requests...................................................................................................
31.6
Runtime Content Negotiation................................................................................................
31.7
Using JAX-RS with JAXB ......................................................................................................
31.7.1
Using Java Objects to Model Your Data ......................................................................
31.7.2
Starting from an Existing XML Schema Definition ...................................................
31.7.3
Using JSON with JAX-RS and JAXB ............................................................................
31.8
The customer Example Application....................................................................................
31.8.1
Overview of the customer Example Application.......................................................
31.8.2
The Customer and Address Entity Classes.................................................................
31.8.3
The CustomerService Class ...........................................................................................
31.8.4
Using the JAX-RS Client in the CustomerBean Classes ............................................
31.8.5
Running the customer Example ...................................................................................
31.8.5.1
To Build, Package, and Deploy the customer Example Using NetBeans IDE
31.8.5.2
To Build, Package, and Deploy the customer Example Using Maven ............
Part VII
xx
Enterprise Beans
31-1
31-2
31-2
31-3
31-3
31-4
31-4
31-5
31-6
31-6
31-7
31-7
31-8
31-9
31-9
31-11
31-12
31-14
31-15
31-16
31-16
31-17
31-19
31-20
31-22
31-22
31-22
32 Enterprise Beans
32.1
What Is an Enterprise Bean?...................................................................................................
32.1.1
Benefits of Enterprise Beans ............................................................................................
32.1.2
When to Use Enterprise Beans........................................................................................
32.1.3
Types of Enterprise Beans ...............................................................................................
32.2
What Is a Session Bean? ..........................................................................................................
32.2.1
Types of Session Beans.....................................................................................................
32.2.1.1
Stateful Session Beans ...............................................................................................
32.2.1.2
Stateless Session Beans .............................................................................................
32.2.1.3
Singleton Session Beans............................................................................................
32.2.2
When to Use Session Beans .............................................................................................
32.3
What Is a Message-Driven Bean? ..........................................................................................
32.3.1
What Makes Message-Driven Beans Different from Session Beans?........................
32.3.2
When to Use Message-Driven Beans .............................................................................
32.4
Accessing Enterprise Beans ....................................................................................................
32.4.1
Using Enterprise Beans in Clients ..................................................................................
32.4.1.1
Portable JNDI Syntax ................................................................................................
32.4.2
Deciding on Remote or Local Access.............................................................................
32.4.3
Local Clients ......................................................................................................................
32.4.3.1
Accessing Local Enterprise Beans Using the No-Interface View .......................
32.4.3.2
Accessing Local Enterprise Beans That Implement Business Interfaces ...........
32.4.4
Remote Clients ..................................................................................................................
32.4.5
Web Service Clients ........................................................................................................
32.4.6
Method Parameters and Access....................................................................................
32.4.6.1
Isolation.....................................................................................................................
32.4.6.2
Granularity of Accessed Data ................................................................................
32.5
The Contents of an Enterprise Bean ....................................................................................
32.6
Naming Conventions for Enterprise Beans........................................................................
32.7
The Lifecycles of Enterprise Beans ......................................................................................
32.7.1
The Lifecycle of a Stateful Session Bean ......................................................................
32.7.2
The Lifecycle of a Stateless Session Bean ....................................................................
32.7.3
The Lifecycle of a Singleton Session Bean...................................................................
32.7.4
The Lifecycle of a Message-Driven Bean.....................................................................
32.8
Further Information about Enterprise Beans .....................................................................
32-1
32-1
32-2
32-2
32-2
32-2
32-2
32-3
32-3
32-3
32-4
32-4
32-5
32-5
32-6
32-6
32-7
32-7
32-8
32-8
32-9
32-10
32-10
32-10
32-10
32-10
32-11
32-11
32-11
32-12
32-13
32-13
32-13
33 Getting Started with Enterprise Beans
33.1
Creating the Enterprise Bean..................................................................................................
33.1.1
Coding the Enterprise Bean Class ..................................................................................
33.1.2
Creating the converter Web Client.................................................................................
33.1.3
Running the converter Example.....................................................................................
33.1.3.1
To Run the converter Example Using NetBeans IDE...........................................
33.1.3.2
To Run the converter Example Using Maven .......................................................
33.2
Modifying the Java EE Application.......................................................................................
33.2.1
To Modify a Class File......................................................................................................
33-1
33-1
33-2
33-3
33-3
33-3
33-4
33-4
xxi
34 Running the Enterprise Bean Examples
34.1
The cart Example...................................................................................................................... 34-1
34.1.1
The Business Interface...................................................................................................... 34-2
34.1.2
Session Bean Class ............................................................................................................ 34-2
34.1.2.1
Lifecycle Callback Methods ..................................................................................... 34-4
34.1.2.2
Business Methods ...................................................................................................... 34-4
34.1.3
The @Remove Method ..................................................................................................... 34-5
34.1.4
Helper Classes ................................................................................................................... 34-5
34.1.5
Running the cart Example ............................................................................................... 34-6
34.1.5.1
To Run the cart Example Using NetBeans IDE ..................................................... 34-6
34.1.5.2
To Run the cart Example Using Maven ................................................................. 34-6
34.2
A Singleton Session Bean Example: counter........................................................................ 34-7
34.2.1
Creating a Singleton Session Bean ................................................................................. 34-7
34.2.1.1
Initializing Singleton Session Beans........................................................................ 34-7
34.2.1.2
Managing Concurrent Access in a Singleton Session Bean................................. 34-8
34.2.1.3
Handling Errors in a Singleton Session Bean ...................................................... 34-11
34.2.2
The Architecture of the counter Example ................................................................... 34-11
34.2.3
Running the counter Example ...................................................................................... 34-13
34.2.3.1
To Run the counter Example Using NetBeans IDE ............................................ 34-13
34.2.3.2
To Run the counter Example Using Maven......................................................... 34-13
34.3
A Web Service Example: helloservice ................................................................................. 34-13
34.3.1
The Web Service Endpoint Implementation Class .................................................... 34-14
34.3.2
Stateless Session Bean Implementation Class............................................................. 34-14
34.3.3
Running the helloservice Example............................................................................... 34-15
34.3.3.1
To Build, Package, and Deploy the helloservice Example Using NetBeans IDE ........
34-15
34.3.3.2
To Build, Package, and Deploy the helloservice Example Using Maven........ 34-15
34.3.3.3
To Test the Service without a Client ..................................................................... 34-15
34.4
Using the Timer Service ........................................................................................................ 34-16
34.4.1
Creating Calendar-Based Timer Expressions ............................................................. 34-16
34.4.1.1
Specifying Multiple Values in Calendar Expressions ........................................ 34-17
34.4.2
Programmatic Timers..................................................................................................... 34-18
34.4.2.1
The @Timeout Method ........................................................................................... 34-18
34.4.2.2
Creating Programmatic Timers ............................................................................. 34-19
34.4.3
Automatic Timers ........................................................................................................... 34-20
34.4.4
Canceling and Saving Timers ....................................................................................... 34-20
34.4.5
Getting Timer Information ............................................................................................ 34-21
34.4.6
Transactions and Timers................................................................................................ 34-21
34.4.7
The timersession Example............................................................................................. 34-21
34.4.8
Running the timersession Example.............................................................................. 34-23
34.4.8.1
To Run the timersession Example Using NetBeans IDE ................................... 34-24
34.4.8.2
To Build, Package, and Deploy the timersession Example Using Maven ...... 34-24
34.4.8.3
To Run the Web Client............................................................................................ 34-24
34.5
Handling Exceptions ............................................................................................................. 34-24
35 Using the Embedded Enterprise Bean Container
35.1
xxii
Overview of the Embedded Enterprise Bean Container.................................................... 35-1
35.2
Developing Embeddable Enterprise Bean Applications....................................................
35.2.1
Running Embedded Applications..................................................................................
35.2.2
Creating the Enterprise Bean Container........................................................................
35.2.2.1
Explicitly Specifying Enterprise Bean Modules to Be Initialized .......................
35.2.3
Looking Up Session Bean References ............................................................................
35.2.4
Shutting Down the Enterprise Bean Container ............................................................
35.3
The standalone Example Application...................................................................................
35.3.1
To Run the standalone Example Application Using NetBeans IDE .........................
35.3.2
To Run the standalone Example Application Using Maven ......................................
35-1
35-2
35-2
35-3
35-3
35-3
35-4
35-5
35-5
36 Using Asynchronous Method Invocation in Session Beans
36.1
Asynchronous Method Invocation........................................................................................
36.1.1
Creating an Asynchronous Business Method ..............................................................
36.1.2
Calling Asynchronous Methods from Enterprise Bean Clients.................................
36.1.2.1
Retrieving the Final Result from an Asynchronous Method Invocation ..........
36.1.2.2
Cancelling an Asynchronous Method Invocation ................................................
36.1.2.3
Checking the Status of an Asynchronous Method Invocation ...........................
36.2
The async Example Application ............................................................................................
36.2.1
Architecture of the async-war Module..........................................................................
36.2.2
Running the async Example............................................................................................
36.2.2.1
To Run the async Example Application Using NetBeans IDE............................
36.2.2.2
To Run the async Example Application Using Maven ........................................
36-1
36-1
36-2
36-2
36-3
36-3
36-3
36-3
36-4
36-5
36-5
Part VIII Persistence
37 Introduction to the Java Persistence API
37.1
Entities .......................................................................................................................................
37.1.1
Requirements for Entity Classes.....................................................................................
37.1.2
Persistent Fields and Properties in Entity Classes .......................................................
37.1.2.1
Persistent Fields .........................................................................................................
37.1.2.2
Persistent Properties..................................................................................................
37.1.2.3
Using Collections in Entity Fields and Properties ................................................
37.1.2.4
Validating Persistent Fields and Properties...........................................................
37.1.3
Primary Keys in Entities ..................................................................................................
37.1.4
Multiplicity in Entity Relationships ...............................................................................
37.1.5
Direction in Entity Relationships ...................................................................................
37.1.5.1
Bidirectional Relationships ......................................................................................
37.1.5.2
Unidirectional Relationships ...................................................................................
37.1.5.3
Queries and Relationship Direction........................................................................
37.1.5.4
Cascade Operations and Relationships..................................................................
37.1.5.5
Orphan Removal in Relationships ..........................................................................
37.1.6
Embeddable Classes in Entities ....................................................................................
37.2
Entity Inheritance...................................................................................................................
37.2.1
Abstract Entities ..............................................................................................................
37.2.2
Mapped Superclasses .....................................................................................................
37.2.3
Non-Entity Superclasses ................................................................................................
37-1
37-1
37-2
37-2
37-3
37-3
37-4
37-6
37-7
37-8
37-8
37-8
37-9
37-9
37-9
37-10
37-11
37-11
37-11
37-12
xxiii
37.2.4
Entity Inheritance Mapping Strategies ........................................................................
37.2.4.1
The Single Table per Class Hierarchy Strategy ...................................................
37.2.4.2
The Table per Concrete Class Strategy.................................................................
37.2.4.3
The Joined Subclass Strategy .................................................................................
37.3
Managing Entities ..................................................................................................................
37.3.1
The EntityManager Interface ........................................................................................
37.3.1.1
Container-Managed Entity Managers ..................................................................
37.3.1.2
Application-Managed Entity Managers...............................................................
37.3.1.3
Finding Entities Using the EntityManager ..........................................................
37.3.1.4
Managing an Entity Instance's Lifecycle ..............................................................
37.3.1.5
Persisting Entity Instances .....................................................................................
37.3.1.6
Removing Entity Instances.....................................................................................
37.3.1.7
Synchronizing Entity Data to the Database .........................................................
37.3.2
Persistence Units .............................................................................................................
37.4
Querying Entities ...................................................................................................................
37.5
Database Schema Creation ...................................................................................................
37.5.1
Configuring an Application to Create or Drop Database Tables ............................
37.5.2
Loading Data Using SQL Scripts..................................................................................
37.6
Further Information about Persistence ...............................................................................
37-12
37-12
37-13
37-14
37-14
37-14
37-14
37-15
37-16
37-16
37-16
37-17
37-17
37-17
37-18
37-19
37-20
37-21
37-21
38 Running the Persistence Examples
38.1
The order Application ............................................................................................................. 38-1
38.1.1
Entity Relationships in the order Application.............................................................. 38-2
38.1.1.1
Self-Referential Relationships .................................................................................. 38-2
38.1.1.2
One-to-One Relationships ........................................................................................ 38-3
38.1.1.3
One-to-Many Relationship Mapped to Overlapping Primary and Foreign Keys ......
38-3
38.1.1.4
Unidirectional Relationships ................................................................................... 38-4
38.1.2
Primary Keys in the order Application ......................................................................... 38-4
38.1.2.1
Generated Primary Keys .......................................................................................... 38-4
38.1.2.2
Compound Primary Keys......................................................................................... 38-5
38.1.3
Entity Mapped to More Than One Database Table ..................................................... 38-7
38.1.4
Cascade Operations in the order Application .............................................................. 38-8
38.1.5
BLOB and CLOB Database Types in the order Application ...................................... 38-8
38.1.6
Temporal Types in the order Application..................................................................... 38-9
38.1.7
Managing the order Application's Entities ................................................................... 38-9
38.1.7.1
Creating Entities ........................................................................................................ 38-9
38.1.7.2
Finding Entities ........................................................................................................ 38-10
38.1.7.3
Setting Entity Relationships ................................................................................... 38-10
38.1.7.4
Using Queries........................................................................................................... 38-10
38.1.7.5
Removing Entities ................................................................................................... 38-11
38.1.8
Running the order Example .......................................................................................... 38-11
38.1.8.1
To Run the order Example Using NetBeans IDE ................................................ 38-11
38.1.8.2
To Run the order Example Using Maven ............................................................ 38-11
38.2
The roster Application........................................................................................................... 38-12
38.2.1
Relationships in the roster Application ....................................................................... 38-13
38.2.1.1
The Many-To-Many Relationship in roster ......................................................... 38-13
xxiv
38.2.2
Entity Inheritance in the roster Application ...............................................................
38.2.3
Criteria Queries in the roster Application...................................................................
38.2.3.1
Metamodel Classes in the roster Application......................................................
38.2.3.2
Obtaining a CriteriaBuilder Instance in RequestBean .......................................
38.2.3.3
Creating Criteria Queries in RequestBean's Business Methods .......................
38.2.4
Automatic Table Generation in the roster Application.............................................
38.2.5
Running the roster Example .........................................................................................
38.2.5.1
To Run the roster Example Using NetBeans IDE ...............................................
38.2.5.2
To Run the roster Example Using Maven............................................................
38.3
The address-book Application.............................................................................................
38.3.1
Bean Validation Constraints in address-book ............................................................
38.3.2
Specifying Error Messages for Constraints in address-book ...................................
38.3.3
Validating Contact Input from a JavaServer Faces Application..............................
38.3.4
Running the address-book Example............................................................................
38.3.4.1
To Run the address-book Example Using NetBeans IDE..................................
38.3.4.2
To Run the address-book Example Using Maven ..............................................
38-13
38-15
38-15
38-15
38-15
38-16
38-17
38-17
38-17
38-18
38-18
38-19
38-20
38-20
38-20
38-21
39 The Java Persistence Query Language
39.1
Query Language Terminology...............................................................................................
39.2
Creating Queries Using the Java Persistence Query Language ........................................
39.2.1
Named Parameters in Queries........................................................................................
39.2.2
Positional Parameters in Queries ...................................................................................
39.3
Simplified Query Language Syntax ......................................................................................
39.3.1
Select Statements...............................................................................................................
39.3.2
Update and Delete Statements........................................................................................
39.4
Example Queries ......................................................................................................................
39.4.1
Simple Queries ..................................................................................................................
39.4.1.1
A Basic Select Query .................................................................................................
39.4.1.2
Eliminating Duplicate Values ..................................................................................
39.4.1.3
Using Named Parameters ........................................................................................
39.4.2
Queries That Navigate to Related Entities ....................................................................
39.4.2.1
A Simple Query with Relationships .......................................................................
39.4.2.2
Navigating to Single-Valued Relationship Fields.................................................
39.4.2.3
Traversing Relationships with an Input Parameter .............................................
39.4.2.4
Traversing Multiple Relationships..........................................................................
39.4.2.5
Navigating According to Related Fields ................................................................
39.4.3
Queries with Other Conditional Expressions...............................................................
39.4.3.1
The LIKE Expression.................................................................................................
39.4.3.2
The IS NULL Expression ..........................................................................................
39.4.3.3
The IS EMPTY Expression........................................................................................
39.4.3.4
The BETWEEN Expression ......................................................................................
39.4.3.5
Comparison Operators .............................................................................................
39.4.4
Bulk Updates and Deletes ...............................................................................................
39.4.4.1
Update Queries ..........................................................................................................
39.4.4.2
Delete Queries ............................................................................................................
39.5
Full Query Language Syntax..................................................................................................
39.5.1
BNF Symbols .....................................................................................................................
39-1
39-2
39-2
39-3
39-3
39-3
39-4
39-4
39-4
39-4
39-4
39-5
39-5
39-5
39-5
39-5
39-6
39-6
39-6
39-6
39-7
39-7
39-7
39-7
39-8
39-8
39-8
39-8
39-8
xxv
39.5.2
39.5.3
39.5.3.1
39.5.3.2
39.5.3.3
39.5.3.4
39.5.3.5
39.5.4
39.5.4.1
39.5.4.2
39.5.4.3
39.5.5
39.5.5.1
39.5.5.2
39.5.5.3
39.5.5.4
39.5.5.5
39.5.5.6
39.5.5.7
39.5.5.8
39.5.5.9
39.5.5.10
39.5.5.11
39.5.5.12
39.5.5.13
39.5.5.14
39.5.5.15
39.5.6
39.5.6.1
39.5.6.2
39.5.6.3
39.5.7
39.5.8
BNF Grammar of the Java Persistence Query Language............................................
FROM Clause ..................................................................................................................
Identifiers..................................................................................................................
Identification Variables...........................................................................................
Range Variable Declarations..................................................................................
Collection Member Declarations ...........................................................................
Joins ...........................................................................................................................
Path Expressions .............................................................................................................
Examples of Path Expressions ...............................................................................
Expression Types .....................................................................................................
Navigation ................................................................................................................
WHERE Clause ...............................................................................................................
Literals.......................................................................................................................
Input Parameters .....................................................................................................
Conditional Expressions.........................................................................................
Operators and Their Precedence ...........................................................................
BETWEEN Expressions ..........................................................................................
IN Expressions .........................................................................................................
LIKE Expressions.....................................................................................................
NULL Comparison Expressions............................................................................
Empty Collection Comparison Expressions ........................................................
Collection Member Expressions ............................................................................
Subqueries ................................................................................................................
Functional Expressions ...........................................................................................
Case Expressions .....................................................................................................
NULL Values............................................................................................................
Equality Semantics ..................................................................................................
SELECT Clause................................................................................................................
Return Types ............................................................................................................
The DISTINCT Keyword........................................................................................
Constructor Expressions.........................................................................................
ORDER BY Clause ..........................................................................................................
GROUP BY and HAVING Clauses ..............................................................................
39-9
39-12
39-12
39-14
39-15
39-15
39-15
39-16
39-16
39-17
39-17
39-17
39-17
39-18
39-18
39-18
39-19
39-19
39-20
39-20
39-20
39-21
39-21
39-22
39-23
39-24
39-24
39-25
39-25
39-26
39-26
39-27
39-27
40 Using the Criteria API to Create Queries
40.1
Overview of the Criteria and Metamodel APIs...................................................................
40.2
Using the Metamodel API to Model Entity Classes............................................................
40.2.1
Using Metamodel Classes ...............................................................................................
40.3
Using the Criteria API and Metamodel API to Create Basic Typesafe Queries .............
40.3.1
Creating a Criteria Query ................................................................................................
40.3.2
Query Roots .......................................................................................................................
40.3.3
Querying Relationships Using Joins ..............................................................................
40.3.4
Path Navigation in Criteria Queries ..............................................................................
40.3.5
Restricting Criteria Query Results .................................................................................
40.3.5.1
The Expression Interface Methods..........................................................................
40.3.5.2
Expression Methods in the CriteriaBuilder Interface...........................................
40.3.6
Managing Criteria Query Results...................................................................................
xxvi
40-1
40-2
40-3
40-4
40-4
40-5
40-5
40-6
40-6
40-6
40-7
40-8
40.3.6.1
40.3.6.2
40.3.7
40.3.7.1
40.3.7.2
Ordering Results........................................................................................................
Grouping Results.......................................................................................................
Executing Queries.............................................................................................................
Single-Valued Query Results...................................................................................
Collection-Valued Query Results............................................................................
40-8
40-9
40-9
40-9
40-9
41 Creating and Using String-Based Criteria Queries
41.1
41.2
41.3
Overview of String-Based Criteria API Queries.................................................................. 41-1
Creating String-Based Queries............................................................................................... 41-1
Executing String-Based Queries ............................................................................................ 41-2
42 Controlling Concurrent Access to Entity Data with Locking
42.1
Overview of Entity Locking and Concurrency....................................................................
42.1.1
Using Optimistic Locking................................................................................................
42.2
Lock Modes...............................................................................................................................
42.2.1
Setting the Lock Mode .....................................................................................................
42.2.2
Using Pessimistic Locking...............................................................................................
42.2.2.1
Pessimistic Locking Timeouts..................................................................................
42-1
42-2
42-2
42-3
42-4
42-4
43 Creating Fetch Plans with Entity Graphs
43.1
Entity Graph Basics..................................................................................................................
43.1.1
The Default Entity Graph ................................................................................................
43.1.2
Using Entity Graphs in Persistence Operations ...........................................................
43.1.2.1
Fetch Graphs ..............................................................................................................
43.1.2.2
Load Graphs ...............................................................................................................
43.2
Using Named Entity Graphs ..................................................................................................
43.2.1
Applying Named Entity Graph Annotations to Entity Classes.................................
43.2.2
Obtaining EntityGraph Instances from Named Entity Graphs .................................
43.3
Using Entity Graphs in Query Operations...........................................................................
43-1
43-1
43-2
43-2
43-2
43-3
43-3
43-4
43-4
44 Using a Second-Level Cache with Java Persistence API Applications
44.1
Overview of the Second-Level Cache ...................................................................................
44.1.1
Controlling whether Entities May Be Cached ..............................................................
44.2
Specifying the Cache Mode Settings to Improve Performance.........................................
44.2.1
Setting the Cache Retrieval and Store Modes...............................................................
44.2.1.1
Cache Retrieval Mode...............................................................................................
44.2.1.2
Cache Store Mode......................................................................................................
44.2.1.3
Setting the Cache Retrieval or Store Mode ............................................................
44.2.2
Controlling the Second-Level Cache Programmatically.............................................
44.2.2.1
Checking whether an Entity's Data Is Cached ......................................................
44.2.2.2
Removing an Entity from the Cache.......................................................................
44.2.2.3
Removing All Data from the Cache ........................................................................
44-1
44-2
44-3
44-3
44-3
44-4
44-4
44-4
44-5
44-5
44-5
Part IX Messaging
xxvii
45
Java Message Service Concepts
45.1
Overview of the JMS API........................................................................................................
45.1.1
What Is Messaging?..........................................................................................................
45.1.2
What Is the JMS API? .......................................................................................................
45.1.3
When Can You Use the JMS API? ..................................................................................
45.1.4
How Does the JMS API Work with the Java EE Platform? ........................................
45.2
Basic JMS API Concepts..........................................................................................................
45.2.1
JMS API Architecture .......................................................................................................
45.2.2
Messaging Styles...............................................................................................................
45.2.2.1
Point-to-Point Messaging Style ...............................................................................
45.2.2.2
Publish/Subscribe Messaging Style .......................................................................
45.2.3
Message Consumption.....................................................................................................
45.3
The JMS API Programming Model .......................................................................................
45.3.1
JMS Administered Objects ..............................................................................................
45.3.1.1
JMS Connection Factories.........................................................................................
45.3.1.2
JMS Destinations........................................................................................................
45.3.2
Connections .......................................................................................................................
45.3.3
Sessions ..............................................................................................................................
45.3.4
JMSContext Objects ..........................................................................................................
45.3.5
JMS Message Producers.................................................................................................
45.3.6
JMS Message Consumers...............................................................................................
45.3.6.1
JMS Message Listeners............................................................................................
45.3.6.2
JMS Message Selectors ............................................................................................
45.3.6.3
Consuming Messages from Topics .......................................................................
45.3.6.4
Creating Durable Subscriptions ............................................................................
45.3.6.5
Creating Shared Subscriptions ..............................................................................
45.3.7
JMS Messages ..................................................................................................................
45.3.7.1
Message Headers .....................................................................................................
45.3.7.2
Message Properties..................................................................................................
45.3.7.3
Message Bodies ........................................................................................................
45.3.8
JMS Queue Browsers......................................................................................................
45.3.9
JMS Exception Handling ...............................................................................................
45.4
Using Advanced JMS Features ............................................................................................
45.4.1
Controlling Message Acknowledgment......................................................................
45.4.2
Specifying Options for Sending Messages ..................................................................
45.4.2.1
Specifying Message Persistence ............................................................................
45.4.2.2
Setting Message Priority Levels ............................................................................
45.4.2.3
Allowing Messages to Expire ................................................................................
45.4.2.4
Specifying a Delivery Delay...................................................................................
45.4.2.5
Using JMSProducer Method Chaining.................................................................
45.4.3
Creating Temporary Destinations................................................................................
45.4.4
Using JMS Local Transactions ......................................................................................
45.4.5
Sending Messages Asynchronously.............................................................................
45.5
Using the JMS API in Java EE Applications.......................................................................
45.5.1
Creating Resources for Java EE Applications.............................................................
45.5.2
Using Resource Injection in Enterprise Bean or Web Components ........................
45.5.2.1
Injecting a ConnectionFactory, Queue, or Topic.................................................
xxviii
45-1
45-1
45-2
45-2
45-3
45-3
45-4
45-4
45-5
45-5
45-6
45-6
45-7
45-8
45-8
45-9
45-9
45-9
45-10
45-10
45-11
45-12
45-12
45-13
45-15
45-16
45-16
45-17
45-17
45-18
45-19
45-19
45-20
45-21
45-21
45-22
45-22
45-23
45-23
45-23
45-24
45-25
45-26
45-26
45-27
45-27
Injecting a JMSContext Object ............................................................................... 45-28
Using Java EE Components to Produce and to Synchronously Receive Messages ...........
45-28
45.5.3.1
Managing JMS Resources in Web and EJB Components................................... 45-29
45.5.3.2
Managing Transactions in Session Beans............................................................. 45-29
45.5.4
Using Message-Driven Beans to Receive Messages Asynchronously .................... 45-29
45.5.5
Managing JTA Transactions.......................................................................................... 45-32
45.6
Further Information about JMS............................................................................................ 45-33
45.5.2.2
45.5.3
46 Java Message Service Examples
46.1
Overview of the JMS Examples .............................................................................................
46.2
Writing Simple JMS Applications..........................................................................................
46.2.1
Starting the JMS Provider ................................................................................................
46.2.2
Creating JMS Administered Objects ..............................................................................
46.2.2.1
To Create Resources for the Simple Examples ......................................................
46.2.3
Building All the Simple Examples .................................................................................
46.2.3.1
To Build All the Simple Examples Using NetBeans IDE .....................................
46.2.3.2
To Build All the Simple Examples Using Maven .................................................
46.2.4
Sending Messages.............................................................................................................
46.2.4.1
The Producer.java Client ..........................................................................................
46.2.4.2
To Run the Producer Client .....................................................................................
46.2.5
Receiving Messages Synchronously ..............................................................................
46.2.5.1
The SynchConsumer.java Client .............................................................................
46.2.5.2
To Run the SynchConsumer and Producer Clients..............................................
46.2.6
Using a Message Listener for Asynchronous Message Delivery...............................
46.2.6.1
Writing the AsynchConsumer.java and TextListener.java Clients ....................
46.2.6.2
To Run the AsynchConsumer and Producer Clients .........................................
46.2.7
Browsing Messages on a Queue ...................................................................................
46.2.7.1
The MessageBrowser.java Client ..........................................................................
46.2.7.2
To Run the QueueBrowser Client .........................................................................
46.2.8
Running Multiple Consumers on the Same Destination ..........................................
46.2.9
Acknowledging Messages .............................................................................................
46.2.9.1
To Run the ClientAckConsumer Client ...............................................................
46.3
Writing More Advanced JMS Applications .......................................................................
46.3.1
Using Durable Subscriptions ........................................................................................
46.3.1.1
To Create Resources for the Durable Subscription Example ............................
46.3.1.2
To Run the Durable Subscription Example .........................................................
46.3.1.3
To Run the unsubscriber Example ........................................................................
46.3.2
Using Local Transactions...............................................................................................
46.3.2.1
To Create Resources for the transactedexample Example.................................
46.3.2.2
To Run the transactedexample Clients.................................................................
46.4
Writing High Performance and Scalable JMS Applications ............................................
46.4.1
Using Shared Nondurable Subscriptions....................................................................
46.4.1.1
Writing the Clients for the Shared Consumer Example ....................................
46.4.1.2
To Run the SharedConsumer and Producer Clients ..........................................
46.4.2
Using Shared Durable Subscriptions ...........................................................................
46.4.2.1
To Run the SharedDurableConsumer and Producer Clients ...........................
46-1
46-2
46-3
46-3
46-3
46-4
46-4
46-4
46-5
46-5
46-6
46-7
46-7
46-7
46-9
46-9
46-10
46-11
46-11
46-12
46-13
46-14
46-15
46-16
46-16
46-17
46-17
46-18
46-18
46-20
46-21
46-23
46-23
46-23
46-24
46-24
46-25
xxix
46.5
Sending and Receiving Messages Using a Simple Web Application .............................
46.5.1
The websimplemessage Facelets Pages .......................................................................
46.5.2
The websimplemessage Managed Beans ....................................................................
46.5.3
Running the websimplemessage Example .................................................................
46.5.3.1
Creating Resources for the websimplemessage Example .................................
46.5.3.2
To Package and Deploy websimplemessage Using NetBeans IDE .................
46.5.3.3
To Package and Deploy websimplemessage Using Maven ..............................
46.5.3.4
To Run the websimplemessage Example.............................................................
46.6
Receiving Messages Asynchronously Using a Message-Driven Bean...........................
46.6.1
Overview of the simplemessage Example ..................................................................
46.6.2
The simplemessage Application Client .......................................................................
46.6.3
The simplemessage Message-Driven Bean Class.......................................................
46.6.3.1
The onMessage Method..........................................................................................
46.6.4
Running the simplemessage Example.........................................................................
46.6.4.1
Creating Resources for the simplemessage Example.........................................
46.6.4.2
To Run the simplemessage Example Using NetBeans IDE...............................
46.6.4.3
To Run the simplemessage Example Using Maven ...........................................
46.7
Sending Messages from a Session Bean to an MDB..........................................................
46.7.1
Writing the Application Components for the clientsessionmdb Example.............
46.7.1.1
Coding the Application Client: MyAppClient.java............................................
46.7.1.2
Coding the Publisher Session Bean.......................................................................
46.7.1.3
Coding the Message-Driven Bean: MessageBean.java.......................................
46.7.2
Running the clientsessionmdb Example .....................................................................
46.7.2.1
To Run clientsessionmdb Using NetBeans IDE ..................................................
46.7.2.2
To Run clientsessionmdb Using Maven...............................................................
46.8
Using an Entity to Join Messages from Two MDBs..........................................................
46.8.1
Overview of the clientmdbentity Example Application ...........................................
46.8.2
Writing the Application Components for the clientmdbentity Example ...............
46.8.2.1
Coding the Application Client: HumanResourceClient.java ............................
46.8.2.2
Coding the Message-Driven Beans for the clientmdbentity Example.............
46.8.2.3
Coding the Entity Class for the clientmdbentity Example ................................
46.8.3
Running the clientmdbentity Example........................................................................
46.8.3.1
To Run clientmdbentity Using NetBeans IDE.....................................................
46.8.3.2
To Run clientmdbentity Using Maven .................................................................
46.8.3.3
Viewing the Application Output...........................................................................
46.9
Using NetBeans IDE to Create JMS Resources ..................................................................
46.9.1
To Create JMS Resources Using NetBeans IDE..........................................................
46.9.2
To Delete JMS Resources Using NetBeans IDE ..........................................................
46-26
46-26
46-26
46-28
46-28
46-28
46-28
46-28
46-29
46-29
46-30
46-30
46-30
46-31
46-31
46-31
46-32
46-32
46-33
46-33
46-34
46-34
46-35
46-35
46-36
46-36
46-37
46-38
46-38
46-38
46-39
46-40
46-40
46-40
46-41
46-42
46-42
46-43
Part X Security
47 Introduction to Security in the Java EE Platform
47.1
Overview of Java EE Security ................................................................................................
47.1.1
A Simple Application Security Walkthrough...............................................................
47.1.1.1
Step 1: Initial Request................................................................................................
47.1.1.2
Step 2: Initial Authentication ...................................................................................
47.1.1.3
Step 3: URL Authorization .......................................................................................
xxx
47-1
47-2
47-2
47-2
47-3
47.1.1.4
Step 4: Fulfilling the Original Request....................................................................
47.1.1.5
Step 5: Invoking Enterprise Bean Business Methods ...........................................
47.1.2
Features of a Security Mechanism..................................................................................
47.1.3
Characteristics of Application Security .........................................................................
47.2
Security Mechanisms...............................................................................................................
47.2.1
Java SE Security Mechanisms .........................................................................................
47.2.2
Java EE Security Mechanisms .........................................................................................
47.2.2.1
Application-Layer Security ......................................................................................
47.2.2.2
Transport-Layer Security..........................................................................................
47.2.2.3
Message-Layer Security............................................................................................
47.3
Securing Containers.................................................................................................................
47.3.1
Using Annotations to Specify Security Information....................................................
47.3.2
Using Deployment Descriptors for Declarative Security............................................
47.3.3
Using Programmatic Security .........................................................................................
47.4
Securing GlassFish Server.......................................................................................................
47.5
Working with Realms, Users, Groups, and Roles .............................................................
47.5.1
What Are Realms, Users, Groups, and Roles?............................................................
47.5.1.1
What Is a Realm? .....................................................................................................
47.5.1.2
What Is a User? ........................................................................................................
47.5.1.3
What Is a Group? .....................................................................................................
47.5.1.4
What Is a Role?.........................................................................................................
47.5.1.5
Some Other Terminology .......................................................................................
47.5.2
Managing Users and Groups in GlassFish Server .....................................................
47.5.2.1
To Add Users to GlassFish Server.........................................................................
47.5.3
Setting Up Security Roles ..............................................................................................
47.5.4
Mapping Roles to Users and Groups...........................................................................
47.6
Establishing a Secure Connection Using SSL.....................................................................
47.6.1
Verifying and Configuring SSL Support.....................................................................
47.7
Further Information about Security ....................................................................................
47-3
47-3
47-4
47-4
47-5
47-5
47-6
47-6
47-7
47-7
47-8
47-8
47-8
47-9
47-9
47-10
47-10
47-11
47-11
47-12
47-12
47-12
47-12
47-13
47-13
47-14
47-15
47-16
47-17
48 Getting Started Securing Web Applications
48.1
Overview of Web Application Security................................................................................
48.2
Securing Web Applications ....................................................................................................
48.2.1
Specifying Security Constraints......................................................................................
48.2.1.1
Specifying a Web Resource Collection ...................................................................
48.2.1.2
Specifying an Authorization Constraint ................................................................
48.2.1.3
Specifying a Secure Connection ..............................................................................
48.2.1.4
Specifying Security Constraints for Resources......................................................
48.2.2
Specifying Authentication Mechanisms........................................................................
48.2.2.1
HTTP Basic Authentication......................................................................................
48.2.2.2
Form-Based Authentication .....................................................................................
48.2.2.3
Digest Authentication ...............................................................................................
48.2.3
Specifying an Authentication Mechanism in the Deployment Descriptor ..............
48.2.4
Declaring Security Roles ..................................................................................................
48.3
Using Programmatic Security with Web Applications ....................................................
48.3.1
Authenticating Users Programmatically.....................................................................
48.3.2
Checking Caller Identity Programmatically ...............................................................
48-1
48-2
48-2
48-3
48-4
48-4
48-5
48-6
48-6
48-7
48-8
48-8
48-9
48-10
48-10
48-12
xxxi
48.3.3
Example Code for Programmatic Security.................................................................. 48-12
48.3.4
Declaring and Linking Role References ...................................................................... 48-13
48.4
Examples: Securing Web Applications ............................................................................... 48-14
48.4.1
To Set Up Your System for Running the Security Examples ................................... 48-14
48.4.2
The hello2-basicauth Example: Basic Authentication with a Servlet ...................... 48-15
48.4.2.1
Specifying Security for Basic Authentication Using Annotations.................... 48-16
48.4.2.2
To Build, Package, and Deploy the hello2-basicauth Example Using NetBeans IDE
48-16
48.4.2.3
To Build, Package, and Deploy the hello2-basicauth Example Using Maven 48-17
48.4.2.4
To Run the hello2-basicauth Example .................................................................. 48-17
48.4.3
The hello1-formauth Example: Form-Based Authentication with a JavaServer Faces
Application 48-18
48.4.3.1
Creating the Login Form and the Error Page ...................................................... 48-18
48.4.3.2
Specifying Security for the Form-Based Authentication Example................... 48-19
48.4.3.3
To Build, Package, and Deploy the hello1-formauth Example Using NetBeans IDE
48-20
48.4.3.4
To Build, Package, and Deploy the hello1-formauth Example Using Maven and
the asadmin Command 48-20
48.4.3.5
To Run the hello1-formauth Example .................................................................. 48-20
49 Getting Started Securing Enterprise Applications
49.1
Basic Security Tasks for Enterprise Applications................................................................
49.2
Securing Enterprise Beans ......................................................................................................
49.2.1
Securing an Enterprise Bean Using Declarative Security ...........................................
49.2.1.1
Specifying Authorized Users by Declaring Security Roles .................................
49.2.1.2
Specifying an Authentication Mechanism and Secure Connection ...................
49.2.2
Securing an Enterprise Bean Programmatically...........................................................
49.2.2.1
Accessing an Enterprise Bean Caller's Security Context .....................................
49.2.3
Propagating a Security Identity (Run-As).....................................................................
49.2.3.1
Configuring a Component's Propagated Security Identity.................................
49.2.3.2
Trust between Containers ........................................................................................
49.2.4
Deploying Secure Enterprise Beans ...............................................................................
49.3
Examples: Securing Enterprise Beans ...................................................................................
49.3.1
The cart-secure Example: Securing an Enterprise Bean with Declarative Security
49.3.1.1
Annotating the Bean................................................................................................
49.3.1.2
To Run the cart-secure Example Using NetBeans IDE ......................................
49.3.1.3
To Run the cart-secure Example Using Maven...................................................
49.3.2
The converter-secure Example: Securing an Enterprise Bean with Programmatic
Security 49-13
49.3.2.1
Modifying ConverterBean......................................................................................
49.3.2.2
Modifying ConverterServlet ..................................................................................
49.3.2.3
To Run the converter-secure Example Using NetBeans IDE ............................
49.3.2.4
To Run the converter-secure Example Using Maven.........................................
49.3.2.5
To Run the converter-secure Example .................................................................
49-1
49-1
49-3
49-3
49-6
49-6
49-6
49-8
49-8
49-9
49-9
49-9
49-9
49-10
49-11
49-12
49-13
49-14
49-14
49-15
49-15
50 Java EE Security: Advanced Topics
50.1
xxxii
Working with Digital Certificates.......................................................................................... 50-1
50.1.1
Creating a Server Certificate ........................................................................................... 50-2
50.1.1.1
To Use keytool to Create a Server Certificate........................................................ 50-3
50.1.2
Adding Users to the Certificate Realm .......................................................................... 50-4
50.1.3
Using a Different Server Certificate with GlassFish Server........................................ 50-4
50.1.3.1
To Specify a Different Server Certificate................................................................ 50-4
50.2
Authentication Mechanisms................................................................................................... 50-5
50.2.1
Client Authentication ....................................................................................................... 50-5
50.2.2
Mutual Authentication..................................................................................................... 50-5
50.2.2.1
Enabling Mutual Authentication over SSL ............................................................ 50-7
50.2.2.2
Creating a Client Certificate for Mutual Authentication ..................................... 50-7
50.3
Using the JDBC Realm for User Authentication ................................................................. 50-9
50.3.1
To Configure a JDBC Authentication Realm ................................................................ 50-9
50.4
Securing HTTP Resources .................................................................................................... 50-10
50.5
Securing Application Clients................................................................................................ 50-13
50.5.1
Using Login Modules..................................................................................................... 50-13
50.5.2
Using Programmatic Login ........................................................................................... 50-14
50.6
Securing Enterprise Information Systems Applications .................................................. 50-14
50.6.1
Container-Managed Sign-On ........................................................................................ 50-14
50.6.2
Component-Managed Sign-On..................................................................................... 50-15
50.6.3
Configuring Resource Adapter Security ..................................................................... 50-15
50.6.4
Mapping an Application Principal to EIS Principals................................................. 50-16
50.7
Configuring Security Using Deployment Descriptors ..................................................... 50-17
50.7.1
Specifying Security for Basic Authentication in the Deployment Descriptor........ 50-17
50.7.2
Specifying Non-Default Principal-to-Role Mapping in the Deployment Descriptor ........
50-17
50.8
Further Information about Advanced Security Topics .................................................... 50-18
Part XI Java EE Supporting Technologies
51 Transactions
51.1
Transactions in Java EE Applications ...................................................................................
51.2
What Is a Transaction? ............................................................................................................
51.3
Container-Managed Transactions .........................................................................................
51.3.1
Transaction Attributes .....................................................................................................
51.3.1.1
Required Attribute ....................................................................................................
51.3.1.2
RequiresNew Attribute.............................................................................................
51.3.1.3
Mandatory Attribute .................................................................................................
51.3.1.4
NotSupported Attribute ...........................................................................................
51.3.1.5
Supports Attribute.....................................................................................................
51.3.1.6
Never Attribute..........................................................................................................
51.3.1.7
Summary of Transaction Attributes .......................................................................
51.3.1.8
Setting Transaction Attributes .................................................................................
51.3.2
Rolling Back a Container-Managed Transaction .........................................................
51.3.3
Synchronizing a Session Bean's Instance Variables .....................................................
51.3.4
Methods Not Allowed in Container-Managed Transactions.....................................
51.4
Bean-Managed Transactions ..................................................................................................
51.4.1
JTA Transactions...............................................................................................................
51-1
51-2
51-2
51-3
51-3
51-3
51-4
51-4
51-4
51-4
51-4
51-5
51-6
51-6
51-6
51-7
51-7
xxxiii
51.4.2
51.4.3
51.5
51.5.1
51.6
51.7
51.8
Returning without Committing......................................................................................
Methods Not Allowed in Bean-Managed Transactions..............................................
Transaction Timeouts ..............................................................................................................
To Set a Transaction Timeout..........................................................................................
Updating Multiple Databases ................................................................................................
Transactions in Web Components.........................................................................................
Further Information about Transactions ..............................................................................
51-7
51-8
51-8
51-8
51-8
51-9
51-9
52 Resource Adapters and Contracts
52.1
What Is a Resource Adapter? .................................................................................................
52.1.1
Management Contracts ....................................................................................................
52.1.1.1
Lifecycle Management ..............................................................................................
52.1.1.2
Work Management Contract ...................................................................................
52.1.2
Generic Work Context Contract .....................................................................................
52.1.3
Outbound and Inbound Contracts.................................................................................
52.2
Metadata Annotations.............................................................................................................
52.3
Common Client Interface........................................................................................................
52.4
Using Resource Adapters with Contexts and Dependency Injection for Java EE (CDI)
52.5
Further Information about Resource Adapters ...................................................................
52-1
52-2
52-2
52-2
52-3
52-3
52-4
52-5
52-6
52-7
53 The Resource Adapter Examples
53.1
The trading Example ...............................................................................................................
53.1.1
Using the Outbound Resource Adapter........................................................................
53.1.2
Implementing the Outbound Resource Adapter .........................................................
53.1.3
Running the trading Example.........................................................................................
53.1.3.1
To Run the trading Example Using NetBeans IDE...............................................
53.1.3.2
To Run the trading Example Using Maven ...........................................................
53.2
The traffic Example..................................................................................................................
53.2.1
Using the Inbound Resource Adapter ...........................................................................
53.2.2
Implementing the Inbound Resource Adapter ............................................................
53.2.3
Running the traffic Example .........................................................................................
53.2.3.1
To Run the traffic Example Using NetBeans IDE ...............................................
53.2.3.2
To Run the traffic Example Using Maven............................................................
53-1
53-2
53-4
53-5
53-5
53-6
53-6
53-7
53-8
53-10
53-11
53-11
54 Using Java EE Interceptors
54.1
Overview of Interceptors ........................................................................................................
54.1.1
Interceptor Classes............................................................................................................
54.1.2
Interceptor Lifecycle .........................................................................................................
54.1.3
Interceptors and CDI........................................................................................................
54.2
Using Interceptors....................................................................................................................
54.2.1
Intercepting Method Invocations ...................................................................................
54.2.1.1
Using Multiple Method Interceptors ......................................................................
54.2.1.2
Accessing Target Method Parameters from an Interceptor Class ......................
54.2.2
Intercepting Lifecycle Callback Events..........................................................................
54.2.2.1
Using AroundConstruct Interceptor Methods......................................................
54.2.2.2
Using Multiple Lifecycle Callback Interceptors....................................................
xxxiv
54-1
54-2
54-2
54-2
54-2
54-3
54-3
54-4
54-4
54-5
54-5
54.2.3
Intercepting Timeout Events...........................................................................................
54.2.3.1
Using Multiple Timeout Interceptors .....................................................................
54.2.4
Binding Interceptors to Components.............................................................................
54.2.4.1
Declaring the Interceptor Bindings on an Interceptor Class ...............................
54.2.4.2
Binding a Component to an Interceptor ................................................................
54.2.5
Ordering Interceptors.......................................................................................................
54.3
The interceptor Example Application...................................................................................
54.3.1
Running the interceptor Example ..................................................................................
54.3.1.1
To Run the interceptor Example Using NetBeans IDE ......................................
54.3.1.2
To Run the interceptor Example Using Maven...................................................
54-6
54-6
54-6
54-7
54-7
54-8
54-9
54-9
54-10
54-10
55 Batch Processing
55.1
Introduction to Batch Processing...........................................................................................
55.1.1
Steps in Batch Jobs ............................................................................................................
55.1.2
Parallel Processing............................................................................................................
55.1.3
Status and Decision Elements .........................................................................................
55.1.4
Batch Framework Functionality .....................................................................................
55.2
Batch Processing in Java EE....................................................................................................
55.2.1
The Batch Processing Framework ..................................................................................
55.2.2
Creating Batch Applications ...........................................................................................
55.2.3
Elements of a Batch Job....................................................................................................
55.2.4
Properties and Parameters ..............................................................................................
55.2.5
Job Instances and Job Executions ...................................................................................
55.2.6
Batch and Exit Status........................................................................................................
55.3
Simple Use Case .......................................................................................................................
55.3.1
Chunk Step ........................................................................................................................
55.3.2
Task Step ............................................................................................................................
55.4
Using the Job Specification Language.................................................................................
55.4.1
The job Element...............................................................................................................
55.4.2
The step Element.............................................................................................................
55.4.2.1
The chunk Element..................................................................................................
55.4.2.2
The batchlet Element...............................................................................................
55.4.2.3
The partition Element .............................................................................................
55.4.3
The flow Element ............................................................................................................
55.4.4
The split Element ............................................................................................................
55.4.5
The decision Element .....................................................................................................
55.5
Creating Batch Artifacts ........................................................................................................
55.5.1
Batch Artifact Interfaces.................................................................................................
55.5.2
Dependency Injection in Batch Artifacts .....................................................................
55.5.3
Using the Context Objects from the Batch Runtime ..................................................
55.6
Submitting Jobs to the Batch Runtime ................................................................................
55.6.1
Starting a Job....................................................................................................................
55.6.2
Checking the Status of a Job..........................................................................................
55.6.3
Invoking the Batch Runtime in Your Application .....................................................
55.7
Packaging Batch Applications..............................................................................................
55.8
The webserverlog Example Application ............................................................................
55.8.1
Architecture of the webserverlog Example Application...........................................
55-1
55-2
55-3
55-3
55-4
55-4
55-4
55-5
55-5
55-6
55-6
55-6
55-7
55-7
55-9
55-10
55-10
55-11
55-12
55-14
55-14
55-16
55-16
55-17
55-17
55-17
55-20
55-21
55-21
55-22
55-22
55-22
55-22
55-23
55-23
xxxv
55.8.1.1
The Job Definition File ............................................................................................
55.8.1.2
The LogLine and LogFilteredLine Items..............................................................
55.8.1.3
The Chunk Step Batch Artifacts ............................................................................
55.8.1.4
The Listener Batch Artifacts ...................................................................................
55.8.1.5
The Task Step Batch Artifact..................................................................................
55.8.1.6
The JavaServer Faces Pages....................................................................................
55.8.1.7
The Managed Bean ..................................................................................................
55.8.2
Running the webserverlog Example Application......................................................
55.8.2.1
To Run the webserverlog Example Application Using NetBeans IDE............
55.8.2.2
To Run the webserverlog Example Application Using Maven ........................
55.9
The phonebilling Example Application..............................................................................
55.9.1
Architecture of the phonebilling Example Application ............................................
55.9.1.1
The Job Definition File ............................................................................................
55.9.1.2
The CallRecord and PhoneBill Entities ................................................................
55.9.1.3
The Call Records Chunk Step ................................................................................
55.9.1.4
The Phone Billing Chunk Step...............................................................................
55.9.1.5
The JavaServer Faces Pages....................................................................................
55.9.1.6
The Managed Bean ..................................................................................................
55.9.2
Running the phonebilling Example Application .......................................................
55.9.2.1
To Run the phonebilling Example Application Using NetBeans IDE .............
55.9.2.2
To Run the phonebilling Example Application Using Maven..........................
55.10 Further Information about Batch Processing .....................................................................
55-23
55-24
55-25
55-26
55-27
55-27
55-27
55-28
55-28
55-28
55-29
55-29
55-29
55-30
55-31
55-33
55-34
55-35
55-35
55-35
55-36
55-36
56 Concurrency Utilities for Java EE
56.1
Concurrency Basics.................................................................................................................. 56-1
56.1.1
Threads and Processes ..................................................................................................... 56-1
56.2
Main Components of the Concurrency Utilities ................................................................. 56-2
56.3
Concurrency and Transactions .............................................................................................. 56-3
56.4
Concurrency and Security ...................................................................................................... 56-3
56.5
The jobs Concurrency Example ............................................................................................. 56-3
56.5.1
Running the jobs Example............................................................................................... 56-4
56.5.1.1
To Configure GlassFish Server for the Basic Concurrency Example................. 56-4
56.5.1.2
To Build, Package, and Deploy the jobs Example Using NetBeans IDE ........... 56-5
56.5.1.3
To Build, Package, and Deploy the jobs Example Using Maven........................ 56-5
56.5.1.4
To Run the jobs Example and Submit Jobs with Low Priority ........................... 56-5
56.5.1.5
To Run the jobs Example and Submit Jobs with High Priority .......................... 56-6
56.6
The taskcreator Concurrency Example................................................................................. 56-7
56.6.1
Running the taskcreator Example .................................................................................. 56-8
56.6.1.1
To Build, Package, and Deploy the taskcreator Example Using NetBeans IDE..........
56-8
56.6.1.2
To Build, Package, and Deploy the taskcreator Example Using Maven ........... 56-8
56.6.1.3
To Run the taskcreator Example ............................................................................. 56-9
56.7
Further Information about the Concurrency Utilities ........................................................ 56-9
Part XII
xxxvi
Case Studies
57 Duke's Bookstore Case Study Example
57.1
Design and Architecture of Duke's Bookstore.....................................................................
57.2
The Duke's Bookstore Interface .............................................................................................
57.2.1
The Book Java Persistence API Entity............................................................................
57.2.2
Enterprise Beans Used in Duke's Bookstore .................................................................
57.2.3
Facelets Pages and Managed Beans Used in Duke's Bookstore.................................
57.2.4
Custom Components and Other Custom Objects Used in Duke's Bookstore .........
57.2.5
Properties Files Used in Duke's Bookstore ...................................................................
57.2.6
Deployment Descriptors Used in Duke's Bookstore ...................................................
57.3
Running the Duke's Bookstore Case Study Application....................................................
57.3.1
To Build and Deploy Duke's Bookstore Using NetBeans IDE ...................................
57.3.2
To Build and Deploy Duke's Bookstore Using Maven................................................
57.3.3
To Run Duke's Bookstore ................................................................................................
58
57-1
57-2
57-2
57-3
57-3
57-4
57-5
57-5
57-6
57-6
57-6
57-6
Duke's Tutoring Case Study Example
58.1
Design and Architecture of Duke's Tutoring.......................................................................
58.2
Main Interface...........................................................................................................................
58.2.1
Java Persistence API Entities Used in the Main Interface...........................................
58.2.2
Enterprise Beans Used in the Main Interface................................................................
58.2.3
WebSocket Endpoint Used in the Main Interface ........................................................
58.2.4
Facelets Files Used in the Main Interface ......................................................................
58.2.5
Helper Classes Used in the Main Interface ...................................................................
58.2.6
Properties Files ..................................................................................................................
58.2.7
Deployment Descriptors Used in Duke's Tutoring .....................................................
58.3
Administration Interface.........................................................................................................
58.3.1
Enterprise Beans Used in the Administration Interface..............................................
58.3.2
Facelets Files Used in the Administration Interface ....................................................
58.3.3
CDI Managed Beans Used in the Administration Interface .......................................
58.3.4
Helper Classes Used in the Administration Interface .................................................
58.4
Running the Duke's Tutoring Case Study Application......................................................
58.4.1
Running Duke's Tutoring ................................................................................................
58.4.1.1
To Build and Deploy Duke's Tutoring Using NetBeans IDE..............................
58.4.1.2
To Build and Deploy Duke's Tutoring Using Maven ..........................................
58.4.1.3
Using Duke's Tutoring..............................................................................................
58-1
58-3
58-3
58-4
58-4
58-4
58-5
58-5
58-6
58-6
58-6
58-7
58-7
58-7
58-8
58-8
58-8
58-8
58-9
59 Duke's Forest Case Study Example
59.1
Design and Architecture of Duke's Forest............................................................................
59.1.1
The events Project .............................................................................................................
59.1.2
The entities Project............................................................................................................
59.1.3
The dukes-payment Project.............................................................................................
59.1.4
The dukes-resources Project............................................................................................
59.1.5
The Duke's Store Project ..................................................................................................
59.1.5.1
Enterprise Beans Used in Duke's Store ..................................................................
59.1.5.2
Facelets Files Used in the Main Interface of Duke's Store ...................................
59.1.5.3
Facelets Files Used in the Administration Interface of Duke's Store ...............
59.1.5.4
Managed Beans Used in Duke's Store ..................................................................
59-2
59-4
59-5
59-7
59-7
59-8
59-9
59-9
59-10
59-10
xxxvii
59.1.5.5
Helper Classes Used in Duke's Store....................................................................
59.1.5.6
Qualifiers Used in Duke's Store.............................................................................
59.1.5.7
Event Handlers Used in Duke's Store ..................................................................
59.1.5.8
Deployment Descriptors Used in Duke's Store...................................................
59.1.6
The Duke's Shipment Project ........................................................................................
59.1.6.1
Enterprise Beans Used in Duke's Shipment ........................................................
59.1.6.2
Facelets Files Used in Duke's Shipment ...............................................................
59.1.6.3
Managed Beans Used in Duke's Shipment ..........................................................
59.1.6.4
Helper Class Used in Duke's Shipment ...............................................................
59.1.6.5
Qualifier Used in Duke's Shipment ......................................................................
59.1.6.6
Deployment Descriptors Used in Duke's Shipment...........................................
59.2
Building and Deploying the Duke's Forest Case Study Application .............................
59.2.1
To Build and Deploy the Duke's Forest Application Using NetBeans IDE ...........
59.2.2
To Build and Deploy the Duke's Forest Application Using Maven........................
59.3
Running the Duke's Forest Application .............................................................................
59.3.1
To Register as a Duke's Store Customer......................................................................
59.3.2
To Purchase Products.....................................................................................................
59.3.3
To Approve Shipment of a Product .............................................................................
59.3.4
To Create a New Product ..............................................................................................
Index
xxxviii
59-11
59-11
59-11
59-11
59-11
59-12
59-12
59-12
59-13
59-13
59-13
59-13
59-13
59-13
59-14
59-14
59-14
59-15
59-15
Preface
This tutorial is a guide to developing enterprise applications for the Java Platform,
Enterprise Edition 7 (Java EE 7), using GlassFish Server Open Source Edition.
GlassFish Server Open Source Edition is the leading open-source and
open-community platform for building and deploying next-generation applications
and services. GlassFish Server Open Source Edition, developed by the GlassFish
project open-source community at https://glassfish.java.net/, is the first
compatible implementation of the Java EE 7 platform specification. This lightweight,
flexible, and open-source application server enables organizations not only to leverage
the new capabilities introduced within the Java EE 7 specification, but also to add to
their existing capabilities through a faster and more streamlined development and
deployment cycle. GlassFish Server Open Source Edition is hereafter referred to as
GlassFish Server.
The following topics are addressed here:
■
Audience
■
Documentation Accessibility
■
Before You Read This Book
■
Related Documentation
■
Conventions
■
Default Paths and File Names
Audience
This tutorial is intended for programmers interested in developing and deploying Java
EE 7 applications. It covers the technologies comprising the Java EE platform and
describes how to develop Java EE components and deploy them on the Java EE
Software Development Kit (SDK).
Documentation Accessibility
For information about Oracle's commitment to accessibility, visit the Oracle
Accessibility Program website at
http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc.
xxxix
Before You Read This Book
Before proceeding with this tutorial, you should have a good knowledge of the Java
programming language. A good way to get to that point is to work through the Java
Tutorials (http://docs.oracle.com/javase/tutorial/index.html).
Related Documentation
The GlassFish Server documentation set describes deployment planning and system
installation. To obtain documentation for GlassFish Server Open Source Edition, go to
https://glassfish.java.net/docs/.
The Java EE 7 API specification can be viewed at
http://docs.oracle.com/javaee/7/api/ and is also provided in the Java EE 7
SDK.
Additionally, the Java EE Specifications at
http://www.oracle.com/technetwork/java/javaee/tech/index.html
might be useful.
For information about creating enterprise applications in the NetBeans Integrated
Development Environment (IDE), see http://www.netbeans.org/kb/.
For information about the Java DB database for use with GlassFish Server, see
http://www.oracle.com/technetwork/java/javadb/overview/index.htm
l.
The GlassFish Samples project is a collection of sample applications that demonstrate a
broad range of Java EE technologies. The GlassFish Samples are bundled with the Java
EE Software Development Kit (SDK) and are also available from the GlassFish
Samples project page at https://glassfish-samples.java.net/.
Conventions
The following table describes the typographic conventions that are used in this book.
Convention Meaning
Boldface
Boldface type indicates graphical
user interface elements associated
with an action or terms defined in
text.
Example
From the File menu, choose Open
Project.
A cache is a copy that is stored locally.
Monospace
Monospace type indicates the names Edit your .login file.
of files and directories, commands
Use ls -a to list all files.
within a paragraph, URLs, code in
examples, text that appears on the
machine_name% you have mail.
screen, or text that you enter.
Italic
Italic type indicates book titles,
emphasis, or placeholder variables
for which you supply particular
values.
Read Chapter 6 in the User's Guide.
Do not save the file.
The command to remove a file is rm
filename.
Default Paths and File Names
The following table describes the default paths and file names that are used in this
book.
xl
Placeholder
Description
Default Value
as-install
Represents the base
installation directory for
GlassFish Server or the SDK
of which GlassFish Server is
a part.
Installations on the Solaris operating system,
Linux operating system, and Mac operating
system:
user's-home-directory/glassfish4/glassfish
Windows, all installations:
SystemDrive:\glassfish4\glassfish
as-install-parent
Represents the parent of the
base installation directory
for GlassFish Server.
Installations on the Solaris operating system,
Linux operating system, and Mac operating
system:
user's-home-directory/glassfish4
Windows, all installations:
SystemDrive:\glassfish4
tut-install
Represents the base
as-install-parent/docs/javaee-tutorial
installation directory for the
Java EE Tutorial after you
install GlassFish Server or
the SDK and run the Update
Tool.
domain-dir
Represents the directory in
which a domain's
configuration is stored.
as-install/domains/domain1
xli
xlii
Part I
Part I
Introduction
Part I introduces the platform, the tutorial, and the examples. This part contains the
following chapters:
■
Chapter 1, "Overview"
■
Chapter 2, "Using the Tutorial Examples"
1
Overview
1
This chapter introduces you to Java EE enterprise application development. Here you
will review development basics, learn about the Java EE architecture and APIs,
become acquainted with important terms and concepts, and find out how to approach
Java EE application programming, assembly, and deployment.
Developers today increasingly recognize the need for distributed, transactional, and
portable applications that leverage the speed, security, and reliability of server-side
technology. Enterprise applications provide the business logic for an enterprise. They
are centrally managed and often interact with other enterprise software. In the world
of information technology, enterprise applications must be designed, built, and
produced for less money, with greater speed, and with fewer resources.
With the Java Platform, Enterprise Edition (Java EE), development of Java enterprise
applications has never been easier or faster. The aim of the Java EE platform is to
provide developers with a powerful set of APIs while shortening development time,
reducing application complexity, and improving application performance.
The Java EE platform is developed through the Java Community Process (JCP), which
is responsible for all Java technologies. Expert groups composed of interested parties
have created Java Specification Requests (JSRs) to define the various Java EE
technologies. The work of the Java Community under the JCP program helps to ensure
Java technology's standards of stability and cross-platform compatibility.
The Java EE platform uses a simplified programming model. XML deployment
descriptors are optional. Instead, a developer can simply enter the information as an
annotation directly into a Java source file, and the Java EE server will configure the
component at deployment and runtime. These annotations are generally used to
embed in a program data that would otherwise be furnished in a deployment
descriptor. With annotations, you put the specification information in your code next
to the program element affected.
In the Java EE platform, dependency injection can be applied to all resources a
component needs, effectively hiding the creation and lookup of resources from
application code. Dependency injection can be used in Enterprise JavaBeans (EJB)
containers, web containers, and application clients. Dependency injection allows the
Java EE container to automatically insert references to other required components or
resources, using annotations.
This tutorial uses examples to describe the features available in the Java EE platform
for developing enterprise applications. Whether you are a new or experienced
enterprise developer, you should find the examples and accompanying text a valuable
and accessible knowledge base for creating your own solutions.
The following topics are addressed here:
■
Java EE 7 Platform Highlights
Overview 1-1
Java EE 7 Platform Highlights
■
Java EE Application Model
■
Distributed Multitiered Applications
■
Java EE Containers
■
Web Services Support
■
Java EE Application Assembly and Deployment
■
Java EE 7 APIs
■
Java EE 7 APIs in the Java Platform, Standard Edition 7
■
GlassFish Server Tools
1.1 Java EE 7 Platform Highlights
The most important goal of the Java EE 7 platform is to simplify development by
providing a common foundation for the various kinds of components in the Java EE
platform. Developers benefit from productivity improvements with more annotations
and less XML configuration, more Plain Old Java Objects (POJOs), and simplified
packaging. The Java EE 7 platform includes the following new features:
■
■
■
■
■
New technologies, including the following:
–
Batch Applications for the Java Platform
–
Concurrency Utilities for Java EE
–
Java API for JSON Processing (JSON-P)
–
Java API for WebSocket
New features for EJB components (see Enterprise JavaBeans Technology for
details)
New features for servlets (see Java Servlet Technology for details)
New features for JavaServer Faces components (see JavaServer Faces Technology
for details)
New features for the Java Message Service (JMS) (see Java Message Service API for
details)
1.2 Java EE Application Model
The Java EE application model begins with the Java programming language and the
Java virtual machine. The proven portability, security, and developer productivity they
provide form the basis of the application model. Java EE is designed to support
applications that implement enterprise services for customers, employees, suppliers,
partners, and others who make demands on or contributions to the enterprise. Such
applications are inherently complex, potentially accessing data from a variety of
sources and distributing applications to a variety of clients.
To better control and manage these applications, the business functions to support
these various users are conducted in the middle tier. The middle tier represents an
environment that is closely controlled by an enterprise's information technology
department. The middle tier is typically run on dedicated server hardware and has
access to the full services of the enterprise.
The Java EE application model defines an architecture for implementing services as
multitier applications that deliver the scalability, accessibility, and manageability
1-2 The Java EE 7 Tutorial
Distributed Multitiered Applications
needed by enterprise-level applications. This model partitions the work needed to
implement a multitier service into the following parts:
■
The business and presentation logic to be implemented by the developer
■
The standard system services provided by the Java EE platform
The developer can rely on the platform to provide solutions for the hard systems-level
problems of developing a multitier service.
1.3 Distributed Multitiered Applications
The Java EE platform uses a distributed multitiered application model for enterprise
applications. Application logic is divided into components according to function, and
the application components that make up a Java EE application are installed on
various machines depending on the tier in the multitiered Java EE environment to
which the application component belongs.
Figure 1–1 shows two multitiered Java EE applications divided into the tiers described
in the following list. The Java EE application parts shown in Figure 1–1 are presented
in Java EE Components.
■
Client-tier components run on the client machine.
■
Web-tier components run on the Java EE server.
■
Business-tier components run on the Java EE server.
■
Enterprise information system (EIS)-tier software runs on the EIS server.
Although a Java EE application can consist of all tiers shown in Figure 1–1, Java EE
multitiered applications are generally considered to be three-tiered applications
because they are distributed over three locations: client machines, the Java EE server
machine, and the database or legacy machines at the back end. Three-tiered
applications that run in this way extend the standard two-tiered client-and-server
model by placing a multithreaded application server between the client application
and back-end storage.
Overview 1-3
Distributed Multitiered Applications
Figure 1–1 Multitiered Applications
Java EE Application 1
Java EE Application 2
Client
Tier
Application Client
Client
Machine
Web Pages
JavaServer Faces
Pages
Web
Tier
Java EE
Server
Enterprise Beans
Enterprise Beans
Business
Tier
Database
Database
EIS
Tier
Database
Server
1.3.1 Security
Although other enterprise application models require platform-specific security
measures in each application, the Java EE security environment enables security
constraints to be defined at deployment time. The Java EE platform makes
applications portable to a wide variety of security implementations by shielding
application developers from the complexity of implementing security features.
The Java EE platform provides standard declarative access control rules that are
defined by the developer and interpreted when the application is deployed on the
server. Java EE also provides standard login mechanisms so that application
developers do not have to implement these mechanisms in their applications. The
same application works in a variety of security environments without changing the
source code.
1.3.2 Java EE Components
Java EE applications are made up of components. A Java EE component is a
self-contained functional software unit that is assembled into a Java EE application
with its related classes and files and that communicates with other components.
The Java EE specification defines the following Java EE components:
■
■
Application clients and applets are components that run on the client.
Java Servlet, JavaServer Faces, and JavaServer Pages (JSP) technology components
are web components that run on the server.
1-4 The Java EE 7 Tutorial
Distributed Multitiered Applications
■
EJB components (enterprise beans) are business components that run on the
server.
Java EE components are written in the Java programming language and are compiled
in the same way as any program in the language. The differences between Java EE
components and "standard" Java classes are that Java EE components are assembled
into a Java EE application, they are verified to be well formed and in compliance with
the Java EE specification, and they are deployed to production, where they are run and
managed by the Java EE server.
1.3.3 Java EE Clients
A Java EE client is usually either a web client or an application client.
1.3.3.1 Web Clients
A web client consists of two parts:
■
■
Dynamic web pages containing various types of markup language (HTML, XML,
and so on), which are generated by web components running in the web tier
A web browser, which renders the pages received from the server
A web client is sometimes called a thin client. Thin clients usually do not query
databases, execute complex business rules, or connect to legacy applications. When
you use a thin client, such heavyweight operations are off-loaded to enterprise beans
executing on the Java EE server, where they can leverage the security, speed, services,
and reliability of Java EE server-side technologies.
1.3.3.2 Application Clients
An application client runs on a client machine and provides a way for users to handle
tasks that require a richer user interface than can be provided by a markup language.
An application client typically has a graphical user interface (GUI) created from the
Swing API or the Abstract Window Toolkit (AWT) API, but a command-line interface
is certainly possible.
Application clients directly access enterprise beans running in the business tier.
However, if application requirements warrant it, an application client can open an
HTTP connection to establish communication with a servlet running in the web tier.
Application clients written in languages other than Java can interact with Java EE
servers, enabling the Java EE platform to interoperate with legacy systems, clients, and
non-Java languages.
1.3.3.3 Applets
A web page received from the web tier can include an embedded applet. Written in the
Java programming language, an applet is a small client application that executes in the
Java virtual machine installed in the web browser. However, client systems will likely
need the Java Plug-in and possibly a security policy file for the applet to successfully
execute in the web browser.
Web components are the preferred API for creating a web client program because no
plug-ins or security policy files are needed on the client systems. Also, web
components enable cleaner and more modular application design because they
provide a way to separate applications programming from web page design.
Personnel involved in web page design thus do not need to understand Java
programming language syntax to do their jobs.
Overview 1-5
Distributed Multitiered Applications
1.3.3.4 The JavaBeans Component Architecture
The server and client tiers might also include components based on the JavaBeans
component architecture (JavaBeans components) to manage the data flow between the
following:
■
An application client or applet and components running on the Java EE server
■
Server components and a database
JavaBeans components are not considered Java EE components by the Java EE
specification.
JavaBeans components have properties and have get and set methods for accessing
those properties. JavaBeans components used in this way are typically simple in
design and implementation but should conform to the naming and design conventions
outlined in the JavaBeans component architecture.
1.3.3.5 Java EE Server Communications
Figure 1–2 shows the various elements that can make up the client tier. The client
communicates with the business tier running on the Java EE server either directly or,
as in the case of a client running in a browser, by going through web pages or servlets
running in the web tier.
Figure 1–2 Server Communication
Application Client and Optional
JavaBeans Components
Web Browser, Web Pages,
Applets, and Optional
JavaBeans Components
Web Tier
Client
Tier
Java EE
Server
Business Tier
1.3.4 Web Components
Java EE web components are either servlets or web pages created using JavaServer
Faces technology and/or JSP technology (JSP pages). Servlets are Java programming
language classes that dynamically process requests and construct responses. JSP pages
are text-based documents that execute as servlets but allow a more natural approach to
creating static content. JavaServer Faces technology builds on servlets and JSP
technology and provides a user interface component framework for web applications.
Static HTML pages and applets are bundled with web components during application
assembly but are not considered web components by the Java EE specification.
Server-side utility classes can also be bundled with web components and, like HTML
pages, are not considered web components.
1-6 The Java EE 7 Tutorial
Distributed Multitiered Applications
As shown in Figure 1–3, the web tier, like the client tier, might include a JavaBeans
component to manage the user input and send that input to enterprise beans running
in the business tier for processing.
Figure 1–3 Web Tier and Java EE Applications
Application Client and Optional
JavaBeans Components
JavaBeans Components
(Optional)
Web Browser, Web Pages,
Applets, and Optional JavaBeans
Components
Web Pages, Servlets
Web
Tier
Client
Tier
Java EE
Server
Business
Tier
1.3.5 Business Components
Business code, which is logic that solves or meets the needs of a particular business
domain such as banking, retail, or finance, is handled by enterprise beans running in
either the business tier or the web tier. Figure 1–4 shows how an enterprise bean
receives data from client programs, processes it (if necessary), and sends it to the
enterprise information system tier for storage. An enterprise bean also retrieves data
from storage, processes it (if necessary), and sends it back to the client program.
Overview 1-7
Java EE Containers
Figure 1–4 Business and EIS Tiers
Application Client and Optional
JavaBeans Components
JavaBeans Components
(Optional)
Web Browser, Web Pages,
Applets, and Optional JavaBeans
Components
Web Pages, Servlets
Java Persistence Entities, Session Beans,
Message-Driven Beans
Database and Legacy Systems
Web
Tier
Client
Tier
Java EE
Server
Business
Tier
EIS
Tier
1.3.6 Enterprise Information System Tier
The enterprise information system tier handles EIS software and includes enterprise
infrastructure systems, such as enterprise resource planning (ERP), mainframe
transaction processing, database systems, and other legacy information systems. For
example, Java EE application components might need access to enterprise information
systems for database connectivity.
1.4 Java EE Containers
Normally, thin-client multitiered applications are hard to write because they involve
many lines of intricate code to handle transaction and state management,
multithreading, resource pooling, and other complex low-level details. The
component-based and platform-independent Java EE architecture makes applications
easy to write because business logic is organized into reusable components. In
addition, the Java EE server provides underlying services in the form of a container for
every component type. Because you do not have to develop these services yourself,
you are free to concentrate on solving the business problem at hand.
1-8 The Java EE 7 Tutorial
Java EE Containers
1.4.1 Container Services
Containers are the interface between a component and the low-level, platform-specific
functionality that supports the component. Before it can be executed, a web, enterprise
bean, or application client component must be assembled into a Java EE module and
deployed into its container.
The assembly process involves specifying container settings for each component in the
Java EE application and for the Java EE application itself. Container settings customize
the underlying support provided by the Java EE server, including such services as
security, transaction management, Java Naming and Directory Interface (JNDI) API
lookups, and remote connectivity. Here are some of the highlights.
■
■
■
■
The Java EE security model lets you configure a web component or enterprise
bean so that system resources are accessed only by authorized users.
The Java EE transaction model lets you specify relationships among methods that
make up a single transaction so that all methods in one transaction are treated as a
single unit.
JNDI lookup services provide a unified interface to multiple naming and directory
services in the enterprise so that application components can access these services.
The Java EE remote connectivity model manages low-level communications
between clients and enterprise beans. After an enterprise bean is created, a client
invokes methods on it as if it were in the same virtual machine.
Because the Java EE architecture provides configurable services, components within
the same application can behave differently based on where they are deployed. For
example, an enterprise bean can have security settings that allow it a certain level of
access to database data in one production environment and another level of database
access in another production environment.
The container also manages nonconfigurable services, such as enterprise bean and
servlet lifecycles, database connection resource pooling, data persistence, and access to
the Java EE platform APIs (see Java EE 7 APIs).
1.4.2 Container Types
The deployment process installs Java EE application components in the Java EE
containers, as illustrated in Figure 1–5.
Overview 1-9
Web Services Support
Figure 1–5 Java EE Server and Containers
Application Client Container
Client
Machine
Application Client
Web Browser
Servlet
Web Page
Web
Container
Java EE
Server
Enterprise Bean
Enterprise Bean
EJB
Container
Database
The server and containers are as follows:
■
■
■
■
■
Java EE server: The runtime portion of a Java EE product. A Java EE server
provides EJB and web containers.
EJB container: Manages the execution of enterprise beans for Java EE applications.
Enterprise beans and their container run on the Java EE server.
Web container: Manages the execution of web pages, servlets, and some EJB
components for Java EE applications. Web components and their container run on
the Java EE server.
Application client container: Manages the execution of application client
components. Application clients and their container run on the client.
Applet container: Manages the execution of applets. Consists of a web browser
and a Java Plug-in running on the client together.
1.5 Web Services Support
Web services are web-based enterprise applications that use open, XML-based
standards and transport protocols to exchange data with calling clients. The Java EE
platform provides the XML APIs and tools you need to quickly design, develop, test,
and deploy web services and clients that fully interoperate with other web services
and clients running on Java-based or non-Java-based platforms.
To write web services and clients with the Java EE XML APIs, all you need to do is
pass parameter data to the method calls and process the data returned; for
document-oriented web services, you send documents containing the service data
back and forth. No low-level programming is needed because the XML API
1-10 The Java EE 7 Tutorial
Web Services Support
implementations do the work of translating the application data to and from an
XML-based data stream that is sent over the standardized XML-based transport
protocols. These XML-based standards and protocols are introduced in the following
sections.
The translation of data to a standardized XML-based data stream is what makes web
services and clients written with the Java EE XML APIs fully interoperable. This does
not necessarily mean that the data being transported includes XML tags, because the
transported data can itself be plain text, XML data, or any kind of binary data, such as
audio, video, maps, program files, computer-aided design (CAD) documents, and the
like. The next section introduces XML and explains how parties doing business can
use XML tags and schemas to exchange data in a meaningful way.
1.5.1 XML
Extensible Markup Language (XML) is a cross-platform, extensible, text-based
standard for representing data. Parties that exchange XML data can create their own
tags to describe the data, set up schemas to specify which tags can be used in a
particular kind of XML document, and use XML style sheets to manage the display
and handling of the data.
For example, a web service can use XML and a schema to produce price lists, and
companies that receive the price lists and schema can have their own style sheets to
handle the data in a way that best suits their needs. Here are examples.
■
■
■
One company might put XML pricing information through a program to translate
the XML into HTML so that it can post the price lists to its intranet.
A partner company might put the XML pricing information through a tool to
create a marketing presentation.
Another company might read the XML pricing information into an application for
processing.
1.5.2 SOAP Transport Protocol
Client requests and web service responses are transmitted as Simple Object Access
Protocol (SOAP) messages over HTTP to enable a completely interoperable exchange
between clients and web services, all running on different platforms and at various
locations on the Internet. HTTP is a familiar request-and-response standard for
sending messages over the Internet, and SOAP is an XML-based protocol that follows
the HTTP request-and-response model.
The SOAP portion of a transported message does the following:
■
■
■
Defines an XML-based envelope to describe what is in the message and explain
how to process the message
Includes XML-based encoding rules to express instances of application-defined
data types within the message
Defines an XML-based convention for representing the request to the remote
service and the resulting response
1.5.3 WSDL Standard Format
The Web Services Description Language (WSDL) is a standardized XML format for
describing network services. The description includes the name of the service, the
location of the service, and ways to communicate with the service. WSDL service
descriptions can be published on the Web. GlassFish Server provides a tool for
Overview
1-11
Java EE Application Assembly and Deployment
generating the WSDL specification of a web service that uses remote procedure calls to
communicate with clients.
1.6 Java EE Application Assembly and Deployment
A Java EE application is packaged into one or more standard units for deployment to
any Java EE platform-compliant system. Each unit contains
■
■
A functional component or components, such as an enterprise bean, web page,
servlet, or applet
An optional deployment descriptor that describes its content
Once a Java EE unit has been produced, it is ready to be deployed. Deployment
typically involves using a platform's deployment tool to specify location-specific
information, such as a list of local users who can access it and the name of the local
database. Once deployed on a local platform, the application is ready to run.
1.7 Java EE 7 APIs
Figure 1–6 shows the relationships among the Java EE containers.
Figure 1–6 Java EE Containers
Client System
Java EE Server
Browser
Web Container
JavaServer Faces
Servlet
Database
Application Client Container
Application Client
EJB Container
EJB
EJB
Figure 1–7 shows the availability of the Java EE 7 APIs in the web container.
1-12 The Java EE 7 Tutorial
Java EE 7 APIs
Figure 1–7 Java EE APIs in the Web Container
Web Container
WebSocket
Java SE
Concurrency Utilities
Batch
JSON-P
Bean Validation
EJB Lite
EL
JavaMail
Servlet
JSP
Connectors
JavaServer Faces
Java Persistence
JMS
Management
WS Metadata
Web Services
JACC
JASPIC
JAX-RS
JAX-WS
JSTL
JTA
CDI
Dependency Injection
New in Java EE 7
Figure 1–8 shows the availability of the Java EE 7 APIs in the EJB container.
Overview
1-13
Java EE 7 APIs
Figure 1–8 Java EE APIs in the EJB Container
EJB Container
Concurrency Utilities
Java SE
Batch
JSON-P
CDI
Dependency Injection
JavaMail
Java Persistence
JTA
Connectors
JMS
EJB
Management
WS Metadata
Web Services
JACC
JASPIC
Bean Validation
JAX-RS
JAX-WS
New in Java EE 7
Figure 1–9 shows the availability of the Java EE 7 APIs in the application client
container.
1-14 The Java EE 7 Tutorial
Java EE 7 APIs
Figure 1–9 Java EE APIs in the Application Client Container
Application Client Container
Java Persistence
Java SE
Management
WS Metadata
Web Services
Application Client
JSON-P
JMS
JAX-WS
Bean Validation
JavaMail
CDI
Dependency Injection
New in Java EE 7
The following sections give a brief summary of the technologies required by the Java
EE platform and the APIs used in Java EE applications.
1.7.1 Enterprise JavaBeans Technology
An Enterprise JavaBeans (EJB) component, or enterprise bean, is a body of code that
has fields and methods to implement modules of business logic. You can think of an
enterprise bean as a building block that can be used alone or with other enterprise
beans to execute business logic on the Java EE server.
Enterprise beans are either session beans or message-driven beans.
■
■
A session bean represents a transient conversation with a client. When the client
finishes executing, the session bean and its data are gone.
A message-driven bean combines features of a session bean and a message
listener, allowing a business component to receive messages asynchronously.
Commonly, these are Java Message Service (JMS) messages.
In the Java EE 7 platform, new enterprise bean features include the following:
■
Asynchronous local session beans in EJB Lite
■
Nonpersistent timers in EJB Lite
The Java EE 7 platform requires Enterprise JavaBeans 3.2 and Interceptors 1.2. The
Interceptors specification is part of the EJB specification.
1.7.2 Java Servlet Technology
Java Servlet technology lets you define HTTP-specific servlet classes. A servlet class
extends the capabilities of servers that host applications accessed by way of a
request-response programming model. Although servlets can respond to any type of
request, they are commonly used to extend the applications hosted by web servers.
In the Java EE 7 platform, new Java Servlet technology features include the following:
■
Nonblocking I/O
Overview
1-15
Java EE 7 APIs
■
HTTP protocol upgrade
The Java EE 7 platform requires Servlet 3.1.
1.7.3 JavaServer Faces Technology
JavaServer Faces technology is a user interface framework for building web
applications. The main components of JavaServer Faces technology are as follows:
■
■
■
A GUI component framework.
A flexible model for rendering components in different kinds of HTML or different
markup languages and technologies. A Renderer object generates the markup to
render the component and converts the data stored in a model object to types that
can be represented in a view.
A standard RenderKit for generating HTML 4.01 markup.
The following features support the GUI components:
■
Input validation
■
Event handling
■
Data conversion between model objects and components
■
Managed model object creation
■
Page navigation configuration
■
Expression Language (EL)
All this functionality is available using standard Java APIs and XML-based
configuration files.
In the Java EE 7 platform, new features of JavaServer Faces technology include the
following:
■
HTML5-friendly markup
■
Faces Flows
■
Resource library contracts
The Java EE 7 platform requires JavaServer Faces 2.2 and Expression Language 3.0.
1.7.4 JavaServer Pages Technology
JavaServer Pages (JSP) technology lets you put snippets of servlet code directly into a
text-based document. A JSP page is a text-based document that contains two types of
text:
■
■
Static data, which can be expressed in any text-based format, such as HTML or
XML
JSP elements, which determine how the page constructs dynamic content
For information about JSP technology, see the The Java EE 5 Tutorial at
http://docs.oracle.com/javaee/5/tutorial/doc/.
The Java EE 7 platform requires JavaServer Pages 2.3 for compatibility with earlier
releases but recommends the use of Facelets as the display technology in new
applications.
1-16 The Java EE 7 Tutorial
Java EE 7 APIs
1.7.5 JavaServer Pages Standard Tag Library
The JavaServer Pages Standard Tag Library (JSTL) encapsulates core functionality
common to many JSP applications. Instead of mixing tags from numerous vendors in
your JSP applications, you use a single, standard set of tags. This standardization
allows you to deploy your applications on any JSP container that supports JSTL and
makes it more likely that the implementation of the tags is optimized.
JSTL has iterator and conditional tags for handling flow control, tags for manipulating
XML documents, internationalization tags, tags for accessing databases using SQL,
and tags for commonly used functions.
The Java EE 7 platform requires JSTL 1.2.
1.7.6 Java Persistence API
The Java Persistence API (JPA) is a Java standards–based solution for persistence.
Persistence uses an object/relational mapping approach to bridge the gap between an
object-oriented model and a relational database. The Java Persistence API can also be
used in Java SE applications outside of the Java EE environment. Java Persistence
consists of the following areas:
■
The Java Persistence API
■
The query language
■
Object/relational mapping metadata
The Java EE 7 platform requires Java Persistence API 2.1.
1.7.7 Java Transaction API
The Java Transaction API (JTA) provides a standard interface for demarcating
transactions. The Java EE architecture provides a default auto commit to handle
transaction commits and rollbacks. An auto commit means that any other applications
that are viewing data will see the updated data after each database read or write
operation. However, if your application performs two separate database access
operations that depend on each other, you will want to use the JTA API to demarcate
where the entire transaction, including both operations, begins, rolls back, and
commits.
The Java EE 7 platform requires Java Transaction API 1.2.
1.7.8 Java API for RESTful Web Services
The Java API for RESTful Web Services (JAX-RS) defines APIs for the development of
web services built according to the Representational State Transfer (REST) architectural
style. A JAX-RS application is a web application that consists of classes packaged as a
servlet in a WAR file along with required libraries.
The Java EE 7 platform requires JAX-RS 2.0.
1.7.9 Managed Beans
Managed Beans, lightweight container-managed objects (POJOs) with minimal
requirements, support a small set of basic services, such as resource injection, lifecycle
callbacks, and interceptors. Managed Beans represent a generalization of the managed
beans specified by JavaServer Faces technology and can be used anywhere in a Java EE
application, not just in web modules.
Overview
1-17
Java EE 7 APIs
The Managed Beans specification is part of the Java EE 7 platform specification (JSR
342). The Java EE 7 platform requires Managed Beans 1.0.
1.7.10 Contexts and Dependency Injection for Java EE
Contexts and Dependency Injection for Java EE (CDI) defines a set of contextual
services, provided by Java EE containers, that make it easy for developers to use
enterprise beans along with JavaServer Faces technology in web applications.
Designed for use with stateful objects, CDI also has many broader uses, allowing
developers a great deal of flexibility to integrate different kinds of components in a
loosely coupled but typesafe way.
The Java EE 7 platform requires CDI 1.1.
1.7.11 Dependency Injection for Java
Dependency Injection for Java defines a standard set of annotations (and one interface)
for use on injectable classes.
In the Java EE platform, CDI provides support for Dependency Injection. Specifically,
you can use injection points only in a CDI-enabled application.
The Java EE 7 platform requires Dependency Injection for Java 1.0.
1.7.12 Bean Validation
The Bean Validation specification defines a metadata model and API for validating
data in JavaBeans components. Instead of distributing validation of data over several
layers, such as the browser and the server side, you can define the validation
constraints in one place and share them across the different layers.
The Java EE 7 platform requires Bean Validation 1.1.
1.7.13 Java Message Service API
The Java Message Service (JMS) API is a messaging standard that allows Java EE
application components to create, send, receive, and read messages. It enables
distributed communication that is loosely coupled, reliable, and asynchronous.
In the platform, new features of JMS include the following.
■
■
A new, simplified API offers a simpler alternative to the previous API. This API
includes a JMSContext object that combines the functions of a Connection and a
Session.
All objects with a close method implement the java.lang.Autocloseable
interface so that they can be used in a Java SE 7 try-with-resources statement.
The Java EE 7 platform requires JMS 2.0.
1.7.14 Java EE Connector Architecture
The Java EE Connector Architecture is used by tools vendors and system integrators to
create resource adapters that support access to enterprise information systems that can
be plugged in to any Java EE product. A resource adapter is a software component
that allows Java EE application components to access and interact with the underlying
resource manager of the EIS. Because a resource adapter is specific to its resource
manager, a different resource adapter typically exists for each type of database or
enterprise information system.
1-18 The Java EE 7 Tutorial
Java EE 7 APIs
The Java EE Connector Architecture also provides a performance-oriented, secure,
scalable, and message-based transactional integration of Java EE platform–based web
services with existing EISs that can be either synchronous or asynchronous. Existing
applications and EISs integrated through the Java EE Connector Architecture into the
Java EE platform can be exposed as XML-based web services by using JAX-WS and
Java EE component models. Thus JAX-WS and the Java EE Connector Architecture are
complementary technologies for enterprise application integration (EAI) and
end-to-end business integration.
The Java EE 7 platform requires Java EE Connector Architecture 1.7.
1.7.15 JavaMail API
Java EE applications use the JavaMail API to send email notifications. The JavaMail
API has two parts:
■
An application-level interface used by the application components to send mail
■
A service provider interface
The Java EE platform includes the JavaMail API with a service provider that allows
application components to send Internet mail.
The Java EE 7 platform requires JavaMail 1.5.
1.7.16 Java Authorization Contract for Containers
The Java Authorization Contract for Containers (JACC) specification defines a contract
between a Java EE application server and an authorization policy provider. All Java EE
containers support this contract.
The JACC specification defines java.security.Permission classes that satisfy the
Java EE authorization model. The specification defines the binding of container-access
decisions to operations on instances of these permission classes. It defines the
semantics of policy providers that use the new permission classes to address the
authorization requirements of the Java EE platform, including the definition and use of
roles.
The Java EE 7 platform requires JACC 1.5.
1.7.17 Java Authentication Service Provider Interface for Containers
The Java Authentication Service Provider Interface for Containers (JASPIC)
specification defines a service provider interface (SPI) by which authentication
providers that implement message authentication mechanisms may be integrated in
client or server message-processing containers or runtimes. Authentication providers
integrated through this interface operate on network messages provided to them by
their calling containers. The authentication providers transform outgoing messages so
that the source of each message can be authenticated by the receiving container, and
the recipient of the message can be authenticated by the message sender.
Authentication providers authenticate each incoming message and return to their
calling containers the identity established as a result of the message authentication.
The Java EE 7 platform requires JASPIC 1.1.
1.7.18 Java API for WebSocket
WebSocket is an application protocol that provides full-duplex communications
between two peers over TCP. The Java API for WebSocket enables Java EE applications
Overview
1-19
Java EE 7 APIs in the Java Platform, Standard Edition 7
to create endpoints using annotations that specify the configuration parameters of the
endpoint and designate its lifecycle callback methods.
The WebSocket API is new to the Java EE 7 platform. The Java EE 7 platform requires
Java API for WebSocket 1.0.
1.7.19 Java API for JSON Processing
JSON is a text-based data exchange format derived from JavaScript that is used in web
services and other connected applications. The Java API for JSON Processing (JSON-P)
enables Java EE applications to parse, transform, and query JSON data using the object
model or the streaming model.
JSON-P is new to the Java EE 7 platform. The Java EE 7 platform requires JSON-P 1.0.
1.7.20 Concurrency Utilities for Java EE
Concurrency Utilities for Java EE is a standard API for providing asynchronous
capabilities to Java EE application components through the following types of objects:
managed executor service, managed scheduled executor service, managed thread
factory, and context service.
Concurrency Utilities for Java EE is new to the Java EE 7 platform. The Java EE 7
platform requires Concurrency Utilities for Java EE 1.0.
1.7.21 Batch Applications for the Java Platform
Batch jobs are tasks that can be executed without user interaction. The Batch
Applications for the Java Platform specification is a batch framework that provides
support for creating and running batch jobs in Java applications. The batch framework
consists of a batch runtime, a job specification language based on XML, a Java API to
interact with the batch runtime, and a Java API to implement batch artifacts.
Batch Applications for the Java Platform is new to the Java EE 7 platform. The Java EE
7 platform requires Batch Applications for the Java Platform 1.0.
1.8 Java EE 7 APIs in the Java Platform, Standard Edition 7
Several APIs that are required by the Java EE 7 platform are included in the Java
Platform, Standard Edition 7 (Java SE 7) and are thus available to Java EE applications.
1.8.1 Java Database Connectivity API
The Java Database Connectivity (JDBC) API lets you invoke SQL commands from Java
programming language methods. You use the JDBC API in an enterprise bean when
you have a session bean access the database. You can also use the JDBC API from a
servlet or a JSP page to access the database directly without going through an
enterprise bean.
The JDBC API has two parts:
■
■
An application-level interface used by the application components to access a
database
A service provider interface to attach a JDBC driver to the Java EE platform
The Java SE 7 platform requires JDBC 4.1.
1-20 The Java EE 7 Tutorial
Java EE 7 APIs in the Java Platform, Standard Edition 7
1.8.2 Java Naming and Directory Interface API
The Java Naming and Directory Interface (JNDI) API provides naming and directory
functionality, enabling applications to access multiple naming and directory services,
such as LDAP, DNS, and NIS. The JNDI API provides applications with methods for
performing standard directory operations, such as associating attributes with objects
and searching for objects using their attributes. Using JNDI, a Java EE application can
store and retrieve any type of named Java object, allowing Java EE applications to
coexist with many legacy applications and systems.
Java EE naming services provide application clients, enterprise beans, and web
components with access to a JNDI naming environment. A naming environment
allows a component to be customized without the need to access or change the
component's source code. A container implements the component's environment and
provides it to the component as a JNDI naming context.
The naming environment provides four logical namespaces: java:comp, java:module,
java:app, and java:global for objects available to components, modules, or
applications or shared by all deployed applications. A Java EE component can access
named system-provided and user-defined objects. The names of some
system-provided objects, such as a default JDBC DataSource object, a default JMS
connection factory, and a JTA UserTransaction object, are stored in the java:comp
namespace. The Java EE platform allows a component to name user-defined objects,
such as enterprise beans, environment entries, JDBC DataSource objects, and
messaging destinations.
A Java EE component can also locate its environment naming context by using JNDI
interfaces. A component can create a javax.naming.InitialContext object and look
up the environment naming context in InitialContext under the name
java:comp/env. A component's naming environment is stored directly in the
environment naming context or in any of its direct or indirect subcontexts.
1.8.3 JavaBeans Activation Framework
The JavaBeans Activation Framework (JAF) is used by the JavaMail API. JAF provides
standard services to determine the type of an arbitrary piece of data, encapsulate
access to it, discover the operations available on it, and create the appropriate
JavaBeans component to perform those operations.
1.8.4 Java API for XML Processing
The Java API for XML Processing (JAXP), part of the Java SE platform, supports the
processing of XML documents using Document Object Model (DOM), Simple API for
XML (SAX), and Extensible Stylesheet Language Transformations (XSLT). JAXP
enables applications to parse and transform XML documents independently of a
particular XML-processing implementation.
JAXP also provides namespace support, which lets you work with schemas that might
otherwise have naming conflicts. Designed to be flexible, JAXP lets you use any
XML-compliant parser or XSL processor from within your application and supports
the Worldwide Web Consortium (W3C) schema. You can find information on the W3C
schema at http://www.w3.org/XML/Schema.
1.8.5 Java Architecture for XML Binding
The Java Architecture for XML Binding (JAXB) provides a convenient way to bind an
XML schema to a representation in Java language programs. JAXB can be used
independently or in combination with JAX-WS, in which case it provides a standard
Overview
1-21
GlassFish Server Tools
data binding for web service messages. All Java EE application client containers, web
containers, and EJB containers support the JAXB API.
The Java EE 7 platform requires JAXB 2.2.
1.8.6 Java API for XML Web Services
The Java API for XML Web Services (JAX-WS) specification provides support for web
services that use the JAXB API for binding XML data to Java objects. The JAX-WS
specification defines client APIs for accessing web services as well as techniques for
implementing web service endpoints. The Implementing Enterprise Web Services
specification describes the deployment of JAX-WS-based services and clients. The EJB
and Java Servlet specifications also describe aspects of such deployment.
JAX-WS-based applications can be deployed using any of these deployment models.
The JAX-WS specification describes the support for message handlers that can process
message requests and responses. In general, these message handlers execute in the
same container and with the same privileges and execution context as the JAX-WS
client or endpoint component with which they are associated. These message handlers
have access to the same JNDI namespace as their associated component. Custom
serializers and deserializers, if supported, are treated in the same way as message
handlers.
The Java EE 7 platform requires JAX-WS 2.2.
1.8.7 SOAP with Attachments API for Java
The SOAP with Attachments API for Java (SAAJ) is a low-level API on which JAX-WS
depends. SAAJ enables the production and consumption of messages that conform to
the SOAP 1.1 and 1.2 specifications and the SOAP with Attachments note. Most
developers do not use the SAAJ API, instead using the higher-level JAX-WS API.
1.8.8 Java Authentication and Authorization Service
The Java Authentication and Authorization Service (JAAS) provides a way for a Java
EE application to authenticate and authorize a specific user or group of users to run it.
JAAS is a Java programming language version of the standard Pluggable
Authentication Module (PAM) framework, which extends the Java platform security
architecture to support user-based authorization.
1.8.9 Common Annotations for the Java Platform
Annotations enable a declarative style of programming in the Java platform.
The Java EE 7 platform requires Common Annotations for the Java Platform 1.2.
1.9 GlassFish Server Tools
GlassFish Server is a compliant implementation of the Java EE 7 platform. In addition
to supporting all the APIs described in the previous sections, GlassFish Server
includes a number of Java EE tools that are not part of the Java EE 7 platform but are
provided as a convenience to the developer.
This section briefly summarizes the tools that make up GlassFish Server. Instructions
for starting and stopping GlassFish Server, starting the Administration Console, and
starting and stopping the Java DB server are in Chapter 2, "Using the Tutorial
Examples".
1-22 The Java EE 7 Tutorial
GlassFish Server Tools
GlassFish Server contains the tools listed in Table 1–1. Basic usage information for
many of the tools appears throughout the tutorial. For detailed information, see the
online help in the GUI tools.
Table 1–1
GlassFish Server Tools
Tool
Description
Administration Console A web-based GUI GlassFish Server administration utility. Used to
stop GlassFish Server and to manage users, resources, and
applications.
asadmin
A command-line GlassFish Server administration utility. Used to
start and stop GlassFish Server and to manage users, resources, and
applications.
appclient
A command-line tool that launches the application client container
and invokes the client application packaged in the application client
JAR file.
capture-schema
A command-line tool to extract schema information from a database,
producing a schema file that GlassFish Server can use for
container-managed persistence.
package-appclient
A command-line tool to package the application client container
libraries and JAR files.
Java DB database
A copy of the Java DB server.
xjc
A command-line tool to transform, or bind, a source XML schema to
a set of JAXB content classes in the Java programming language.
schemagen
A command-line tool to create a schema file for each namespace
referenced in your Java classes.
wsimport
A command-line tool to generate JAX-WS portable artifacts for a
given WSDL file. After generation, these artifacts can be packaged in
a WAR file with the WSDL and schema documents, along with the
endpoint implementation, and then deployed.
wsgen
A command-line tool to read a web service endpoint class and
generate all the required JAX-WS portable artifacts for web service
deployment and invocation.
Overview
1-23
GlassFish Server Tools
1-24 The Java EE 7 Tutorial
2
Using the Tutorial Examples
2
This chapter tells you everything you need to know to install, build, and run the
examples.
The following topics are addressed here:
■
Required Software
■
Starting and Stopping GlassFish Server
■
Starting the Administration Console
■
Starting and Stopping the Java DB Server
■
Building the Examples
■
Tutorial Example Directory Structure
■
Java EE 7 Maven Archetypes in the Tutorial
■
Getting the Latest Updates to the Tutorial
■
Debugging Java EE Applications
2.1 Required Software
The following software is required to run the examples:
■
Java Platform, Standard Edition
■
Java EE 7 Software Development Kit
■
Java EE 7 Tutorial Component
■
NetBeans IDE
■
Apache Maven
2.1.1 Java Platform, Standard Edition
To build, deploy, and run the examples, you need a copy of the Java Platform,
Standard Edition Development Kit (JDK). You must use JDK 7 Update 65 or above or
JDK 8 Update 20 or above. You can download JDK software from
http://www.oracle.com/technetwork/java/javase/downloads/index.ht
ml.
2.1.2 Java EE 7 Software Development Kit
GlassFish Server Open Source Edition 4.1 is targeted as the build and runtime
environment for the tutorial examples. To build, deploy, and run the examples, you
Using the Tutorial Examples
2-1
Required Software
need a copy of GlassFish Server and, optionally, NetBeans IDE. To obtain GlassFish
Server, you must install the Java EE 7 Software Development Kit (SDK) Update 1,
which you can download from
http://www.oracle.com/technetwork/java/javaee/downloads/index.ht
ml. Make sure that you download the Java EE 7 SDK Update 1, not the Java EE 7 Web
Profile SDK Update 1.
2.1.2.1 SDK Installation Tips
The Java EE 7 SDK Update 1 is installed from a ZIP file. It sets the default
administration user name as admin with no required password. The Admin Port is set
to 4848, and the HTTP Port is set to 8080.
This tutorial refers to as-install-parent, the directory where you install GlassFish Server.
For example, the default installation directory on Microsoft Windows is
C:\glassfish4, so as-install-parent is C:\glassfish4. GlassFish Server itself is installed
in as-install, the glassfish directory under as-install-parent. So on Microsoft Windows,
as-install is C:\glassfish4\glassfish.
After you install GlassFish Server, add the following directories to your PATH to avoid
having to specify the full path when you use commands:
as-install-parent/bin
as-install/bin
2.1.3 Java EE 7 Tutorial Component
The tutorial component, including the documentation and example source, is
contained in the Java EE 7 SDK Update 1.
Updates to the Java EE 7 Tutorial are published periodically. For details on obtaining
these updates, see Getting the Latest Updates to the Tutorial.
2.1.4 NetBeans IDE
The NetBeans integrated development environment (IDE) is a free, open-source IDE
for developing Java applications, including enterprise applications. NetBeans IDE
supports the Java EE platform. You can build, package, deploy, and run the tutorial
examples from within NetBeans IDE.
To run the tutorial examples, you need the latest version of NetBeans IDE. You can
download NetBeans IDE from
https://www.netbeans.org/downloads/index.html. Make sure that you
download the Java EE bundle.
2.1.4.1 To Install NetBeans IDE without GlassFish Server
When you install NetBeans IDE, do not install the version of GlassFish Server that
comes with NetBeans IDE. To skip the installation of GlassFish Server, follow these
steps.
1.
On the first page of the NetBeans IDE Installer wizard, deselect the check box for
GlassFish Server and click OK.
2.
Accept both the License Agreement and the Junit License Agreement.
A few of the tutorial examples use the Junit library, so you should install it.
3.
Continue with the installation of NetBeans IDE.
2-2 The Java EE 7 Tutorial
Starting and Stopping GlassFish Server
2.1.4.2 To Add GlassFish Server as a Server Using NetBeans IDE
To run the tutorial examples in NetBeans IDE, you must add your GlassFish Server as
a server in NetBeans IDE. Follow these instructions to add GlassFish Server to
NetBeans IDE.
1.
From the Tools menu, choose Servers.
2.
In the Servers wizard, click Add Server.
3.
Under Choose Server, select GlassFish Server and click Next.
4.
Under Server Location, browse to the location of the Java EE 7 SDK and click
Next.
5.
Under Domain Location, select Register Local Domain.
6.
Click Finish.
2.1.5 Apache Maven
Maven is a Java technology–based build tool developed by the Apache Software
Foundation and is used to build, package, and deploy the tutorial examples. To run the
tutorial examples from the command line, you need Maven 3.0 or higher. If you do not
already have Maven, you can install it from:
http://maven.apache.org
Be sure to add the maven-install/bin directory to your path.
If you are using NetBeans IDE to build and run the examples, it includes a copy of
Maven.
2.2 Starting and Stopping GlassFish Server
You can start and stop GlassFish Server using either NetBeans IDE or the command
line.
2.2.1 To Start GlassFish Server Using NetBeans IDE
1.
Click the Services tab.
2.
Expand Servers.
3.
Right-click the GlassFish Server instance and select Start.
2.2.2 To Stop GlassFish Server Using NetBeans IDE
To stop GlassFish Server using NetBeans IDE, right-click the GlassFish Server instance
and select Stop.
2.2.3 To Start GlassFish Server Using the Command Line
To start GlassFish Server from the command line, open a terminal window or
command prompt and execute the following:
asadmin start-domain --verbose
A domain is a set of one or more GlassFish Server instances managed by one
administration server. The following elements are associated with a domain:
■
The GlassFish Server port number: The default is 8080.
Using the Tutorial Examples
2-3
Starting the Administration Console
■
■
The administration server's port number: The default is 4848.
An administration user name and password: The default user name is admin, and
by default no password is required.
You specify these values when you install GlassFish Server. The examples in this
tutorial assume that you chose the default ports as well as the default user name and
lack of password.
With no arguments, the start-domain command initiates the default domain, which is
domain1. The --verbose flag causes all logging and debugging output to appear on the
terminal window or command prompt. The output also goes into the server log, which
is located in domain-dir/logs/server.log.
2.2.4 To Stop GlassFish Server Using the Command Line
To stop GlassFish Server, open a terminal window or command prompt and execute:
asadmin stop-domain domain1
2.3 Starting the Administration Console
To administer GlassFish Server and manage users, resources, and Java EE applications,
use the Administration Console tool. GlassFish Server must be running before you
invoke the Administration Console. To start the Administration Console, open a
browser at http://localhost:4848/.
2.3.1 To Start the Administration Console Using NetBeans IDE
1.
Click the Services tab.
2.
Expand Servers.
3.
Right-click the GlassFish Server instance and select View Domain Admin
Console.
NetBeans IDE uses your default web browser to open the
Administration Console.
Note:
2.4 Starting and Stopping the Java DB Server
GlassFish Server includes the Java DB database server.
To start the Java DB server from the command line, open a terminal window or
command prompt and execute:
asadmin start-database
To stop the Java DB server from the command line, open a terminal window or
command prompt and execute:
asadmin stop-database
For information about the Java DB included with GlassFish Server, see
http://www.oracle.com/technetwork/java/javadb/overview/index.htm
l.
2-4 The Java EE 7 Tutorial
Tutorial Example Directory Structure
2.4.1 To Start the Database Server Using NetBeans IDE
When you start GlassFish Server using NetBeans IDE, the database server starts
automatically. If you ever need to start the server manually, however, follow these
steps.
1.
Click the Services tab.
2.
Expand Databases.
3.
Right-click Java DB and select Start Server.
Next Steps
To stop the database using NetBeans IDE, right-click Java DB and select Stop Server.
2.5 Building the Examples
The tutorial examples are distributed with a configuration file for either NetBeans IDE
or Maven. Either NetBeans IDE or Maven may be used to build, package, deploy, and
run the examples. Directions for building the examples are provided in each chapter.
2.6 Tutorial Example Directory Structure
To facilitate iterative development and keep application source files separate from
compiled files, the tutorial examples use the Maven application directory structure.
Each application module has the following structure:
■
pom.xml: Maven build file
■
src/main/java: Java source files for the module
■
■
■
src/main/resources: configuration files for the module, with the exception of web
applications
src/main/webapp: web pages, style sheets, tag files, and images (web applications
only)
src/main/webapp/WEB-INF: configuration files for web applications (web
applications only)
When an example has multiple application modules packaged into an EAR file, its
submodule directories use the following naming conventions:
■
example-name-app-client: application clients
■
example-name-ejb: enterprise bean JAR files
■
example-name-war: web applications
■
example-name-ear: enterprise applications
■
example-name-common: library JAR containing components, classes, and files used
by other modules
The Maven build files (pom.xml) distributed with the examples contain goals to
compile and assemble the application into the target directory and deploy the archive
to GlassFish Server.
Using the Tutorial Examples
2-5
Java EE 7 Maven Archetypes in the Tutorial
2.7 Java EE 7 Maven Archetypes in the Tutorial
Some of the chapters have instructions on how to build an example application using
Maven archetypes. Archetypes are templates for generating a particular Maven
project. The Tutorial includes several Maven archetypes for generating Java EE 7
projects.
2.7.1 Installing the Tutorial Archetypes
You must install the included Maven archetypes into your local Maven repository
before you can create new projects based on the archetypes. You can install the
archetypes using NetBeans IDE or Maven.
2.7.1.1 Installing the Tutorial Archetypes Using NetBeans IDE
1.
From the File menu, choose Open Project.
2.
In the Open Project dialog box, navigate to:
tut-install/examples
3.
Select the archetypes folder.
4.
Click Open Project.
5.
In the Projects tab, right-click the archetypes project and select Build.
2.7.1.2 Installing the Tutorial Archetypes Using Maven
1.
In a terminal window, go to:
tut-install/examples/archetypes/
2.
Enter the following command:
mvn install
2.8 Getting the Latest Updates to the Tutorial
Check for any updates to the tutorial by using the Update Tool included with the Java
EE 7 SDK.
2.8.1 To Update the Tutorial Using NetBeans IDE
1.
Open the Services tab in NetBeans IDE and expand Servers.
2.
Right-click the GlassFish Server instance and select View Domain Update Center
to display the Update Tool.
3.
Select Available Updates in the tree to display a list of updated packages.
4.
Look for updates to the Java EE 7 Tutorial (javaee-tutorial) package.
5.
If there is an updated version of the Tutorial, select Java EE 7 Tutorial
(javaee-tutorial) and click Install.
2.8.2 To Update the Tutorial Using the Command Line
1.
Open a terminal window and enter the following command to display the Update
Tool:
updatetool
2-6 The Java EE 7 Tutorial
Debugging Java EE Applications
2.
Select Available Updates in the tree to display a list of updated packages.
3.
Look for updates to the Java EE 7 Tutorial (javaee-tutorial) package.
4.
If there is an updated version of the Tutorial, select Java EE 7 Tutorial
(javaee-tutorial) and click Install.
2.9 Debugging Java EE Applications
This section explains how to determine what is causing an error in your application
deployment or execution.
2.9.1 Using the Server Log
One way to debug applications is to look at the server log in
domain-dir/logs/server.log. The log contains output from GlassFish Server and your
applications. You can log messages from any Java class in your application with
System.out.println and the Java Logging APIs (documented at
http://docs.oracle.com/javase/7/docs/technotes/guides/logging/in
dex.html) and from web components with the ServletContext.log method.
If you use NetBeans IDE, logging output appears in the Output window as well as the
server log.
If you start GlassFish Server with the --verbose flag, all logging and debugging
output will appear on the terminal window or command prompt and the server log. If
you start GlassFish Server in the background, debugging information is available only
in the log. You can view the server log with a text editor or with the Administration
Console log viewer.
2.9.1.1 To Use the Administration Console Log Viewer
1.
Select the GlassFish Server node.
2.
Click View Log Files.
The log viewer opens and displays the last 40 entries.
3.
To display other entries, follow these steps.
a.
Click Modify Search.
b.
Specify any constraints on the entries you want to see.
c.
Click Search at the top of the log viewer.
2.9.2 Using a Debugger
GlassFish Server supports the Java Platform Debugger Architecture (JPDA). With
JPDA, you can configure GlassFish Server to communicate debugging information
using a socket.
2.9.2.1 To Debug an Application Using a Debugger
1.
Follow these steps to enable debugging in GlassFish Server using the
Administration Console:
a.
Expand the Configurations node, then expand the server-config node.
b.
Select the JVM Settings node. The default debug options are set to:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9009
Using the Tutorial Examples
2-7
Debugging Java EE Applications
As you can see, the default debugger socket port is 9009. You can change it to a
port not in use by GlassFish Server or another service.
2.
c.
Select the Debug Enabled check box.
d.
Click Save.
Stop GlassFish Server and then restart it.
2-8 The Java EE 7 Tutorial
Part II
Part II
Platform Basics
Part II introduces platform basics. This part contains the following chapters:
■
Chapter 3, "Resource Creation"
■
Chapter 4, "Injection"
■
Chapter 5, "Packaging"
3
Resource Creation
3
A resource is a program object that provides connections to such systems as database
servers and messaging systems. Java EE components can access a wide variety of
resources, including databases, mail sessions, Java Message Service objects, and URLs.
The Java EE 7 platform provides mechanisms that allow you to access all these
resources in a similar manner. This chapter examines several types of resources and
explains how to create them.
The following topics are addressed here:
■
Resources and JNDI Naming
■
DataSource Objects and Connection Pools
■
Creating Resources Administratively
3.1 Resources and JNDI Naming
In a distributed application, components need to access other components and
resources, such as databases. For example, a servlet might invoke remote methods on
an enterprise bean that retrieves information from a database. In the Java EE platform,
the Java Naming and Directory Interface (JNDI) naming service enables components
to locate other components and resources.
A resource is a program object that provides connections to systems, such as database
servers and messaging systems. (A Java Database Connectivity resource is sometimes
referred to as a data source.) Each resource object is identified by a unique,
people-friendly name, called the JNDI name. For example, the JNDI name of the
preconfigured JDBC resource for the Java DB database that is shipped with GlassFish
Server is java:comp/DefaultDataSource.
An administrator creates resources in a JNDI namespace. In GlassFish Server, you can
use either the Administration Console or the asadmin command to create resources.
Applications then use annotations to inject the resources. If an application uses
resource injection, GlassFish Server invokes the JNDI API, and the application is not
required to do so. However, it is also possible for an application to locate resources by
making direct calls to the JNDI API.
A resource object and its JNDI name are bound together by the naming and directory
service. To create a new resource, a new name/object binding is entered into the JNDI
namespace. You inject resources by using the @Resource annotation in an application.
You can use a deployment descriptor to override the resource mapping that you
specify in an annotation. Using a deployment descriptor allows you to change an
application by repackaging it rather than by both recompiling the source files and
repackaging. However, for most applications a deployment descriptor is not necessary.
Resource Creation 3-1
DataSource Objects and Connection Pools
3.2 DataSource Objects and Connection Pools
To store, organize, and retrieve data, most applications use a relational database. Java
EE 7 components may access relational databases through the JDBC API. For
information on this API, see
http://docs.oracle.com/javase/7/docs/technotes/guides/jdbc/.
In the JDBC API, databases are accessed by using DataSource objects. A DataSource
has a set of properties that identify and describe the real-world data source that it
represents. These properties include such information as the location of the database
server, the name of the database, the network protocol to use to communicate with the
server, and so on. In GlassFish Server, a data source is called a JDBC resource.
Applications access a data source by using a connection, and a DataSource object can
be thought of as a factory for connections to the particular data source that the
DataSource instance represents. In a basic DataSource implementation, a call to the
getConnection method returns a connection object that is a physical connection to the
data source.
A DataSource object may be registered with a JNDI naming service. If so, an
application can use the JNDI API to access that DataSource object, which can then be
used to connect to the data source it represents.
DataSource objects that implement connection pooling also produce a connection to
the particular data source that the DataSource class represents. The connection object
that the getConnection method returns is a handle to a PooledConnection object
rather than a physical connection. An application uses the connection object in the
same way that it uses a connection. Connection pooling has no effect on application
code except that a pooled connection, like all connections, should always be explicitly
closed. When an application closes a connection that is pooled, the connection is
returned to a pool of reusable connections. The next time getConnection is called, a
handle to one of these pooled connections will be returned if one is available. Because
connection pooling avoids creating a new physical connection every time one is
requested, applications can run significantly faster.
A JDBC connection pool is a group of reusable connections for a particular database.
Because creating each new physical connection is time consuming, the server
maintains a pool of available connections to increase performance. When it requests a
connection, an application obtains one from the pool. When an application closes a
connection, the connection is returned to the pool.
Applications that use the Persistence API specify the DataSource object they are using
in the jta-data-source element of the persistence.xml file:
<jta-data-source>jdbc/MyOrderDB</jta-data-source>
This is typically the only reference to a JDBC object for a persistence unit. The
application code does not refer to any JDBC objects.
3.3 Creating Resources Administratively
Before you deploy or run many applications, you may need to create resources for
them. An application can include a glassfish-resources.xml file that can be used to
define resources for that application and others. You can then use the asadmin
command, specifying as the argument a file named glassfish-resources.xml, to
create the resources administratively, as shown.
asadmin add-resources glassfish-resources.xml
3-2 The Java EE 7 Tutorial
Creating Resources Administratively
The glassfish-resources.xml file can be created in any project using NetBeans IDE
or by hand. Some of the JMS examples use this approach to resource creation. A file for
creating the resources needed for the JMS simple producer example can be found in
the jms/simple/producer/src/main/setup directory.
You could also use the asadmin create-jms-resource command to create the
resources for this example. When you are done using the resources, you would use the
asadmin list-jms-resources command to display their names, and the asadmin
delete-jms-resource command to remove them, regardless of the way you created
the resources.
Resource Creation 3-3
Creating Resources Administratively
3-4 The Java EE 7 Tutorial
4
Injection
4
This chapter provides an overview of injection in Java EE and describes the two
injection mechanisms provided by the platform: resource injection and dependency
injection.
Java EE provides injection mechanisms that enable your objects to obtain references to
resources and other dependencies without having to instantiate them directly. You
declare the required resources and other dependencies in your classes by decorating
fields or methods with one of the annotations that mark the field as an injection point.
The container then provides the required instances at runtime. Injection simplifies
your code and decouples it from the implementations of its dependencies.
The following topics are addressed here:
■
Resource Injection
■
Dependency Injection
■
The Main Differences between Resource Injection and Dependency Injection
4.1 Resource Injection
Resource injection enables you to inject any resource available in the JNDI namespace
into any container-managed object, such as a servlet, an enterprise bean, or a managed
bean. For example, you can use resource injection to inject data sources, connectors, or
custom resources available in the JNDI namespace.
The type you use for the reference to the injected instance is usually an interface,
which decouples your code from the implementation of the resource.
For example, the following code injects a data source object that provides connections
to the default Java DB database shipped with GlassFish Server:
public class MyServlet extends HttpServlet {
@Resource(name="java:comp/DefaultDataSource")
private javax.sql.DataSource dsc;
...
}
In addition to field-based injection as in the preceding example, you can inject
resources using method-based injection:
public class MyServlet extends HttpServlet {
private javax.sql.DataSource dsc;
...
@Resource(name="java:comp/DefaultDataSource")
public void setDsc(java.sql.DataSource ds) {
dsc = ds;
Injection 4-1
Dependency Injection
}
}
To use method-based injection, the setter method must follow the JavaBeans
conventions for property names: The method name must begin with set, have a void
return type, and have only one parameter.
The @Resource annotation is in the javax.annotation package and is defined in JSR
250 (Common Annotations for the Java Platform). Resource injection resolves by name,
so it is not typesafe: the type of the resource object is not known at compile time, so
you can get runtime errors if the types of the object and its reference do not match.
4.2 Dependency Injection
Dependency injection enables you to turn regular Java classes into managed objects
and to inject them into any other managed object. Using dependency injection, your
code can declare dependencies on any managed object. The container automatically
provides instances of these dependencies at the injection points at runtime, and it also
manages the lifecycle of these instances for you.
Dependency injection in Java EE defines scopes, which determine the lifecycle of the
objects that the container instantiates and injects. For example, a managed object that
is only needed to respond to a single client request (such as a currency converter) has a
different scope than a managed object that is needed to process multiple client
requests within a session (such as a shopping cart).
You can define managed objects (also called managed beans) that you can later inject
by assigning a scope to a regular class:
@javax.enterprise.context.RequestScoped
public class CurrencyConverter { ... }
Use the javax.inject.Inject annotation to inject managed beans; for example:
public class MyServlet extends HttpServlet {
@Inject CurrencyConverter cc;
...
}
As opposed to resource injection, dependency injection is typesafe because it resolves
by type. To decouple your code from the implementation of the managed bean, you
can reference the injected instances using an interface type and have your managed
bean implement that interface.
For more information about dependency injection, see Chapter 23, "Introduction to
Contexts and Dependency Injection for Java EE" and JSR 299 (Contexts and
Dependency Injection for the Java EE Platform).
4.3 The Main Differences between Resource Injection and Dependency
Injection
Table 4–1 lists the main differences between resource injection and dependency
injection.
4-2 The Java EE 7 Tutorial
The Main Differences between Resource Injection and Dependency Injection
Table 4–1
Differences between Resource Injection and Dependency Injection
Injection Mechanism
Can Inject JNDI
Resources Directly
Can Inject Regular
Classes Directly
Resolves By
Typesafe
Resource Injection
Yes
No
Resource name
No
Dependency Injection
No
Yes
Type
Yes
Injection 4-3
The Main Differences between Resource Injection and Dependency Injection
4-4 The Java EE 7 Tutorial
5
Packaging
5
This chapter describes packaging. A Java EE application is packaged into one or more
standard units for deployment to any Java EE platform–compliant system. Each unit
contains a functional component or components, such as an enterprise bean, web page,
servlet, or applet, and an optional deployment descriptor that describes its content.
The following topics are addressed here:
■
Packaging Applications
■
Packaging Enterprise Beans
■
Packaging Web Archives
■
Packaging Resource Adapter Archives
5.1 Packaging Applications
A Java EE application is delivered in a Java Archive (JAR) file, a Web Archive (WAR)
file, or an Enterprise Archive (EAR) file. A WAR or EAR file is a standard JAR (.jar)
file with a .war or .ear extension. Using JAR, WAR, and EAR files and modules
makes it possible to assemble a number of different Java EE applications using some of
the same components. No extra coding is needed; it is only a matter of assembling (or
packaging) various Java EE modules into Java EE JAR, WAR, or EAR files.
An EAR file (see Figure 5–1) contains Java EE modules and, optionally, deployment
descriptors. A deployment descriptor, an XML document with an .xml extension,
describes the deployment settings of an application, a module, or a component.
Because deployment descriptor information is declarative, it can be changed without
the need to modify the source code. At runtime, the Java EE server reads the
deployment descriptor and acts upon the application, module, or component
accordingly.
Deployment information is most commonly specified in the source code by
annotations. Deployment descriptors, if present, override what is specified in the
source code.
Packaging 5-1
Packaging Enterprise Beans
Figure 5–1 EAR File Structure
Assembly Root
META-INF
Web
Module
Application
Client Module
Resource
Adapter Module
EJB
Module
application.xml
glassfish-application.xml
(optional)
The two types of deployment descriptors are Java EE and runtime. A Java EE
deployment descriptor is defined by a Java EE specification and can be used to
configure deployment settings on any Java EE-compliant implementation. A runtime
deployment descriptor is used to configure Java EE implementation-specific
parameters. For example, the GlassFish Server runtime deployment descriptor
contains such information as the context root of a web application as well as GlassFish
Server implementation-specific parameters, such as caching directives. The GlassFish
Server runtime deployment descriptors are named glassfish-moduleType.xml and are
located in the same META-INF directory as the Java EE deployment descriptor.
A Java EE module consists of one or more Java EE components for the same container
type and, optionally, one component deployment descriptor of that type. An
enterprise bean module deployment descriptor, for example, declares transaction
attributes and security authorizations for an enterprise bean. A Java EE module can be
deployed as a stand-alone module.
Java EE modules are of the following types:
■
■
■
■
EJB modules, which contain class files for enterprise beans and, optionally, an EJB
deployment descriptor. EJB modules are packaged as JAR files with a .jar
extension.
Web modules, which contain servlet class files, web files, supporting class files,
GIF and HTML files, and, optionally, a web application deployment descriptor.
Web modules are packaged as JAR files with a .war (web archive) extension.
Application client modules, which contain class files and, optionally, an
application client deployment descriptor. Application client modules are packaged
as JAR files with a .jar extension.
Resource adapter modules, which contain all Java interfaces, classes, native
libraries, and, optionally, a resource adapter deployment descriptor. Together,
these implement the Connector architecture (see Java EE Connector Architecture)
for a particular EIS. Resource adapter modules are packaged as JAR files with an
.rar (resource adapter archive) extension.
5.2 Packaging Enterprise Beans
This section explains how enterprise beans can be packaged in EJB JAR or WAR
modules.
5-2 The Java EE 7 Tutorial
Packaging Enterprise Beans
5.2.1 Packaging Enterprise Beans in EJB JAR Modules
An EJB JAR file is portable and can be used for various applications.
To assemble a Java EE application, package one or more modules, such as EJB JAR
files, into an EAR file, the archive file that holds the application. When deploying the
EAR file that contains the enterprise bean's EJB JAR file, you also deploy the enterprise
bean to GlassFish Server. You can also deploy an EJB JAR that is not contained in an
EAR file. Figure 5–2 shows the contents of an EJB JAR file.
Figure 5–2 Structure of an Enterprise Bean JAR
Assembly Root
META-INF
All .class files
for this module
ejb-jar.xml
glassfish-ejb-jar.xml
(optional)
MANIFEST.MF
5.2.2 Packaging Enterprise Beans in WAR Modules
Enterprise beans often provide the business logic of a web application. In these cases,
packaging the enterprise bean within the web application's WAR module simplifies
deployment and application organization. Enterprise beans may be packaged within a
WAR module as Java programming language class files or within a JAR file that is
bundled within the WAR module.
To include enterprise bean class files in a WAR module, the class files should be in the
WEB-INF/classes directory.
To include a JAR file that contains enterprise beans in a WAR module, add the JAR to
the WEB-INF/lib directory of the WAR module.
WAR modules that contain enterprise beans do not require an ejb-jar.xml
deployment descriptor. If the application uses ejb-jar.xml, it must be located in the
WAR module's WEB-INF directory.
JAR files that contain enterprise bean classes packaged within a WAR module are not
considered EJB JAR files, even if the bundled JAR file conforms to the format of an EJB
JAR file. The enterprise beans contained within the JAR file are semantically
equivalent to enterprise beans located in the WAR module's WEB-INF/classes
directory, and the environment namespace of all the enterprise beans are scoped to the
WAR module.
For example, suppose that a web application consists of a shopping cart enterprise
bean, a credit card–processing enterprise bean, and a Java servlet front end. The
shopping cart bean exposes a local, no-interface view and is defined as follows:
package com.example.cart;
@Stateless
Packaging 5-3
Packaging Web Archives
public class CartBean { ... }
The credit card–processing bean is packaged within its own JAR file, cc.jar, exposes a
local, no-interface view, and is defined as follows:
package com.example.cc;
@Stateless
public class CreditCardBean { ... }
The servlet, com.example.web.StoreServlet, handles the web front end and uses both
CartBean and CreditCardBean. The WAR module layout for this application is as
follows:
WEB-INF/classes/com/example/cart/CartBean.class
WEB-INF/classes/com/example/web/StoreServlet
WEB-INF/lib/cc.jar
WEB-INF/ejb-jar.xml
WEB-INF/web.xml
5.3 Packaging Web Archives
In the Java EE architecture, a web module is the smallest deployable and usable unit
of web resources. A web module contains web components and static web content
files, such as images, which are called web resources. A Java EE web module
corresponds to a web application as defined in the Java Servlet specification.
In addition to web components and web resources, a web module can contain other
files:
■
Server-side utility classes, such as shopping carts
■
Client-side classes, such as utility classes
A web module has a specific structure. The top-level directory of a web module is the
document root of the application. The document root is where XHTML pages,
client-side classes and archives, and static web resources, such as images, are stored.
The document root contains a subdirectory named WEB-INF, which can contain the
following files and directories:
■
■
■
classes, a directory that contains server-side classes: servlets, enterprise bean
class files, utility classes, and JavaBeans components
lib, a directory that contains JAR files that contain enterprise beans, and JAR
archives of libraries called by server-side classes
Deployment descriptors, such as web.xml (the web application deployment
descriptor) and ejb-jar.xml (an EJB deployment descriptor)
A web module needs a web.xml file if it uses JavaServer Faces technology, if it must
specify certain kinds of security information, or if you want to override information
specified by web component annotations.
You can also create application-specific subdirectories (that is, package directories) in
either the document root or the WEB-INF/classes/ directory.
A web module can be deployed as an unpacked file structure or can be packaged in a
JAR file known as a Web Archive (WAR) file. Because the contents and use of WAR
files differ from those of JAR files, WAR file names use a .war extension. The web
module just described is portable; you can deploy it into any web container that
conforms to the Java Servlet specification.
5-4 The Java EE 7 Tutorial
Packaging Resource Adapter Archives
You can provide a runtime deployment descriptor (DD) when you deploy a WAR on
GlassFish Server, but it is not required under most circumstances. The runtime DD is
an XML file that may contain such information as the context root of the web
application, the mapping of the portable names of an application's resources to
GlassFish Server resources, and the mapping of an application's security roles to users,
groups, and principals defined in GlassFish Server. The GlassFish Server web
application runtime DD, if used, is named glassfish-web.xml and is located in the
WEB-INF directory. The structure of a web module that can be deployed on GlassFish
Server is shown in Figure 5–3.
Figure 5–3 Web Module Structure
Assembly Root
WEB-INF
lib
classes
Web pages
web.xml
glassfish-web.xml
(optional)
Library
archive files
All server-side
.class files for
this web module
5.4 Packaging Resource Adapter Archives
A Resource Adapter Archive (RAR) file stores XML files, Java classes, and other
objects for Java EE Connector Architecture (JCA) applications. A resource adapter can
be deployed on any Java EE server, much like a Java EE application. A RAR file can be
contained in an Enterprise Archive (EAR) file, or it can exist as a separate file.
The RAR file contains
■
■
A JAR file with the implementation classes of the resource adapter
An optional META-INF/ directory that can store an ra.xml file and/or an
application server–specific deployment descriptor used for configuration purposes
A RAR file can be deployed on the application server as a standalone component or as
part of a larger application. In both cases, the adapter is available to all applications
using a lookup procedure.
Packaging 5-5
Packaging Resource Adapter Archives
5-6 The Java EE 7 Tutorial
Part III
Part III
The Web Tier
Part III explores the technologies in the web tier. This part contains the following
chapters:
■
Chapter 6, "Getting Started with Web Applications"
■
Chapter 7, "JavaServer Faces Technology"
■
Chapter 8, "Introduction to Facelets"
■
Chapter 9, "Expression Language"
■
Chapter 10, "Using JavaServer Faces Technology in Web Pages"
■
Chapter 11, "Using Converters, Listeners, and Validators"
■
Chapter 12, "Developing with JavaServer Faces Technology"
■
Chapter 13, "Using Ajax with JavaServer Faces Technology"
■
Chapter 14, "Composite Components: Advanced Topics and an Example"
■
Chapter 15, "Creating Custom UI Components and Other Custom Objects"
■
Chapter 16, "Configuring JavaServer Faces Applications"
■
Chapter 17, "Java Servlet Technology"
■
Chapter 18, "Java API for WebSocket"
■
Chapter 19, "JSON Processing"
■
Chapter 20, "Internationalizing and Localizing Web Applications"
6
Getting Started with Web Applications
6
This chapter introduces web applications, which typically use JavaServer Faces
technology and/or Java Servlet technology. A web application is a dynamic extension
of a web or application server. Web applications are of the following types:
■
■
Presentation-oriented: A presentation-oriented web application generates
interactive web pages containing various types of markup language (HTML,
XHTML, XML, and so on) and dynamic content in response to requests.
Development of presentation-oriented web applications is covered in Chapter 7,
"JavaServer Faces Technology," through Chapter 17, "Java Servlet Technology."
Service-oriented: A service-oriented web application implements the endpoint of
a web service. Presentation-oriented applications are often clients of
service-oriented web applications. Development of service-oriented web
applications is covered in Chapter 28, "Building Web Services with JAX-WS," and
Chapter 29, "Building RESTful Web Services with JAX-RS," in Part VI, "Web
Services."
The following topics are addressed here:
■
Web Applications
■
Web Application Lifecycle
■
A Web Module That Uses JavaServer Faces Technology: The hello1 Example
■
A Web Module That Uses Java Servlet Technology: The hello2 Example
■
Configuring Web Applications
■
Further Information about Web Applications
6.1 Web Applications
In the Java EE platform, web components provide the dynamic extension capabilities
for a web server. Web components can be Java servlets, web pages implemented with
JavaServer Faces technology, web service endpoints, or JSP pages. Figure 6–1
illustrates the interaction between a web client and a web application that uses a
servlet. The client sends an HTTP request to the web server. A web server that
implements Java Servlet and JavaServer Pages technology converts the request into an
HTTPServletRequest object. This object is delivered to a web component, which can
interact with JavaBeans components or a database to generate dynamic content. The
web component can then generate an HTTPServletResponse or can pass the request to
another web component. A web component eventually generates a
HTTPServletResponse object. The web server converts this object to an HTTP response
and returns it to the client.
Getting Started with Web Applications
6-1
Web Application Lifecycle
Figure 6–1 Java Web Application Request Handling
HttpServlet
Request
1 HTTP Request
Web
Client
Web
Components
2
5
HTTP Response
6
HttpServlet
Response
4
Database
3
JavaBeans
Components
4
Database
Servlets are Java programming language classes that dynamically process requests and
construct responses. Java technologies, such as JavaServer Faces and Facelets, are used
for building interactive web applications. (Frameworks can also be used for this
purpose.) Although servlets and JavaServer Faces and Facelets pages can be used to
accomplish similar things, each has its own strengths. Servlets are best suited for
service-oriented applications (web service endpoints can be implemented as servlets)
and the control functions of a presentation-oriented application, such as dispatching
requests and handling nontextual data. JavaServer Faces and Facelets pages are more
appropriate for generating text-based markup, such as XHTML, and are generally
used for presentation-oriented applications.
Web components are supported by the services of a runtime platform called a web
container. A web container provides such services as request dispatching, security,
concurrency, and lifecycle management. A web container also gives web components
access to such APIs as naming, transactions, and email.
Certain aspects of web application behavior can be configured when the application is
installed, or deployed, to the web container. The configuration information can be
specified using Java EE annotations or can be maintained in a text file in XML format
called a web application deployment descriptor (DD). A web application DD must
conform to the schema described in the Java Servlet specification.
This chapter gives a brief overview of the activities involved in developing web
applications. First, it summarizes the web application lifecycle and explains how to
package and deploy very simple web applications on GlassFish Server. The chapter
then moves on to configuring web applications and discusses how to specify the most
commonly used configuration parameters.
6.2 Web Application Lifecycle
A web application consists of web components; static resource files, such as images
and cascading style sheets (CSS); and helper classes and libraries. The web container
provides many supporting services that enhance the capabilities of web components
and make them easier to develop. However, because a web application must take these
services into account, the process for creating and running a web application is
different from that of traditional stand-alone Java classes.
The process for creating, deploying, and executing a web application can be
summarized as follows:
1.
Develop the web component code.
2.
Develop the web application deployment descriptor, if necessary.
3.
Compile the web application components and helper classes referenced by the
components.
6-2 The Java EE 7 Tutorial
A Web Module That Uses JavaServer Faces Technology: The hello1 Example
4.
Optionally, package the application into a deployable unit.
5.
Deploy the application into a web container.
6.
Access a URL that references the web application.
Developing web component code is covered in the later chapters. Steps 2 through 4 are
expanded on in the following sections and illustrated with a Hello, World–style,
presentation-oriented application. This application allows a user to enter a name into
an HTML form and then displays a greeting after the name is submitted.
The Hello application contains two web components that generate the greeting and the
response. This chapter discusses the following simple applications:
■
■
hello1, a JavaServer Faces technology–based application that uses two XHTML
pages and a managed bean
hello2, a servlet-based web application in which the components are
implemented by two servlet classes
The applications are used to illustrate tasks involved in packaging, deploying,
configuring, and running an application that contains web components.
6.3 A Web Module That Uses JavaServer Faces Technology: The hello1
Example
The hello1 application is a web module that uses JavaServer Faces technology to
display a greeting and response. You can use a text editor to view the application files,
or you can use NetBeans IDE.
The source code for this application is in the tut-install/examples/web/jsf/hello1/
directory.
6.3.1 To View the hello1 Web Module Using NetBeans IDE
1.
From the File menu, choose Open Project.
2.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsf
3.
Select the hello1 folder and click Open Project.
4.
Expand the Web Pages node and double-click the index.xhtml file to view it in
the editor.
The index.xhtml file is the default landing page for a Facelets application. In a
typical Facelets application, web pages are created in XHTML. For this application,
the page uses simple tag markup to display a form with a graphic image, a header,
a field, and two command buttons:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>Facelets Hello Greeting</title>
</h:head>
<h:body>
<h:form>
<h:graphicImage url="#{resource['images:duke.waving.gif']}"
Getting Started with Web Applications
6-3
A Web Module That Uses JavaServer Faces Technology: The hello1 Example
alt="Duke waving his hand"/>
<h2>Hello, my name is Duke. What's yours?</h2>
<h:inputText id="username"
title="My name is: "
value="#{hello.name}"
required="true"
requiredMessage="Error: A name is required."
maxlength="25" />
<p></p>
<h:commandButton id="submit" value="Submit" action="response">
</h:commandButton>
<h:commandButton id="reset" value="Reset" type="reset">
</h:commandButton>
</h:form>
...
</h:body>
</html>
The most complex element on the page is the inputText field. The maxlength
attribute specifies the maximum length of the field. The required attribute
specifies that the field must be filled out; the requiredMessage attribute provides
the error message to be displayed if the field is left empty. The title attribute
provides the text to be used by screen readers for the visually disabled. Finally, the
value attribute contains an expression that will be provided by the Hello managed
bean.
The web page connects to the Hello managed bean through the Expression
Language (EL) value expression #{hello.name}, which retrieves the value of the
name property from the managed bean. Note the use of hello to reference the
managed bean Hello. If no name is specified in the @Named annotation of the
managed bean, the managed bean is always accessed with the first letter of the
class name in lowercase.
The Submit commandButton element specifies the action as response, meaning that
when the button is clicked, the response.xhtml page is displayed.
5.
Double-click the response.xhtml file to view it.
The response page appears. Even simpler than the greeting page, the response
page contains a graphic image, a header that displays the expression provided by
the managed bean, and a single button whose action element transfers you back
to the index.xhtml page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>Facelets Hello Response</title>
</h:head>
<h:body>
<h:form>
<h:graphicImage url="#{resource['images:duke.waving.gif']}"
alt="Duke waving his hand"/>
<h2>Hello, #{hello.name}!</h2>
<p></p>
<h:commandButton id="back" value="Back" action="index" />
</h:form>
</h:body>
</html>
6-4 The Java EE 7 Tutorial
A Web Module That Uses JavaServer Faces Technology: The hello1 Example
6.
Expand the Source Packages node, then the javaeetutorial.hello1 node.
7.
Double-click the Hello.java file to view it.
The Hello class, called a managed bean class, provides getter and setter methods
for the name property used in the Facelets page expressions. By default, the
expression language refers to the class name, with the first letter in lowercase
(hello.name).
package javaeetutorial.hello1;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
@Named
@RequestScoped
public class Hello {
private String name;
public Hello() {
}
public String getName() {
return name;
}
public void setName(String user_name) {
this.name = user_name;
}
}
If you use the default name for the bean class, you can specify @Model as the
annotation instead of having to specify both @Named and @RequestScoped. The
@Model annotation is called a stereotype, a term for an annotation that
encapsulates other annotations. It is described later in Using Stereotypes in CDI
Applications. Some examples will use @Model where it is appropriate.
8.
Under the Web Pages node, expand the WEB-INF node and double-click the
web.xml file to view it.
The web.xml file contains several elements that are required for a Facelets
application. All of the following are created automatically when you use NetBeans
IDE to create an application.
■
A context parameter specifying the project stage:
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
A context parameter provides configuration information needed by a web
application. An application can define its own context parameters. In addition,
JavaServer Faces technology and Java Servlet technology define context
parameters that an application can use.
■
A servlet element and its servlet-mapping element specifying the
FacesServlet. All files with the .xhtml suffix will be matched:
<servlet>
Getting Started with Web Applications
6-5
A Web Module That Uses JavaServer Faces Technology: The hello1 Example
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
■
A welcome-file-list element specifying the location of the landing page:
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
6.3.1.1 Introduction to Scopes
In the Hello.java class, the annotations javax.inject.Named and
javax.enterprise.context.RequestScoped identify the class as a managed bean
using request scope. Scope defines how application data persists and is shared.
The most commonly used scopes in JavaServer Faces applications are the following:
■
■
■
Request (@RequestScoped): Request scope persists during a single HTTP request
in a web application. In an application like hello1, in which the application
consists of a single request and response, the bean uses request scope.
Session (@SessionScoped): Session scope persists across multiple HTTP requests
in a web application. When an application consists of multiple requests and
responses where data needs to be maintained, beans use session scope.
Application (@ApplicationScoped): Application scope persists across all users'
interactions with a web application.
For more information on scopes in JavaServer Faces technology, see Using Managed
Bean Scopes.
6.3.2 Packaging and Deploying the hello1 Web Module
A web module must be packaged into a WAR in certain deployment scenarios and
whenever you want to distribute the web module. You can package a web module into
a WAR file by using Maven or by using the IDE tool of your choice. This tutorial
shows you how to use NetBeans IDE or Maven to build, package, and deploy the
hello1 sample application.
You can deploy a WAR file to GlassFish Server by:
■
Using NetBeans IDE
■
Using the asadmin command
■
Using the Administration Console
■
Copying the WAR file into the domain-dir/autodeploy/ directory
Throughout the tutorial, you will use NetBeans IDE or Maven for packaging and
deploying.
6.3.2.1 To Build and Package the hello1 Web Module Using NetBeans IDE
1.
Start GlassFish Server as described in To Start GlassFish Server Using NetBeans
IDE, if you have not already done so.
2.
From the File menu, choose Open Project.
6-6 The Java EE 7 Tutorial
A Web Module That Uses JavaServer Faces Technology: The hello1 Example
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsf
4.
Select the hello1 folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the hello1 project and select Build. This command
deploys the project to the server.
6.3.2.2 To Build and Package the hello1 Web Module Using Maven
1.
Start GlassFish Server as described in To Start GlassFish Server Using the
Command Line, if you have not already done so.
2.
In a terminal window, go to:
tut-install/examples/web/jsf/hello1/
3.
Enter the following command:
mvn install
This command spawns any necessary compilations and creates the WAR file in
tut-install/examples/web/jsf/hello1/target/. It then deploys the project to the
server.
6.3.3 Viewing Deployed Web Modules
GlassFish Server provides two ways to view the deployed web modules: the
Administration Console and the asadmin command. You can also use NetBeans
to view deployed modules.
IDE
6.3.3.1 To View Deployed Web Modules Using the Administration Console
1.
Open the URL http://localhost:4848/ in a browser.
2.
Select the Applications node.
The deployed web modules appear in the Deployed Applications table.
6.3.3.2 To View Deployed Web Modules Using the asadmin Command
Enter the following command:
asadmin list-applications
6.3.3.3 To View Deployed Web Modules Using NetBeans IDE
1.
In the Services tab, expand the Servers node, then expand the GlassFish Server
node.
2.
Expand the Applications node to view the deployed modules.
6.3.4 Running the Deployed hello1 Web Module
Now that the web module is deployed, you can view it by opening the application in a
web browser. By default, the application is deployed to host localhost on port 8080.
The context root of the web application is hello1.
1.
Open a web browser.
2.
Enter the following URL:
Getting Started with Web Applications
6-7
A Web Module That Uses Java Servlet Technology: The hello2 Example
http://localhost:8080/hello1/
3.
In the field, enter your name and click Submit.
The response page displays the name you submitted. Click Back to try again.
6.3.4.1 Dynamic Reloading of Deployed Modules
If dynamic reloading is enabled, you do not have to redeploy an application or module
when you change its code or deployment descriptors. All you have to do is copy the
changed pages or class files into the deployment directory for the application or
module. The deployment directory for a web module named context-root is
domain-dir/applications/context-root. The server checks for changes periodically and
redeploys the application, automatically and dynamically, with the changes.
This capability is useful in a development environment because it allows code changes
to be tested quickly. Dynamic reloading is not recommended for a production
environment, however, because it may degrade performance. In addition, whenever a
reload takes place, the sessions at that time become invalid, and the client must restart
the session.
In GlassFish Server, dynamic reloading is enabled by default.
6.3.5 Undeploying the hello1 Web Module
You can undeploy web modules and other types of enterprise applications by using
either NetBeans IDE or Maven.
6.3.5.1 To Undeploy the hello1 Web Module Using NetBeans IDE
1.
In the Services tab, expand the Servers node, then expand the GlassFish Server
node.
2.
Expand the Applications node.
3.
Right-click the hello1 module and select Undeploy.
4.
To delete the class files and other build artifacts, go back to the Projects tab,
right-click the project, and select Clean.
6.3.5.2 To Undeploy the hello1 Web Module Using Maven
1.
In a terminal window, go to:
tut-install/examples/web/jsf/hello1/
2.
Enter the following command:
mvn cargo:undeploy
3.
To delete the class files and other build artifacts, enter the following command:
mvn clean
6.4 A Web Module That Uses Java Servlet Technology: The hello2
Example
The hello2 application is a web module that uses Java Servlet technology to display a
greeting and response. You can use a text editor to view the application files, or you
can use NetBeans IDE.
6-8 The Java EE 7 Tutorial
A Web Module That Uses Java Servlet Technology: The hello2 Example
The source code for this application is in the
tut-install/examples/web/servlet/hello2/ directory.
6.4.1 Mapping URLs to Web Components
When it receives a request, the web container must determine which web component
should handle the request. The web container does so by mapping the URL path
contained in the request to a web application and a web component. A URL path
contains the context root and, optionally, a URL pattern:
http://host:port/context-root[/url-pattern]
You set the URL pattern for a servlet by using the @WebServlet annotation in the
servlet source file. For example, the GreetingServlet.java file in the hello2
application contains the following annotation, specifying the URL pattern as
/greeting:
@WebServlet("/greeting")
public class GreetingServlet extends HttpServlet {
...
This annotation indicates that the URL pattern /greeting follows the context root.
Therefore, when the servlet is deployed locally, it is accessed with the following URL:
http://localhost:8080/hello2/greeting
To access the servlet by using only the context root, specify "/" as the URL pattern.
6.4.2 Examining the hello2 Web Module
The hello2 application behaves almost identically to the hello1 application, but it is
implemented using Java Servlet technology instead of JavaServer Faces technology.
You can use a text editor to view the application files, or you can use NetBeans IDE.
6.4.2.1 To View the hello2 Web Module Using NetBeans IDE
1.
From the File menu, choose Open Project.
2.
In the Open Project dialog box, navigate to:
tut-install/examples/web/servlet
3.
Select the hello2 folder and click Open Project.
4.
Expand the Source Packages node, then expand the javaeetutorial.hello2
node.
5.
Double-click the GreetingServlet.java file to view it.
This servlet overrides the doGet method, implementing the GET method of HTTP.
The servlet displays a simple HTML greeting form whose Submit button, like that
of hello1, specifies a response page for its action. The following excerpt begins
with the @WebServlet annotation, which specifies the URL pattern relative to the
context root:
@WebServlet("/greeting")
public class GreetingServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Getting Started with Web Applications
6-9
A Web Module That Uses Java Servlet Technology: The hello2 Example
response.setContentType("text/html");
response.setBufferSize(8192);
try (PrintWriter out = response.getWriter()) {
out.println("<html lang=\"en\">"
+ "<head><title>Servlet Hello</title></head>");
// then write the data of the response
out.println("<body bgcolor=\"#ffffff\">"
+ "<img src=\"duke.waving.gif\" "
+ "alt=\"Duke waving his hand\">"
+ "<form method=\"get\">"
+ "<h2>Hello, my name is Duke. What's yours?</h2>"
+ "<input title=\"My name is: \"type=\"text\" "
+ "name=\"username\" size=\"25\">"
+ "<p></p>"
+ "<input type=\"submit\" value=\"Submit\">"
+ "<input type=\"reset\" value=\"Reset\">"
+ "</form>");
String username = request.getParameter("username");
if (username != null && username.length()> 0) {
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher("/response");
if (dispatcher != null) {
dispatcher.include(request, response);
}
}
out.println("</body></html>");
}
}
...
6.
Double-click the ResponseServlet.java file to view it.
This servlet also overrides the doGet method, displaying only the response. The
following excerpt begins with the @WebServlet annotation, which specifies the
URL pattern relative to the context root:
@WebServlet("/response")
public class ResponseServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
try (PrintWriter out = response.getWriter()) {
// then write the data of the response
String username = request.getParameter("username");
if (username != null && username.length()> 0) {
out.println("<h2>Hello, " + username + "!</h2>");
}
}
}
...
6-10 The Java EE 7 Tutorial
Configuring Web Applications
6.4.3 Running the hello2 Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
hello2 example.
6.4.3.1 To Run the hello2 Example Using NetBeans IDE
1.
Start GlassFish Server as described in To Start GlassFish Server Using NetBeans
IDE, if you have not already done so.
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/servlet
4.
Select the hello2 folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the hello2 project and select Build to package and
deploy the project.
7.
In a web browser, open the following URL:
http://localhost:8080/hello2/greeting
The URL specifies the context root, followed by the URL pattern.
The application looks much like the hello1 application. The major difference is
that after you click Submit the response appears below the greeting, not on a
separate page.
6.4.3.2 To Run the hello2 Example Using Maven
1.
Start GlassFish Server as described in To Start GlassFish Server Using the
Command Line, if you have not already done so.
2.
In a terminal window, go to:
tut-install/examples/web/servlet/hello2/
3.
Enter the following command:
mvn install
This target builds the WAR file, copies it to the
tut-install/examples/web/hello2/target/ directory, and deploys it.
4.
In a web browser, open the following URL:
http://localhost:8080/hello2/greeting
The URL specifies the context root, followed by the URL pattern.
The application looks much like the hello1 application. The major difference is
that after you click Submit the response appears below the greeting, not on a
separate page.
6.5 Configuring Web Applications
This section describes the following tasks involved with configuring web applications:
■
Setting context parameters
Getting Started with Web Applications 6-11
Configuring Web Applications
■
Declaring welcome files
■
Mapping errors to error screens
■
Declaring resource references
6.5.1 Setting Context Parameters
The web components in a web module share an object that represents their application
context. You can pass context parameters to the context, or you can pass initialization
parameters to a servlet. Context parameters are available to the entire application. For
information on initialization parameters, see Creating and Initializing a Servlet.
6.5.1.1 To Add a Context Parameter Using NetBeans IDE
These steps apply generally to web applications but do not apply specifically to the
examples in this chapter.
1.
Open the project.
2.
Expand the project's node in the Projects tree.
3.
Expand the Web Pages node and then the WEB-INF node.
4.
Double-click web.xml.
If the project does not have a web.xml file, create one by following the steps in To
Create a web.xml File Using NetBeans IDE.
5.
Click General at the top of the editor window.
6.
Expand the Context Parameters node.
7.
Click Add.
8.
In the Add Context Parameter dialog box, in the Parameter Name field, enter the
name that specifies the context object.
9.
In the Parameter Value field, enter the parameter to pass to the context object.
10. Click OK.
6.5.1.2 To Create a web.xml File Using NetBeans IDE
1.
From the File menu, choose New File.
2.
In the New File wizard, select the Web category, then select Standard Deployment
Descriptor under File Types.
3.
Click Next.
4.
Click Finish.
A basic web.xml file appears in web/WEB-INF/.
6.5.2 Declaring Welcome Files
The welcome files mechanism allows you to specify a list of files that the web
container can append to a request for a URL (called a valid partial request) that is not
mapped to a web component. For example, suppose that you define a welcome file
welcome.html. When a client requests a URL such as host:port/webapp/directory, where
directory is not mapped to a servlet or XHTML page, the file
host:port/webapp/directory/welcome.html is returned to the client.
6-12 The Java EE 7 Tutorial
Configuring Web Applications
If a web container receives a valid partial request, the web container examines the
welcome file list, appends to the partial request each welcome file in the order
specified, and checks whether a static resource or servlet in the WAR is mapped to that
request URL. The web container then sends the request to the first resource that
matches in the WAR.
If no welcome file is specified, GlassFish Server will use a file named index.html as
the default welcome file. If there is no welcome file and no file named index.html,
GlassFish Server returns a directory listing.
You specify welcome files in the web.xml file. The welcome file specification for the
hello1 example looks like this:
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
A specified welcome file must not have a leading or trailing slash (/).
The hello2 example does not specify a welcome file, because the URL request is
mapped to the GreetingServlet web component through the URL pattern /greeting.
6.5.3 Mapping Errors to Error Screens
When an error occurs during execution of a web application, you can have the
application display a specific error screen according to the type of error. In particular,
you can specify a mapping between the status code returned in an HTTP response or a
Java programming language exception returned by any web component and any type
of error screen.
You can have multiple error-page elements in your deployment descriptor. Each
element identifies a different error that causes an error page to open. This error page
can be the same for any number of error-page elements.
6.5.3.1 To Set Up Error Mapping Using NetBeans IDE
These steps apply generally to web applications but do not apply specifically to the
examples in this chapter.
1.
Open the project.
2.
Expand the project's node in the Projects tab.
3.
Expand the Web Pages node and then the WEB-INF node.
4.
Double-click web.xml.
If the project does not have a web.xml file, create one by following the steps in To
Create a web.xml File Using NetBeans IDE.
5.
Click Pages at the top of the editor window.
6.
Expand the Error Pages node.
7.
Click Add.
8.
In the Add Error Page dialog box, click Browse to locate the page that you want to
act as the error page.
9.
Specify either an error code or an exception type.
■
To specify an error code, in the Error Code field enter the HTTP status code
that will cause the error page to be opened, or leave the field blank to include
all error codes.
Getting Started with Web Applications 6-13
Configuring Web Applications
■
To specify an exception type, in the Exception Type field enter the exception
that will cause the error page to load. To specify all throwable errors and
exceptions, enter java.lang.Throwable.
10. Click OK.
6.5.4 Declaring Resource References
If your web component uses such objects as enterprise beans, data sources, or web
services, you use Java EE annotations to inject these resources into your application.
Annotations eliminate a lot of the boilerplate lookup code and configuration elements
that previous versions of Java EE required.
Although resource injection using annotations can be more convenient for the
developer, there are some restrictions on using it in web applications. First, you can
inject resources only into container-managed objects, because a container must have
control over the creation of a component so that it can perform the injection into a
component. As a result, you cannot inject resources into such objects as simple
JavaBeans components. However, managed beans are managed by the container;
therefore, they can accept resource injections.
Components that can accept resource injections are listed in Table 6–1.
This section explains how to use a couple of the annotations supported by a web
container to inject resources. Chapter 38, "Running the Persistence Examples", explains
how web applications use annotations supported by the Java Persistence API.
Chapter 48, "Getting Started Securing Web Applications", explains how to use
annotations to specify information about securing web applications. See Chapter 52,
"Resource Adapters and Contracts", for more information on resources.
Table 6–1
Web Components That Accept Resource Injections
Component
Interface/Class
Servlets
javax.servlet.Servlet
Servlet filters
javax.servlet.ServletFilter
Event listeners
javax.servlet.ServletContextListener
javax.servlet.ServletContextAttributeListener
javax.servlet.ServletRequestListener
javax.servlet.ServletRequestAttributeListener
javax.servlet.http.HttpSessionListener
javax.servlet.http.HttpSessionAttributeListener
javax.servlet.http.HttpSessionBindingListener
Managed beans
Plain Old Java Objects
6.5.4.1 Declaring a Reference to a Resource
The @Resource annotation is used to declare a reference to a resource, such as a data
source, an enterprise bean, or an environment entry.
The @Resource annotation is specified on a class, a method, or a field. The container is
responsible for injecting references to resources declared by the @Resource annotation
and mapping it to the proper JNDI resources.
In the following example, the @Resource annotation is used to inject a data source into
a component that needs to make a connection to the data source, as is done when
using JDBC technology to access a relational database:
6-14 The Java EE 7 Tutorial
Further Information about Web Applications
@Resource javax.sql.DataSource catalogDS;
public getProductsByCategory() {
// get a connection and execute the query
Connection conn = catalogDS.getConnection();
...
}
The container injects this data source prior to the component's being made available to
the application. The data source JNDI mapping is inferred from the field name,
catalogDS, and the type, javax.sql.DataSource.
If you have multiple resources that you need to inject into one component, you need to
use the @Resources annotation to contain them, as shown by the following example:
@Resources ({
@Resource(name="myDB" type=javax.sql.DataSource.class),
@Resource(name="myMQ" type=javax.jms.ConnectionFactory.class)
})
The web application examples in this tutorial use the Java Persistence API to access
relational databases. This API does not require you to explicitly create a connection to
a data source. Therefore, the examples do not use the @Resource annotation to inject a
data source. However, this API supports the @PersistenceUnit and
@PersistenceContext annotations for injecting EntityManagerFactory and
EntityManager instances, respectively. Chapter 38, "Running the Persistence
Examples" describes these annotations and the use of the Java Persistence API in web
applications.
6.5.4.2 Declaring a Reference to a Web Service
The @WebServiceRef annotation provides a reference to a web service. The following
example shows uses the @WebServiceRef annotation to declare a reference to a web
service. WebServiceRef uses the wsdlLocation element to specify the URI of the
deployed service's WSDL file:
...
import javax.xml.ws.WebServiceRef;
...
public class ResponseServlet extends HTTPServlet {
@WebServiceRef(wsdlLocation="http://localhost:8080/helloservice/hello?wsdl")
static HelloService service;
6.6 Further Information about Web Applications
For more information on web applications, see
■
JavaServer Faces 2.2 specification:
http://jcp.org/en/jsr/detail?id=344
■
Java Servlet 3.1 specification:
http://jcp.org/en/jsr/detail?id=340
Getting Started with Web Applications 6-15
Further Information about Web Applications
6-16 The Java EE 7 Tutorial
7
JavaServer Faces Technology
7
JavaServer Faces technology is a server-side component framework for building Java
technology–based web applications.
JavaServer Faces technology consists of the following:
■
■
An API for representing components and managing their state; handling events,
server-side validation, and data conversion; defining page navigation; supporting
internationalization and accessibility; and providing extensibility for all these
features
Tag libraries for adding components to web pages and for connecting components
to server-side objects
JavaServer Faces technology provides a well-defined programming model and various
tag libraries. The tag libraries contain tag handlers that implement the component
tags. These features significantly ease the burden of building and maintaining web
applications with server-side user interfaces (UIs). With minimal effort, you can
complete the following tasks.
■
Create a web page.
■
Drop components onto a web page by adding component tags.
■
Bind components on a page to server-side data.
■
Wire component-generated events to server-side application code.
■
Save and restore application state beyond the life of server requests.
■
Reuse and extend components through customization.
This chapter provides an overview of JavaServer Faces technology. After explaining
what a JavaServer Faces application is and reviewing some of the primary benefits of
using JavaServer Faces technology, this chapter describes the process of creating a
simple JavaServer Faces application. This chapter also introduces the JavaServer Faces
lifecycle by describing the example JavaServer Faces application and its progression
through the lifecycle stages.
The following topics are addressed here:
■
What Is a JavaServer Faces Application?
■
JavaServer Faces Technology Benefits
■
A Simple JavaServer Faces Application
■
User Interface Component Model
■
Navigation Model
■
The Lifecycle of a JavaServer Faces Application
JavaServer Faces Technology
7-1
What Is a JavaServer Faces Application?
■
Partial Processing and Partial Rendering
■
Further Information about JavaServer Faces Technology
7.1 What Is a JavaServer Faces Application?
The functionality provided by a JavaServer Faces application is similar to that of any
other Java web application. A typical JavaServer Faces application includes the
following parts.
■
A set of web pages in which components are laid out.
■
A set of tags to add components to the web page.
■
■
■
■
■
A set of managed beans, which are lightweight, container-managed objects
(POJOs). In a JavaServer Faces application, managed beans serve as backing beans,
which define properties and functions for UI components on a page.
A web deployment descriptor (web.xml file).
Optionally, one or more application configuration resource files, such as a
faces-config.xml file, which can be used to define page navigation rules and
configure beans and other custom objects, such as custom components.
Optionally, a set of custom objects, which can include custom components,
validators, converters, or listeners, created by the application developer.
Optionally, a set of custom tags for representing custom objects on the page.
Figure 7–1 shows the interaction between client and server in a typical JavaServer
Faces application. In response to a client request, a web page is rendered by the web
container that implements JavaServer Faces technology.
Figure 7–1 Responding to a Client Request for a JavaServer Faces Page
Web Container
myfacelet.xhtml
Browser
Access page
(HTTP Request)
Generates
Component
Tree
Renders HTML
(HTTP Response)
myView
The web page, myfacelet.xhtml, is built using JavaServer Faces component tags.
Component tags are used to add components to the view (represented by myView in the
diagram), which is the server-side representation of the page. In addition to
components, the web page can also reference objects, such as the following:
■
■
Any event listeners, validators, and converters that are registered on the
components
The JavaBeans components that capture the data and process the
application-specific functionality of the components
7-2 The Java EE 7 Tutorial
JavaServer Faces Technology Benefits
On request from the client, the view is rendered as a response. Rendering is the
process whereby, based on the server-side view, the web container generates output,
such as HTML or XHTML, that can be read by the client, such as a browser.
7.2 JavaServer Faces Technology Benefits
One of the greatest advantages of JavaServer Faces technology is that it offers a clean
separation between behavior and presentation for web applications. A JavaServer
Faces application can map HTTP requests to component-specific event handling and
manage components as stateful objects on the server. JavaServer Faces technology
allows you to build web applications that implement the finer-grained separation of
behavior and presentation that is traditionally offered by client-side UI architectures.
The separation of logic from presentation also allows each member of a web
application development team to focus on a single piece of the development process
and provides a simple programming model to link the pieces. For example, page
authors with no programming expertise can use JavaServer Faces technology tags in a
web page to link to server-side objects without writing any scripts.
Another important goal of JavaServer Faces technology is to leverage familiar
component and web-tier concepts without limiting you to a particular scripting
technology or markup language. JavaServer Faces technology APIs are layered directly
on top of the Servlet API, as shown in Figure 7–2.
Figure 7–2 Java Web Application Technologies
JavaServer Faces
JavaServer Pages
Standard Tag Library
JavaServer Pages
Java Servlet
This layering of APIs enables several important application use cases, such as using
different presentation technologies, creating your own custom components directly
from the component classes, and generating output for various client devices.
Facelets technology, available as part of JavaServer Faces technology, is the preferred
presentation technology for building JavaServer Faces technology–based web
applications. For more information on Facelets technology features, see Chapter 8,
"Introduction to Facelets".
Facelets technology offers several advantages.
■
■
■
Code can be reused and extended for components through the templating and
composite component features.
You can use annotations to automatically register the managed bean as a resource
available for JavaServer Faces applications. In addition, implicit navigation rules
allow developers to quickly configure page navigation (see Navigation Model for
details). These features reduce the manual configuration process for applications.
Most important, JavaServer Faces technology provides a rich architecture for
managing component state, processing component data, validating user input,
and handling events.
JavaServer Faces Technology
7-3
A Simple JavaServer Faces Application
7.3 A Simple JavaServer Faces Application
JavaServer Faces technology provides an easy and user-friendly process for creating
web applications. Developing a simple JavaServer Faces application typically requires
the following tasks, which have already been described in A Web Module That Uses
JavaServer Faces Technology: The hello1 Example:
■
Creating web pages using component tags
■
Developing managed beans
■
Mapping the FacesServlet instance
The hello1 example includes a managed bean and two Facelets web pages. When
accessed by a client, the first web page asks the user for his or her name, and the
second page responds by providing a greeting.
For details on Facelets technology, see Chapter 8, "Introduction to Facelets". For details
on using EL expressions, see Chapter 9, "Expression Language". For details on the
JavaServer Faces programming model and building web pages using JavaServer Faces
technology, see Chapter 10, "Using JavaServer Faces Technology in Web Pages".
Every web application has a lifecycle. Common tasks, such as handling incoming
requests, decoding parameters, modifying and saving state, and rendering web pages
to the browser, are all performed during a web application lifecycle. Some web
application frameworks hide the details of the lifecycle from you, whereas others
require you to manage them manually.
By default, JavaServer Faces automatically handles most of the lifecycle actions for
you. However, it also exposes the various stages of the request lifecycle so that you can
modify or perform different actions if your application requirements warrant it.
The lifecycle of a JavaServer Faces application starts and ends with the following
activity: The client makes a request for the web page, and the server responds with the
page. The lifecycle consists of two main phases: Execute and Render.
During the Execute phase, several actions can take place.
■
The application view is built or restored.
■
The request parameter values are applied.
■
Conversions and validations are performed for component values.
■
Managed beans are updated with component values.
■
Application logic is invoked.
For a first (initial) request, only the view is built. For subsequent (postback) requests,
some or all of the other actions can take place.
In the Render phase, the requested view is rendered as a response to the client.
Rendering is typically the process of generating output, such as HTML or XHTML,
that can be read by the client, usually a browser.
The following short description of the example JavaServer Faces application passing
through its lifecycle summarizes the activity that takes place behind the scenes.
The hello1 example application goes through the following stages when it is deployed
on GlassFish Server.
1.
When the hello1 application is built and deployed on GlassFish Server, the
application is in an uninitiated state.
7-4 The Java EE 7 Tutorial
User Interface Component Model
2.
When a client makes an initial request for the index.xhtml web page, the hello1
Facelets application is compiled.
3.
The compiled Facelets application is executed, and a new component tree is
constructed for the hello1 application and placed in a FacesContext.
4.
The component tree is populated with the component and the managed bean
property associated with it, represented by the EL expression hello.name.
5.
A new view is built, based on the component tree.
6.
The view is rendered to the requesting client as a response.
7.
The component tree is destroyed automatically.
8.
On subsequent (postback) requests, the component tree is rebuilt, and the saved
state is applied.
For full details on the lifecycle, see The Lifecycle of a JavaServer Faces Application.
7.4 User Interface Component Model
In addition to the lifecycle description, an overview of JavaServer Faces architecture
provides better understanding of the technology.
JavaServer Faces components are the building blocks of a JavaServer Faces view. A
component can be a user interface (UI) component or a non-UI component.
JavaServer Faces UI components are configurable, reusable elements that compose the
user interfaces of JavaServer Faces applications. A component can be simple, such as a
button, or can be compound, such as a table composed of multiple components.
JavaServer Faces technology provides a rich, flexible component architecture that
includes the following:
■
A set of javax.faces.component.UIComponent classes for specifying the state and
behavior of UI components
■
A rendering model that defines how to render the components in various ways
■
A conversion model that defines how to register data converters onto a component
■
An event and listener model that defines how to handle component events
■
A validation model that defines how to register validators onto a component
This section briefly describes each of these pieces of the component architecture.
7.4.1 User Interface Component Classes
JavaServer Faces technology provides a set of UI component classes and associated
behavioral interfaces that specify all the UI component functionality, such as holding
component state, maintaining a reference to objects, and driving event handling and
rendering for a set of standard components.
The component classes are completely extensible, allowing component writers to
create their own custom components. See Chapter 15, "Creating Custom UI
Components and Other Custom Objects" for more information.
The abstract base class for all components is javax.faces.component.UIComponent.
JavaServer Faces UI component classes extend the UIComponentBase class (a subclass
of UIComponent), which defines the default state and behavior of a component. The
following set of component classes is included with JavaServer Faces technology.
JavaServer Faces Technology
7-5
User Interface Component Model
■
UIColumn: Represents a single column of data in a UIData component.
■
UICommand: Represents a control that fires actions when activated.
■
■
UIData: Represents a data binding to a collection of data represented by a
javax.faces.model.DataModel instance.
UIForm: Represents an input form to be presented to the user. Its child components
represent (among other things) the input fields to be included when the form is
submitted. This component is analogous to the form tag in HTML.
■
UIGraphic: Displays an image.
■
UIInput: Takes data input from a user. This class is a subclass of UIOutput.
■
UIMessage: Displays a localized error message.
■
UIMessages: Displays a set of localized error messages.
■
UIOutcomeTarget: Displays a link in the form of a link or a button.
■
UIOutput: Displays data output on a page.
■
UIPanel: Manages the layout of its child components.
■
UIParameter: Represents substitution parameters.
■
UISelectBoolean: Allows a user to set a boolean value on a control by selecting or
deselecting it. This class is a subclass of the UIInput class.
■
UISelectItem: Represents a single item in a set of items.
■
UISelectItems: Represents an entire set of items.
■
■
■
■
UISelectMany: Allows a user to select multiple items from a group of items. This
class is a subclass of the UIInput class.
UISelectOne: Allows a user to select one item from a group of items. This class is a
subclass of the UIInput class.
UIViewParameter: Represents the query parameters in a request. This class is a
subclass of the UIInput class.
UIViewRoot: Represents the root of the component tree.
In addition to extending UIComponentBase, the component classes also implement one
or more behavioral interfaces, each of which defines certain behavior for a set of
components whose classes implement the interface.
These behavioral interfaces, all defined in the javax.faces.component package unless
otherwise stated, are as follows.
■
■
■
■
■
ActionSource: Indicates that the component can fire an action event. This interface
is intended for use with components based on JavaServer Faces technology 1.1_01
and earlier versions. This interface is deprecated in JavaServer Faces 2.
ActionSource2: Extends ActionSource and therefore provides the same
functionality. However, it allows components to use the Expression Language (EL)
when they are referencing methods that handle action events.
EditableValueHolder: Extends ValueHolder and specifies additional features for
editable components, such as validation and emitting value-change events.
NamingContainer: Mandates that each component rooted at this component have a
unique ID.
StateHolder: Denotes that a component has state that must be saved between
requests.
7-6 The Java EE 7 Tutorial
User Interface Component Model
■
■
■
ValueHolder: Indicates that the component maintains a local value as well as the
option of accessing data in the model tier.
javax.faces.event.SystemEventListenerHolder: Maintains a list of
javax.faces.event.SystemEventListener instances for each type of
javax.faces.event.SystemEvent defined by that class.
javax.faces.component.behavior.ClientBehaviorHolder: Adds the ability to
attach javax.faces.component.behavior.ClientBehavior instances, such as a
reusable script.
UICommand implements ActionSource2 and StateHolder. UIOutput and component
classes that extend UIOutput implement StateHolder and ValueHolder. UIInput and
component classes that extend UIInput implement EditableValueHolder,
StateHolder, and ValueHolder. UIComponentBase implements StateHolder.
Only component writers will need to use the component classes and behavioral
interfaces directly. Page authors and application developers will use a standard
component by including a tag that represents it on a page. Most of the components can
be rendered in different ways on a page. For example, a UICommand component can be
rendered as a button or a link.
The next section explains how the rendering model works and how page authors can
choose to render the components by selecting the appropriate tags.
7.4.2 Component Rendering Model
The JavaServer Faces component architecture is designed such that the functionality of
the components is defined by the component classes, whereas the component
rendering can be defined by a separate renderer class. This design has several benefits,
including the following.
■
■
Component writers can define the behavior of a component once but create
multiple renderers, each of which defines a different way to render the component
to the same client or to different clients.
Page authors and application developers can change the appearance of a
component on the page by selecting the tag that represents the appropriate
combination of component and renderer.
A render kit defines how component classes map to component tags that are
appropriate for a particular client. The JavaServer Faces implementation includes a
standard HTML render kit for rendering to an HTML client.
The render kit defines a set of javax.faces.render.Renderer classes for each
component that it supports. Each Renderer class defines a different way to render the
particular component to the output defined by the render kit. For example, a
UISelectOne component has three different renderers. One of them renders the
component as a group of options. Another renders the component as a combo box. The
third one renders the component as a list box. Similarly, a UICommand component can
be rendered as a button or a link, using the h:commandButton or h:commandLink tag.
The command part of each tag corresponds to the UICommand class, specifying the
functionality, which is to fire an action. The Button or Link part of each tag
corresponds to a separate Renderer class that defines how the component appears on
the page.
Each custom tag defined in the standard HTML render kit is composed of the
component functionality (defined in the UIComponent class) and the rendering
attributes (defined by the Renderer class).
JavaServer Faces Technology
7-7
User Interface Component Model
The section Adding Components to a Page Using HTML Tag Library Tags lists all
supported component tags and illustrates how to use the tags in an example.
The JavaServer Faces implementation provides a custom tag library for rendering
components in HTML.
7.4.3 Conversion Model
A JavaServer Faces application can optionally associate a component with server-side
object data. This object is a JavaBeans component, such as a managed bean. An
application gets and sets the object data for a component by calling the appropriate
object properties for that component.
When a component is bound to an object, the application has two views of the
component's data.
■
■
The model view, in which data is represented as data types, such as int or long.
The presentation view, in which data is represented in a manner that can be read
or modified by the user. For example, a java.util.Date might be represented as a
text string in the format mm/dd/yy or as a set of three text strings.
The JavaServer Faces implementation automatically converts component data between
these two views when the bean property associated with the component is of one of
the types supported by the component's data. For example, if a UISelectBoolean
component is associated with a bean property of type java.lang.Boolean, the
JavaServer Faces implementation will automatically convert the component's data
from String to Boolean. In addition, some component data must be bound to
properties of a particular type. For example, a UISelectBoolean component must be
bound to a property of type boolean or java.lang.Boolean.
Sometimes you might want to convert a component's data to a type other than a
standard type, or you might want to convert the format of the data. To facilitate this,
JavaServer Faces technology allows you to register a javax.faces.convert.Converter
implementation on UIOutput components and components whose classes subclass
UIOutput. If you register the Converter implementation on a component, the
Converter implementation converts the component's data between the two views.
You can either use the standard converters supplied with the JavaServer Faces
implementation or create your own custom converter. Custom converter creation is
covered in Chapter 15, "Creating Custom UI Components and Other Custom Objects".
7.4.4 Event and Listener Model
The JavaServer Faces event and listener model is similar to the JavaBeans event model
in that it has strongly typed event classes and listener interfaces that an application can
use to handle events generated by components.
The JavaServer Faces specification defines three types of events: application events,
system events, and data-model events.
Application events are tied to a particular application and are generated by a
UIComponent. They represent the standard events available in previous versions of
JavaServer Faces technology.
An event object identifies the component that generated the event and stores
information about the event. To be notified of an event, an application must provide an
implementation of the listener class and must register it on the component that
generates the event. When the user activates a component, such as by clicking a
7-8 The Java EE 7 Tutorial
User Interface Component Model
button, an event is fired. This causes the JavaServer Faces implementation to invoke
the listener method that processes the event.
JavaServer Faces supports two kinds of application events: action events and
value-change events.
An action event (class javax.faces.event.ActionEvent) occurs when the user
activates a component that implements ActionSource. These components include
buttons and links.
A value-change event (class javax.faces.event.ValueChangeEvent) occurs when the
user changes the value of a component represented by UIInput or one of its subclasses.
An example is selecting a check box, an action that results in the component's value
changing to true. The component types that can generate these types of events are the
UIInput, UISelectOne, UISelectMany, and UISelectBoolean components.
Value-change events are fired only if no validation errors are detected.
Depending on the value of the immediate property (see The immediate Attribute) of
the component emitting the event, action events can be processed during the Invoke
Application phase or the Apply Request Values phase, and value-change events can be
processed during the Process Validations phase or the Apply Request Values phase.
System events are generated by an Object rather than a UIComponent. They are
generated during the execution of an application at predefined times. They are
applicable to the entire application rather than to a specific component.
A data-model event occurs when a new row of a UIData component is selected.
There are two ways to cause your application to react to action events or value-change
events that are emitted by a standard component:
■
■
Implement an event listener class to handle the event, and register the listener on
the component by nesting either an f:valueChangeListener tag or an
f:actionListener tag inside the component tag.
Implement a method of a managed bean to handle the event, and refer to the
method with a method expression from the appropriate attribute of the
component's tag.
See Implementing an Event Listener for information on how to implement an event
listener. See Registering Listeners on Components for information on how to register
the listener on a component.
See Writing a Method to Handle an Action Event and Writing a Method to Handle a
Value-Change Event for information on how to implement managed bean methods
that handle these events.
See Referencing a Managed Bean Method for information on how to refer to the
managed bean method from the component tag.
When emitting events from custom components, you must implement the appropriate
event class and manually queue the event on the component in addition to
implementing an event listener class or a managed bean method that handles the
event. Handling Events for Custom Components explains how to do this.
7.4.5 Validation Model
JavaServer Faces technology supports a mechanism for validating the local data of
editable components (such as text fields). This validation occurs before the
corresponding model data is updated to match the local value.
JavaServer Faces Technology
7-9
Navigation Model
Like the conversion model, the validation model defines a set of standard classes for
performing common data validation checks. The JavaServer Faces core tag library also
defines a set of tags that correspond to the standard
javax.faces.validator.Validator implementations. See Using the Standard
Validators for a list of all the standard validation classes and corresponding tags.
Most of the tags have a set of attributes for configuring the validator's properties, such
as the minimum and maximum allowable values for the component's data. The page
author registers the validator on a component by nesting the validator's tag within the
component's tag.
In addition to validators that are registered on the component, you can declare a
default validator that is registered on all UIInput components in the application. For
more information on default validators, see Using Default Validators.
The validation model also allows you to create your own custom validator and
corresponding tag to perform custom validation. The validation model provides two
ways to implement custom validation.
■
Implement a Validator interface that performs the validation.
■
Implement a managed bean method that performs the validation.
If you are implementing a Validator interface, you must also do the following.
■
■
Register the Validator implementation with the application.
Create a custom tag or use an f:validator tag to register the validator on the
component.
In the previously described standard validation model, the validator is defined for
each input component on a page. The Bean Validation model allows the validator to be
applied to all fields in a page. See Chapter 21, "Introduction to Bean Validation" and
Chapter 22, "Bean Validation: Advanced Topics" for more information on Bean
Validation.
7.5 Navigation Model
The JavaServer Faces navigation model makes it easy to define page navigation and to
handle any additional processing that is needed to choose the sequence in which pages
are loaded.
In JavaServer Faces technology, navigation is a set of rules for choosing the next page
or view to be displayed after an application action, such as when a button or link is
clicked.
Navigation can be implicit or user-defined. Implicit navigation comes into play when
user-defined navigation rules are not configured in the application configuration
resource files.
When you add a component such as a commandButton to a Facelets page, and assign
another page as the value for its action property, the default navigation handler will
try to match a suitable page within the application implicitly. In the following
example, the default navigation handler will try to locate a page named
response.xhtml within the application and navigate to it:
<h:commandButton value="submit" action="response">
User-defined navigation rules are declared in zero or more application configuration
resource files, such as faces-config.xml, by using a set of XML elements. The default
structure of a navigation rule is as follows:
7-10 The Java EE 7 Tutorial
Navigation Model
<navigation-rule>
<description></description
<from-view-id></from-view-id>
<navigation-case>
<from-action></from-action>
<from-outcome></from-outcome>
<if></if>
<to-view-id></to-view-id>
</navigation-case>
</navigation-rule>
User-defined navigation is handled as follows.
■
■
Define the rules in the application configuration resource file.
Refer to an outcome String from the button or link component's action attribute.
This outcome String is used by the JavaServer Faces implementation to select the
navigation rule.
Here is an example navigation rule:
<navigation-rule>
<from-view-id>/greeting.xhtml</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/response.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
This rule states that when a command component (such as an h:commandButton or an
h:commandLink) on greeting.xhtml is activated, the application will navigate from the
greeting.xhtml page to the response.xhtml page if the outcome referenced by the
button component's tag is success. Here is an h:commandButton tag from
greeting.xhtml that would specify a logical outcome of success:
<h:commandButton id="submit" value="Submit" action="success"/>
As the example demonstrates, each navigation-rule element defines how to get from
one page (specified in the from-view-id element) to the other pages of the application.
The navigation-rule elements can contain any number of navigation-case elements,
each of which defines the page to open next (defined by to-view-id) based on a
logical outcome (defined by from-outcome).
In more complicated applications, the logical outcome can also come from the return
value of an action method in a managed bean. This method performs some processing
to determine the outcome. For example, the method can check whether the password
the user entered on the page matches the one on file. If it does, the method might
return success; otherwise, it might return failure. An outcome of failure might
result in the logon page being reloaded. An outcome of success might cause the page
displaying the user's credit card activity to open. If you want the outcome to be
returned by a method on a bean, you must refer to the method using a method
expression with the action attribute, as shown by this example:
<h:commandButton id="submit" value="Submit"
action="#{cashierBean.submit}" />
When the user clicks the button represented by this tag, the corresponding component
generates an action event. This event is handled by the default
javax.faces.event.ActionListener instance, which calls the action method
referenced by the component that triggered the event. The action method returns a
logical outcome to the action listener.
JavaServer Faces Technology 7-11
Navigation Model
The listener passes the logical outcome and a reference to the action method that
produced the outcome to the default javax.faces.application.NavigationHandler.
The NavigationHandler selects the page to display next by matching the outcome or
the action method reference against the navigation rules in the application
configuration resource file by the following process.
1.
The NavigationHandler selects the navigation rule that matches the page
currently displayed.
2.
It matches the outcome or the action method reference that it received from the
default javax.faces.event.ActionListener with those defined by the navigation
cases.
3.
It tries to match both the method reference and the outcome against the same
navigation case.
4.
If the previous step fails, the navigation handler attempts to match the outcome.
5.
Finally, the navigation handler attempts to match the action method reference if
the previous two attempts failed.
6.
If no navigation case is matched, it displays the same view again.
When the NavigationHandler achieves a match, the Render Response phase begins.
During this phase, the page selected by the NavigationHandler will be rendered.
The Duke's Tutoring case study example application uses navigation rules in the
business methods that handle creating, editing, and deleting the users of the
application. For example, the form for creating a student has the following
h:commandButton tag:
<h:commandButton id="submit"
action="#{adminBean.createStudent(studentManager.newStudent)}"
value="#{bundle['action.submit']}"/>
The action event calls the dukestutoring.ejb.AdminBean.createStudent method:
public String createStudent(Student student) {
em.persist(student);
return "createdStudent";
}
The return value of createdStudent has a corresponding navigation case in the
faces-config.xml configuration file:
<navigation-rule>
<from-view-id>/admin/student/createStudent.xhtml</from-view-id>
<navigation-case>
<from-outcome>createdStudent</from-outcome>
<to-view-id>/admin/index.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
After the student is created, the user is returned to the Administration index page.
For more information on how to define navigation rules, see Configuring Navigation
Rules.
For more information on how to implement action methods to handle navigation, see
Writing a Method to Handle an Action Event.
For more information on how to reference outcomes or action methods from
component tags, see Referencing a Method That Performs Navigation.
7-12 The Java EE 7 Tutorial
The Lifecycle of a JavaServer Faces Application
7.6 The Lifecycle of a JavaServer Faces Application
The lifecycle of an application refers to the various stages of processing of that
application, from its initiation to its conclusion. All applications have lifecycles.
During a web application lifecycle, common tasks are performed, including the
following.
■
Handling incoming requests
■
Decoding parameters
■
Modifying and saving state
■
Rendering web pages to the browser
The JavaServer Faces web application framework manages lifecycle phases
automatically for simple applications or allows you to manage them manually for
more complex applications as required.
JavaServer Faces applications that use advanced features may require interaction with
the lifecycle at certain phases. For example, Ajax applications use partial processing
features of the lifecycle (see Partial Processing and Partial Rendering). A clearer
understanding of the lifecycle phases is key to creating well-designed components.
A simplified view of the JavaServer faces lifecycle, consisting of the two main phases
of a JavaServer Faces web application, is introduced in A Simple JavaServer Faces
Application. This section examines the JavaServer Faces lifecycle in more detail.
7.6.1 Overview of the JavaServer Faces Lifecycle
The lifecycle of a JavaServer Faces application begins when the client makes an HTTP
request for a page and ends when the server responds with the page, translated to
HTML.
The lifecycle can be divided into two main phases: Execute and Render. The Execute
phase is further divided into subphases to support the sophisticated component tree.
This structure requires that component data be converted and validated, component
events be handled, and component data be propagated to beans in an orderly fashion.
A JavaServer Faces page is represented by a tree of components, called a view. During
the lifecycle, the JavaServer Faces implementation must build the view while
considering the state saved from a previous submission of the page. When the client
requests a page, the JavaServer Faces implementation performs several tasks, such as
validating the data input of components in the view and converting input data to
types specified on the server side.
The JavaServer Faces implementation performs all these tasks as a series of steps in the
JavaServer Faces request-response lifecycle. Figure 7–3 illustrates these steps.
JavaServer Faces Technology 7-13
The Lifecycle of a JavaServer Faces Application
Figure 7–3 JavaServer Faces Standard Request-Response Lifecycle
Faces Request
Restore View
Apply Requests
Render Response
Process Events
Response
Complete
Process Validations
Validation/
Conversion Errors/
Render Response
Process Events
Response
Complete
Update Model Values
Conversion Errors/
Render Response
Process Events
Response
Complete
Invoke Application
Process Events
Response
Complete
Render Response
Faces Response
The request-response lifecycle handles two kinds of requests: initial requests and
postbacks. An initial request occurs when a user makes a request for a page for the
first time. A postback request occurs when a user submits the form contained on a
page that was previously loaded into the browser as a result of executing an initial
request.
When the lifecycle handles an initial request, it executes only the Restore View and
Render Response phases, because there is no user input or action to process.
Conversely, when the lifecycle handles a postback, it executes all of the phases.
Usually, the first request for a JavaServer Faces page comes in from a client, as a result
of clicking a link or button component on a JavaServer Faces page. To render a
response that is another JavaServer Faces page, the application creates a new view and
stores it in the javax.faces.context.FacesContext instance, which represents all of
the information associated with processing an incoming request and creating a
response. The application then acquires object references needed by the view and calls
the FacesContext.renderResponse method, which forces immediate rendering of the
view by skipping to the Render Response Phase of the lifecycle, as is shown by the
arrows labelled Render Response in Figure 7–3.
Sometimes, an application might need to redirect to a different web application
resource, such as a web service, or generate a response that does not contain
JavaServer Faces components. In these situations, the developer must skip the Render
Response phase by calling the FacesContext.responseComplete method. This
situation is also shown in Figure 7–3, with the arrows labelled Response Complete.
The most common situation is that a JavaServer Faces component submits a request
for another JavaServer Faces page. In this case, the JavaServer Faces implementation
7-14 The Java EE 7 Tutorial
The Lifecycle of a JavaServer Faces Application
handles the request and automatically goes through the phases in the lifecycle to
perform any necessary conversions, validations, and model updates and to generate
the response.
There is one exception to the lifecycle described in this section. When a component's
immediate attribute is set to true, the validation, conversion, and events associated
with these components are processed during the Apply Request Values Phase rather
than in a later phase.
The details of the lifecycle explained in the following sections are primarily intended
for developers who need to know information such as when validations, conversions,
and events are usually handled and ways to change how and when they are handled.
For more information on each of the lifecycle phases, download the latest JavaServer
Faces Specification documentation from
http://jcp.org/en/jsr/detail?id=344.
The JavaServer Faces application lifecycle Execute phase contains the following
subphases:
■
Restore View Phase
■
Apply Request Values Phase
■
Process Validations Phase
■
Update Model Values Phase
■
Invoke Application Phase
■
Render Response Phase
7.6.2 Restore View Phase
When a request for a JavaServer Faces page is made, usually by an action, such as
when a link or a button component is clicked, the JavaServer Faces implementation
begins the Restore View phase.
During this phase, the JavaServer Faces implementation builds the view of the page,
wires event handlers and validators to components in the view, and saves the view in
the FacesContext instance, which contains all the information needed to process a
single request. All the application's components, event handlers, converters, and
validators have access to the FacesContext instance.
If the request for the page is an initial request, the JavaServer Faces implementation
creates an empty view during this phase and the lifecycle advances to the Render
Response phase, during which the empty view is populated with the components
referenced by the tags in the page.
If the request for the page is a postback, a view corresponding to this page already
exists in the FacesContext instance. During this phase, the JavaServer Faces
implementation restores the view by using the state information saved on the client or
the server.
7.6.3 Apply Request Values Phase
After the component tree is restored during a postback request, each component in the
tree extracts its new value from the request parameters by using its decode
(processDecodes()) method. The value is then stored locally on each component.
If any decode methods or event listeners have called the renderResponse method on
the current FacesContext instance, the JavaServer Faces implementation skips to the
Render Response phase.
JavaServer Faces Technology 7-15
The Lifecycle of a JavaServer Faces Application
If any events have been queued during this phase, the JavaServer Faces
implementation broadcasts the events to interested listeners.
If some components on the page have their immediate attributes (see The immediate
Attribute) set to true, then the validations, conversions, and events associated with
these components will be processed during this phase. If any conversion fails, an error
message associated with the component is generated and queued on FacesContext.
This message will be displayed during the Render Response phase, along with any
validation errors resulting from the Process Validations phase.
At this point, if the application needs to redirect to a different web application resource
or generate a response that does not contain any JavaServer Faces components, it can
call the FacesContext.responseComplete method.
At the end of this phase, the components are set to their new values, and messages and
events have been queued.
If the current request is identified as a partial request, the partial context is retrieved
from the FacesContext, and the partial processing method is applied.
7.6.4 Process Validations Phase
During this phase, the JavaServer Faces implementation processes all validators
registered on the components in the tree by using its validate (processValidators)
method. It examines the component attributes that specify the rules for the validation
and compares these rules to the local value stored for the component. The JavaServer
Faces implementation also completes conversions for input components that do not
have the immediate attribute set to true.
If the local value is invalid, or if any conversion fails, the JavaServer Faces
implementation adds an error message to the FacesContext instance, and the lifecycle
advances directly to the Render Response phase so that the page is rendered again
with the error messages displayed. If there were conversion errors from the Apply
Request Values phase, the messages for these errors are also displayed.
If any validate methods or event listeners have called the renderResponse method on
the current FacesContext, the JavaServer Faces implementation skips to the Render
Response phase.
At this point, if the application needs to redirect to a different web application resource
or generate a response that does not contain any JavaServer Faces components, it can
call the FacesContext.responseComplete method.
If events have been queued during this phase, the JavaServer Faces implementation
broadcasts them to interested listeners.
If the current request is identified as a partial request, the partial context is retrieved
from the FacesContext, and the partial processing method is applied.
7.6.5 Update Model Values Phase
After the JavaServer Faces implementation determines that the data is valid, it
traverses the component tree and sets the corresponding server-side object properties
to the components' local values. The JavaServer Faces implementation updates only
the bean properties pointed at by an input component's value attribute. If the local
data cannot be converted to the types specified by the bean properties, the lifecycle
advances directly to the Render Response phase so that the page is re-rendered with
errors displayed. This is similar to what happens with validation errors.
7-16 The Java EE 7 Tutorial
Partial Processing and Partial Rendering
If any updateModels methods or any listeners have called the renderResponse method
on the current FacesContext instance, the JavaServer Faces implementation skips to
the Render Response phase.
At this point, if the application needs to redirect to a different web application resource
or generate a response that does not contain any JavaServer Faces components, it can
call the FacesContext.responseComplete method.
If any events have been queued during this phase, the JavaServer Faces
implementation broadcasts them to interested listeners.
If the current request is identified as a partial request, the partial context is retrieved
from the FacesContext, and the partial processing method is applied.
7.6.6 Invoke Application Phase
During this phase, the JavaServer Faces implementation handles any application-level
events, such as submitting a form or linking to another page.
At this point, if the application needs to redirect to a different web application resource
or generate a response that does not contain any JavaServer Faces components, it can
call the FacesContext.responseComplete method.
If the view being processed was reconstructed from state information from a previous
request and if a component has fired an event, these events are broadcast to interested
listeners.
Finally, the JavaServer Faces implementation transfers control to the Render Response
phase.
7.6.7 Render Response Phase
During this phase, JavaServer Faces builds the view and delegates authority to the
appropriate resource for rendering the pages.
If this is an initial request, the components that are represented on the page will be
added to the component tree. If this is not an initial request, the components are
already added to the tree and need not be added again.
If the request is a postback and errors were encountered during the Apply Request
Values phase, Process Validations phase, or Update Model Values phase, the original
page is rendered again during this phase. If the pages contain h:message or
h:messages tags, any queued error messages are displayed on the page.
After the content of the view is rendered, the state of the response is saved so that
subsequent requests can access it. The saved state is available to the Restore View
phase.
7.7 Partial Processing and Partial Rendering
The JavaServer Faces lifecycle spans all of the execute and render processes of an
application. It is also possible to process and render only parts of an application, such
as a single component. For example, the JavaServer Faces Ajax framework can
generate requests containing information on which particular component may be
processed and which particular component may be rendered back to the client.
Once such a partial request enters the JavaServer Faces lifecycle, the information is
identified and processed by a javax.faces.context.PartialViewContext object. The
JavaServer Faces lifecycle is still aware of such Ajax requests and modifies the
component tree accordingly.
JavaServer Faces Technology 7-17
Further Information about JavaServer Faces Technology
The execute and render attributes of the f:ajax tag are used to identify which
components may be executed and rendered. For more information on these attributes,
see Chapter 13, "Using Ajax with JavaServer Faces Technology".
7.8 Further Information about JavaServer Faces Technology
For more information on JavaServer Faces technology, see
■
JavaServer Faces 2.2 specification:
http://jcp.org/en/jsr/detail?id=344
■
JavaServer Faces project website:
https://javaserverfaces.java.net/
7-18 The Java EE 7 Tutorial
8
Introduction to Facelets
8
The term Facelets refers to the view declaration language for JavaServer Faces
technology. Facelets is a part of the JavaServer Faces specification and also the
preferred presentation technology for building JavaServer Faces technology–based
applications. JavaServer Pages (JSP) technology, previously used as the presentation
technology for JavaServer Faces, does not support all the new features available in
JavaServer Faces in the Java EE 7 platform. JSP technology is considered to be a
deprecated presentation technology for JavaServer Faces.
The following topics are addressed here:
■
What Is Facelets?
■
The Lifecycle of a Facelets Application
■
Developing a Simple Facelets Application: The guessnumber-jsf Example
Application
■
Using Facelets Templates
■
Composite Components
■
Web Resources
■
Relocatable Resources
■
Resource Library Contracts
■
HTML5-Friendly Markup
8.1 What Is Facelets?
Facelets is a powerful but lightweight page declaration language that is used to build
JavaServer Faces views using HTML style templates and to build component trees.
Facelets features include the following:
■
■
Use of XHTML for creating web pages
Support for Facelets tag libraries in addition to JavaServer Faces and JSTL tag
libraries
■
Support for the Expression Language (EL)
■
Templating for components and pages
The advantages of Facelets for large-scale development projects include the following:
■
■
Support for code reuse through templating and composite components
Functional extensibility of components and other server-side objects through
customization
Introduction to Facelets 8-1
What Is Facelets?
■
Faster compilation time
■
Compile-time EL validation
■
High-performance rendering
In short, the use of Facelets reduces the time and effort that needs to be spent on
development and deployment.
Facelets views are usually created as XHTML pages. JavaServer Faces
implementations support XHTML pages created in conformance with the XHTML
Transitional Document Type Definition (DTD), as listed at
http://www.w3.org/TR/xhtml1/#a_dtd_XHTML-1.0-Transitional. By
convention, web pages built with XHTML have an .xhtml extension.
JavaServer Faces technology supports various tag libraries to add components to a
web page. To support the JavaServer Faces tag library mechanism, Facelets uses XML
namespace declarations. Table 8–1 lists the tag libraries supported by Facelets.
Table 8–1
Tag Libraries Supported by Facelets
Tag Library
URI
Prefix
Example
Contents
JavaServer
Faces
Facelets Tag
Library
http://xmlns.jcp.org/jsf/facelets
ui:
ui:component
Tags for
templating
ui:insert
http://xmlns.jcp.org/jsf/html
JavaServer
Faces HTML
Tag Library
h:
h:head
h:body
h:outputText
h:inputText
JavaServer
Faces Core
Tag Library
JavaServer Faces
component tags
for all
UIComponent
objects
f:
f:actionListener Tags for
JavaServer Faces
f:attribute
custom actions
that are
independent of
any particular
render kit
Pass-through http://xmlns.jcp.org/jsf
Elements
Tag Library
jsf:
jsf:id
Tags to support
HTML5-friendly
markup
Pass-through http://xmlns.jcp.org/jsf/passthrough
Attributes
Tag Library
p:
p:type
Tags to support
HTML5-friendly
markup
Composite
Component
Tag Library
http://xmlns.jcp.org/jsf/composite
cc:
cc:interface
Tags to support
composite
components
JSTL Core
Tag Library
http://xmlns.jcp.org/jsp/jstl/core
c:
c:forEach
JSTL 1.2 Core
Tags
JSTL
Functions
Tag Library
http://xmlns.jcp.org/jsp/jstl/functions fn:
http://xmlns.jcp.org/jsf/core
c:catch
fn:toUpperCase
fn:toLowerCase
JSTL 1.2
Functions Tags
Facelets provides two namespaces to support HTML5-friendly markup. For details,
see HTML5-Friendly Markup.
8-2 The Java EE 7 Tutorial
Developing a Simple Facelets Application: The guessnumber-jsf Example Application
Facelets supports tags for composite components, for which you can declare custom
prefixes. For more information on composite components, see Composite
Components.
The namespace prefixes shown in the table are conventional, not mandatory. As is
always the case when you declare an XML namespace, you can specify any prefix in
your Facelets page. For example, you can declare the prefix for the composite
component tag library as
xmlns:composite="http://java.sun.com/jsf/composite"
instead of as
xmlns:cc="http://java.sun.com/jsf/composite"
Based on the JavaServer Faces support for Expression Language (EL) syntax, Facelets
uses EL expressions to reference properties and methods of managed beans. EL
expressions can be used to bind component objects or values to methods or properties
of managed beans that are used as backing beans. For more information on using EL
expressions, see Using the EL to Reference Managed Beans.
8.2 The Lifecycle of a Facelets Application
The JavaServer Faces specification defines the lifecycle of a JavaServer Faces
application. For more information on this lifecycle, see The Lifecycle of a JavaServer
Faces Application. The following steps describe that process as applied to a
Facelets-based application.
1.
When a client, such as a browser, makes a new request to a page that is created
using Facelets, a new component tree or javax.faces.component.UIViewRoot is
created and placed in the FacesContext.
2.
The UIViewRoot is applied to the Facelets, and the view is populated with
components for rendering.
3.
The newly built view is rendered back as a response to the client.
4.
On rendering, the state of this view is stored for the next request. The state of
input components and form data is stored.
5.
The client may interact with the view and request another view or change from the
JavaServer Faces application. At this time, the saved view is restored from the
stored state.
6.
The restored view is once again passed through the JavaServer Faces lifecycle,
which eventually will either generate a new view or re-render the current view if
there were no validation problems and no action was triggered.
7.
If the same view is requested, the stored view is rendered once again.
8.
If a new view is requested, then the process described in Step 2 is continued.
9.
The new view is then rendered back as a response to the client.
8.3 Developing a Simple Facelets Application: The guessnumber-jsf
Example Application
This section describes the general steps involved in developing a JavaServer Faces
application. The following tasks are usually required:
■
Developing the managed beans
Introduction to Facelets 8-3
Developing a Simple Facelets Application: The guessnumber-jsf Example Application
■
Creating the pages using the component tags
■
Defining page navigation
■
Mapping the FacesServlet instance
■
Adding managed bean declarations
8.3.1 Creating a Facelets Application
The example used in this tutorial is the guessnumber-jsf application. The application
presents you with a page that asks you to guess a number from 0 to 10, validates your
input against a random number, and responds with another page that informs you
whether you guessed the number correctly or incorrectly.
The source code for this application is in the
tut-install/examples/web/jsf/guessnumber-jsf/ directory.
8.3.1.1 Developing a Managed Bean
In a typical JavaServer Faces application, each page of the application connects to a
managed bean that serves as a backing bean. The backing bean defines the methods
and properties that are associated with the components. In this example, both pages
use the same backing bean.
The following managed bean class, UserNumberBean.java, generates a random
number from 0 to 10 inclusive:
package javaeetutorial.guessnumber;
import
import
import
import
java.io.Serializable;
java.util.Random;
javax.enterprise.context.SessionScoped;
javax.inject.Named;
@Named
@SessionScoped
public class UserNumberBean implements Serializable {
private static final long serialVersionUID = 5443351151396868724L;
Integer randomInt = null;
Integer userNumber = null;
String response = null;
private int maximum = 10;
private int minimum = 0;
public UserNumberBean() {
Random randomGR = new Random();
randomInt = new Integer(randomGR.nextInt(maximum + 1));
// Print number to server log
System.out.println("Duke's number: " + randomInt);
}
public void setUserNumber(Integer user_number) {
userNumber = user_number;
}
public Integer getUserNumber() {
return userNumber;
}
public String getResponse() {
8-4 The Java EE 7 Tutorial
Developing a Simple Facelets Application: The guessnumber-jsf Example Application
if ((userNumber == null) || (userNumber.compareTo(randomInt) != 0)) {
return "Sorry, " + userNumber + " is incorrect.";
} else {
return "Yay! You got it!";
}
}
public int getMaximum() {
return (this.maximum);
}
public void setMaximum(int maximum) {
this.maximum = maximum;
}
public int getMinimum() {
return (this.minimum);
}
public void setMinimum(int minimum) {
this.minimum = minimum;
}
}
Note the use of the @Named annotation, which makes the managed bean accessible
through the EL. The @SessionScoped annotation registers the bean scope as session to
enable you to make multiple guesses as you run the application.
8.3.1.2 Creating Facelets Views
To create a page or view, you add components to the pages, wire the components to
backing bean values and properties, and register converters, validators, or listeners on
the components.
For the example application, XHTML web pages serve as the front end. The first page
of the example application is a page called greeting.xhtml. A closer look at various
sections of this web page provides more information.
The first section of the web page declares the content type for the page, which is
XHTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
The next section specifies the language of the XHTML page and then declares the XML
namespace for the tag libraries that are used in the web page:
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
The next section uses various tags to insert components into the web page:
<h:head>
<h:outputStylesheet library="css" name="default.css"/>
<title>Guess Number Facelets Application</title>
</h:head>
<h:body>
<h:form>
<h:graphicImage value="#{resource['images:wave.med.gif']}"
Introduction to Facelets 8-5
Developing a Simple Facelets Application: The guessnumber-jsf Example Application
alt="Duke waving his hand"/>
<h2>
Hi, my name is Duke. I am thinking of a number from
#{userNumberBean.minimum} to #{userNumberBean.maximum}.
Can you guess it?
</h2>
<p><h:inputText id="userNo"
title="Enter a number from 0 to 10:"
value="#{userNumberBean.userNumber}">
<f:validateLongRange minimum="#{userNumberBean.minimum}"
maximum="#{userNumberBean.maximum}"/>
</h:inputText>
<h:commandButton id="submit" value="Submit"
action="response"/>
</p>
<h:message showSummary="true" showDetail="false"
style="color: #d20005;
font-family: 'New Century Schoolbook', serif;
font-style: oblique;
text-decoration: overline"
id="errors1"
for="userNo"/>
</h:form>
</h:body>
Note the use of the following tags:
■
Facelets HTML tags (those beginning with h:) to add components
■
The Facelets core tag f:validateLongRange to validate the user input
An h:inputText tag accepts user input and sets the value of the managed bean
property userNumber through the EL expression #{userNumberBean.userNumber}. The
input value is validated for value range by the JavaServer Faces standard validator tag
f:validateLongRange.
The image file, wave.med.gif, is added to the page as a resource, as is the style sheet.
For more details about the resources facility, see Web Resources.
An h:commandButton tag with the ID submit starts validation of the input data when a
user clicks the button. Using implicit navigation, the tag redirects the client to another
page, response.xhtml, which shows the response to your input. The page specifies
only response, which by default causes the server to look for response.xhtml.
You can now create the second page, response.xhtml, with the following content:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<h:outputStylesheet library="css" name="default.css"/>
<title>Guess Number Facelets Application</title>
</h:head>
<h:body>
<h:form>
<h:graphicImage value="#{resource['images:wave.med.gif']}"
alt="Duke waving his hand"/>
<h2>
8-6 The Java EE 7 Tutorial
Developing a Simple Facelets Application: The guessnumber-jsf Example Application
<h:outputText id="result" value="#{userNumberBean.response}"/>
</h2>
<h:commandButton id="back" value="Back" action="greeting"/>
</h:form>
</h:body>
</html>
This page also uses implicit navigation, setting the action attribute for the Back
button to send the user to the greeting.xhtml page.
8.3.2 Configuring the Application
Configuring a JavaServer Faces application involves mapping the Faces Servlet in the
web deployment descriptor file, such as a web.xml file, and possibly adding managed
bean declarations, navigation rules, and resource bundle declarations to the
application configuration resource file, faces-config.xml.
If you are using NetBeans IDE, a web deployment descriptor file is automatically
created for you. In such an IDE-created web.xml file, change the default greeting page,
which is index.xhtml, to greeting.xhtml. Here is an example web.xml file, showing
this change in bold.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>greeting.xhtml</welcome-file>
</welcome-file-list>
</web-app>
Note the use of the context parameter PROJECT_STAGE. This parameter identifies the
status of a JavaServer Faces application in the software lifecycle.
The stage of an application can affect the behavior of the application. For example, if
the project stage is defined as Development, debugging information is automatically
generated for the user. If not defined by the user, the default project stage is
Production.
Introduction to Facelets 8-7
Using Facelets Templates
8.3.3 Running the guessnumber-jsf Facelets Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
guessnumber-jsf example.
8.3.3.1 To Build, Package, and Deploy the guessnumber-jsf Example Using
NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsf
4.
Select the guessnumber-jsf folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the guessnumber-jsf project and select Build.
This option builds the example application and deploys it to your GlassFish Server
instance.
8.3.3.2 To Build, Package, and Deploy the guessnumber-jsf Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/jsf/guessnumber-jsf/
3.
Enter the following command:
mvn install
This command builds and packages the application into a WAR file,
guessnumber-jsf.war, that is located in the target directory. It then deploys it to
the server.
8.3.3.3 To Run the guessnumber-jsf Example
1.
Open a web browser.
2.
Enter the following URL in your web browser:
http://localhost:8080/guessnumber-jsf
3.
In the field, enter a number from 0 to 10 and click Submit.
Another page appears, reporting whether your guess is correct or incorrect.
4.
If you guessed incorrectly, click Back to return to the main page.
You can continue to guess until you get the correct answer, or you can look in the
server log, where the UserNumberBean constructor displays the correct answer.
8.4 Using Facelets Templates
JavaServer Faces technology provides the tools to implement user interfaces that are
easy to extend and reuse. Templating is a useful Facelets feature that allows you to
8-8 The Java EE 7 Tutorial
Using Facelets Templates
create a page that will act as the base, or template, for the other pages in an
application. By using templates, you can reuse code and avoid recreating similarly
constructed pages. Templating also helps in maintaining a standard look and feel in an
application with a large number of pages.
Table 8–2 lists Facelets tags that are used for templating and their respective
functionality.
Table 8–2
Facelets Templating Tags
Tag
Function
ui:component
Defines a component that is created and added to the component tree.
ui:composition
Defines a page composition that optionally uses a template. Content
outside of this tag is ignored.
ui:debug
Defines a debug component that is created and added to the component
tree.
ui:decorate
Similar to the composition tag but does not disregard content outside this
tag.
ui:define
Defines content that is inserted into a page by a template.
ui:fragment
Similar to the component tag but does not disregard content outside this
tag.
ui:include
Encapsulates and reuses content for multiple pages.
ui:insert
Inserts content into a template.
ui:param
Used to pass parameters to an included file.
ui:repeat
Used as an alternative for loop tags, such as c:forEach or h:dataTable.
ui:remove
Removes content from a page.
For more information on Facelets templating tags, see the documentation at
http://docs.oracle.com/javaee/7/javaserverfaces/2.2/vdldocs/face
lets/.
The Facelets tag library includes the main templating tag ui:insert. A template page
that is created with this tag allows you to define a default structure for a page. A
template page is used as a template for other pages, usually referred to as client pages.
Here is an example of a template saved as template.xhtml:
<!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://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8" />
<h:outputStylesheet library="css" name="default.css"/>
<h:outputStylesheet library="css" name="cssLayout.css"/>
<title>Facelets Template</title>
</h:head>
<h:body>
<div id="top" class="top">
<ui:insert name="top">Top Section</ui:insert>
</div>
Introduction to Facelets 8-9
Composite Components
<div>
<div id="left">
<ui:insert name="left">Left Section</ui:insert>
</div>
<div id="content" class="left_content">
<ui:insert name="content">Main Content</ui:insert>
</div>
</div>
</h:body>
</html>
The example page defines an XHTML page that is divided into three sections: a top
section, a left section, and a main section. The sections have style sheets associated
with them. The same structure can be reused for the other pages of the application.
The client page invokes the template by using the ui:composition tag. In the
following example, a client page named templateclient.xhtml invokes the template
page named template.xhtml from the preceding example. A client page allows
content to be inserted with the help of the ui:define tag.
<!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://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:body>
<ui:composition template="./template.xhtml">
<ui:define name="top">
Welcome to Template Client Page
</ui:define>
<ui:define name="left">
<h:outputLabel value="You are in the Left Section"/>
</ui:define>
<ui:define name="content">
<h:graphicImage value="#{resource['images:wave.med.gif']}"/>
<h:outputText value="You are in the Main Content Section"/>
</ui:define>
</ui:composition>
</h:body>
</html>
You can use NetBeans IDE to create Facelets template and client pages. For more
information on creating these pages, see
https://netbeans.org/kb/docs/web/jsf20-intro.html.
8.5 Composite Components
JavaServer Faces technology offers the concept of composite components with
Facelets. A composite component is a special type of template that acts as a
component.
Any component is essentially a piece of reusable code that behaves in a particular way.
For example, an input component accepts user input. A component can also have
validators, converters, and listeners attached to it to perform certain defined actions.
A composite component consists of a collection of markup tags and other existing
components. This reusable, user-created component has a customized, defined
8-10 The Java EE 7 Tutorial
Composite Components
functionality and can have validators, converters, and listeners attached to it like any
other component.
With Facelets, any XHTML page that contains markup tags and other components can
be converted into a composite component. Using the resources facility, the composite
component can be stored in a library that is available to the application from the
defined resources location.
Table 8–3 lists the most commonly used composite tags and their functions.
Table 8–3
Composite Component Tags
Tag
Function
composite:interface
Declares the usage contract for a composite component.
The composite component can be used as a single
component whose feature set is the union of the features
declared in the usage contract.
composite:implementation
Defines the implementation of the composite component.
If a composite:interface element appears, there must
be a corresponding composite:implementation.
composite:attribute
Declares an attribute that may be given to an instance of
the composite component in which this tag is declared.
composite:insertChildren
Any child components or template text within the
composite component tag in the using page will be
reparented into the composite component at the point
indicated by this tag's placement within the
composite:implementation section.
composite:valueHolder
Declares that the composite component whose contract is
declared by the composite:interface in which this
element is nested exposes an implementation of
ValueHolder suitable for use as the target of attached
objects in the using page.
composite:editableValueHolder
Declares that the composite component whose contract is
declared by the composite:interface in which this
element is nested exposes an implementation of
EditableValueHolder suitable for use as the target of
attached objects in the using page.
composite:actionSource
Declares that the composite component whose contract is
declared by the composite:interface in which this
element is nested exposes an implementation of
ActionSource2 suitable for use as the target of attached
objects in the using page.
For more information and a complete list of Facelets composite tags, see the
documentation at
http://docs.oracle.com/javaee/7/javaserverfaces/2.2/vdldocs/face
lets/.
The following example shows a composite component that accepts an email address as
input:
<!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:composite="http://xmlns.jcp.org/jsf/composite"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>This content will not be displayed</title>
Introduction to Facelets 8-11
Web Resources
</h:head>
<h:body>
<composite:interface>
<composite:attribute name="value" required="false"/>
</composite:interface>
<composite:implementation>
<h:outputLabel value="Email id: "></h:outputLabel>
<h:inputText value="#{cc.attrs.value}"></h:inputText>
</composite:implementation>
</h:body>
</html>
Note the use of cc.attrs.value when defining the value of the inputText component.
The word cc in JavaServer Faces is a reserved word for composite components. The
#{cc.attrs.attribute-name} expression is used to access the attributes defined for the
composite component's interface, which in this case happens to be value.
The preceding example content is stored as a file named email.xhtml in a folder
named resources/emcomp, under the application web root directory. This directory is
considered a library by JavaServer Faces, and a component can be accessed from such
a library. For more information on resources, see Web Resources.
The web page that uses this composite component is generally called a using page.
The using page includes a reference to the composite component, in the xml
namespace declarations:
<!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://xmlns.jcp.org/jsf/html"
xmlns:em="http://xmlns.jcp.org/jsf/composite/emcomp">
<h:head>
<title>Using a sample composite component</title>
</h:head>
<body>
<h:form>
<em:email value="Enter your email id" />
</h:form>
</body>
</html>
The local composite component library is defined in the xmlns namespace with the
declaration xmlns:em="http://xmlns.jcp.org/jsf/composite/emcomp". The
component itself is accessed through the em:email tag. The preceding example content
can be stored as a web page named emuserpage.xhtml under the web root directory.
When compiled and deployed on a server, it can be accessed with the following URL:
http://localhost:8080/application-name/emuserpage.xhtml
See Chapter 14, "Composite Components: Advanced Topics and an Example," for more
information and an example.
8.6 Web Resources
Web resources are any software artifacts that the web application requires for proper
rendering, including images, script files, and any user-created component libraries.
Resources must be collected in a standard location, which can be one of the following.
8-12 The Java EE 7 Tutorial
Relocatable Resources
■
■
A resource packaged in the web application root must be in a subdirectory of a
resources directory at the web application root: resources/resource-identifier.
A resource packaged in the web application's classpath must be in a subdirectory
of the META-INF/resources directory within a web application:
META-INF/resources/resource-identifier. You can use this file structure to package
resources in a JAR file bundled in the web application.
The JavaServer Faces runtime will look for the resources in the preceding listed
locations, in that order.
Resource identifiers are unique strings that conform to the following format (all on one
line):
[locale-prefix/][library-name/][library-version/]resource-name[/resource-version]
Elements of the resource identifier in brackets ([]) are optional, indicating that only a
resource-name, which is usually a file name, is a required element. For example, the
most common way to specify a style sheet, image, or script is to use the library and
name attributes, as in the following tag from the guessnumber-jsf example:
<h:outputStylesheet library="css" name="default.css"/>
This tag specifies that the default.css style sheet is in the directory
web/resources/css.
You can also specify the location of an image using the following syntax, also from the
guessnumber-jsf example:
<h:graphicImage value="#{resource['images:wave.med.gif']}"/>
This tag specifies that the image named wave.med.gif is in the directory
web/resources/images.
Resources can be considered as a library location. Any artifact, such as a composite
component or a template that is stored in the resources directory, becomes accessible
to the other application components, which can use it to create a resource instance.
8.7 Relocatable Resources
You can place a resource tag in one part of a page and specify that it be rendered in
another part of the page. To do this, you use the target attribute of a tag that specifies
a resource. Acceptable values for this attribute are as follows.
■
"head" renders the resource in the head element.
■
"body" renders the resource in the body element.
■
"form" renders the resource in the form element.
For example, the following h:outputScript tag is placed within an h:form element,
but it renders the JavaScript in the head element:
<h:form>
<h:outputScript name="myscript.js" library="mylibrary" target="head"/>
</h:form>
The h:outputStylesheet tag also supports resource relocation, in a similar way.
Relocatable resources are essential for composite components that use stylesheets and
can also be useful for composite components that use JavaScript. See The
compositecomponentexample Example Application for an example.
Introduction to Facelets 8-13
Resource Library Contracts
8.8 Resource Library Contracts
Resource library contracts allow you to define a different look and feel for different
parts of one or more applications, instead of either having to use the same look and
feel for all or having to specify a different look on a page-by-page basis.
To do this, you create a contracts section of your web application. Within the
contracts section, you can specify any number of named areas, each of which is called
a contract. Within each contract you can specify resources such as template files,
stylesheets, JavaScript files, and images.
For example, you could specify two contracts named c1 and c2, each of which uses a
template and other files:
src/main/webapp
WEB-INF/
contracts
c1
template.xhtml
style.css
myImg.gif
myJS.js
c2
template.xhtml
style2.css
img2.gif
JS2.js
index.xhtml
...
One part of the application can use c1, while another can use c2.
Another way to use contracts is to specify a single contract that contains multiple
templates:
src/main/webapp
contracts
myContract
template1.xhtml
template2.xhtml
style.css
img.png
img2.png
You can package a resource library contract in a JAR file for reuse in different
applications. If you do so, the contracts must be located under META-INF/contracts.
You can then place the JAR file in the WEB-INF/lib directory of an application. This
means that the application would be organized as follows:
src/main/webapp/
WEB-INF/lib/myContract.jar
...
You can specify the contract usage within an application's faces-config.xml file,
under the resource-library-contracts element. You need to use this element only if
your application uses more than one contract, however.
8-14 The Java EE 7 Tutorial
Resource Library Contracts
8.8.1 The hello1-rlc Example Application
The hello1-rlc example modifies the simple hello1 example from A Web Module
That Uses JavaServer Faces Technology: The hello1 Example to use two resource
library contracts. Each of the two pages in the application uses a different contract.
The managed bean for hello1-rlc, Hello.java, is identical to the one for hello1
(except that it replaces the @Named and @RequestScoped annotations with @Model).
The source code for this application is in the
tut-install/examples/web/jsf/hello1-rlc/ directory.
8.8.1.1 Configuring the hello1-rlc Example
The faces-config.xml file for the hello1-rlc example contains the following
elements:
<resource-library-contracts>
<contract-mapping>
<url-pattern>/reply/*</url-pattern>
<contracts>reply</contracts>
</contract-mapping>
<contract-mapping>
<url-pattern>*</url-pattern>
<contracts>hello</contracts>
</contract-mapping>
</resource-library-contracts>
The contract-mapping elements within the resource-library-contracts element
map each contract to a different set of pages within the application. One contract,
named reply, is used for all pages under the reply area of the application (/reply/*).
The other contract, hello, is used for all other pages in the application (*).
The application is organized as follows:
hello1-rlc
pom.xml
src/main/java/javaeetutorial/hello1rlc/Hello.java
src/main/webapp
WEB-INF
faces-config.xml
web.xml
contracts
hello
default.css
duke.handsOnHips.gif
template.xhtml
reply
default.css
duke.thumbsup.gif
template.xhtml
reply
response.xhtml
greeting.xhtml
The web.xml file specifies the welcome-file as greeting.xhtml. Because it is not
located under src/main/webapp/reply, this Facelets page uses the hello contract,
whereas src/main/webapp/reply/response.xhtml uses the reply contract.
Introduction to Facelets 8-15
Resource Library Contracts
8.8.1.2 The Facelets Pages for the hello1-rlc Example
The greeting.xhtml and response.xhtml pages have identical code calling in their
templates:
<ui:composition template="/template.xhtml">
The template.xhtml files in the hello and reply contracts differ only in two respects:
the placeholder text for the title element ("Hello Template" and "Reply Template")
and the graphic that each specifies.
The default.css stylesheets in the two contracts differ in only one respect: the
background color specified for the body element.
8.8.1.3 To Build, Package, and Deploy the hello1-rlc Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsf
4.
Select the hello1-rlc folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the hello1-rlc project and select Build.
This option builds the example application and deploys it to your GlassFish Server
instance.
8.8.1.4 To Build, Package, and Deploy the hello1-rlc Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/jsf/hello1-rlc/
3.
Enter the following command:
mvn install
This command builds and packages the application into a WAR file,
hello1-rlc.war, that is located in the target directory. It then deploys it to your
GlassFish Server instance.
8.8.1.5 To Run the hello1-rlc Example
1.
Enter the following URL in your web browser:
http://localhost:8080/hello1-rlc
2.
The greeting.xhtml page looks just like the one from hello1 except for its
background color and graphic.
3.
In the text field, enter your name and click Submit.
4.
The response page also looks just like the one from hello1 except for its
background color and graphic.
8-16 The Java EE 7 Tutorial
HTML5-Friendly Markup
The page displays the name you submitted. Click Back to return to the
greeting.xhtml page.
8.9 HTML5-Friendly Markup
When you want to produce user interface features for which HTML does not have its
own elements, you can create a custom JavaServer Faces component and insert it in
your Facelets page. This mechanism can cause a simple element to create complex web
code. However, creating such a component is a significant task (see Chapter 15,
"Creating Custom UI Components and Other Custom Objects").
HTML5 offers new elements and attributes that can make it unnecessary to write your
own components. It also provides many new capabilities for existing components.
JavaServer Faces technology supports HTML5 not by introducing new UI components
that imitate HTML5 ones but by allowing you to use HTML5 markup directly. It also
allows you to use JavaServer Faces attributes within HTML5 elements. JavaServer
Faces technology support for HTML5 falls into two categories:
■
Pass-through elements
■
Pass-through attributes
The effect of the HTML5-friendly markup feature is to offer the Facelets page author
almost complete control over the rendered page output, rather than having to pass this
control off to component authors. You can mix and match JavaServer Faces and
HTML5 components and elements as you see fit.
8.9.1 Using Pass-Through Elements
Pass-through elements allow you to use HTML5 tags and attributes but to treat them
as equivalent to JavaServer Faces components associated with a server-side
UIComponent instance.
To make an element that is not a JavaServer Faces element a pass-through element,
specify at least one of its attributes using the http://xmlns.jcp.org/jsf namespace.
For example, the following code declares the namespace with the short name jsf:
<html ... xmlns:jsf="http://xmlns.jcp.org/jsf"
...
<input type="email" jsf:id="email" name="email"
value="#{reservationBean.email}" required="required"/>
Here, the jsf prefix is placed on the id attribute so that the HTML5 input tag's
attributes are treated as part of the Facelets page. This means that, for example, you
can use EL expressions to retrieve managed bean properties.
Table 8–4 shows how pass-through elements are rendered as Facelets tags. The JSF
implementation uses the element name and the identifying attribute to determine the
corresponding Facelets tag that will be used in the server-side processing. The
browser, however, interprets the markup that the page author has written.
Table 8–4
How Facelets Renders HTML5 Elements
HTML5 Element Name
Identifying Attribute
Facelets Tag
a
jsf:action
h:commandLink
a
jsf:actionListener
h:commandLink
a
jsf:value
h:outputLink
a
jsf:outcome
h:link
Introduction to Facelets 8-17
HTML5-Friendly Markup
Table 8–4 (Cont.) How Facelets Renders HTML5 Elements
HTML5 Element Name
Identifying Attribute
Facelets Tag
body
h:body
button
h:commandButton
button
jsf:outcome
h:button
form
h:form
head
h:head
img
h:graphicImage
input
type="button"
h:commandButton
input
type="checkbox"
h:selectBooleanCheckbox
input
type="color"
h:inputText
input
type="date"
h:inputText
input
type="datetime"
h:inputText
input
type="datetime-local"
h:inputText
input
type="email"
h:inputText
input
type="month"
h:inputText
input
type="number"
h:inputText
input
type="range"
h:inputText
input
type="search"
h:inputText
input
type="time"
h:inputText
input
type="url"
h:inputText
input
type="week"
h:inputText
input
type="file"
h:inputFile
input
type="hidden"
h:inputHidden
input
type="password"
h:inputSecret
input
type="reset"
h:commandButton
input
type="submit"
h:commandButton
input
type="*"
h:inputText
label
h:outputLabel
link
h:outputStylesheet
script
h:outputScript
select
multiple="*"
h:selectManyListbox
select
h:selectOneListbox
textarea
h:inputTextArea
8.9.2 Using Pass-Through Attributes
Pass-through attributes are the converse of pass-through elements. They allow you to
pass attributes that are not JavaServer Faces attributes through to the browser without
interpretation. If you specify a pass-through attribute in a JavaServer Faces
UIComponent, the attribute name and value are passed straight through to the browser
8-18 The Java EE 7 Tutorial
HTML5-Friendly Markup
without being interpreted by JavaServer Faces components or renderers. There are
several ways to specify pass-through attributes.
■
Use the JavaServer Faces namespace for pass-through attributes to prefix the
attribute names within a JavaServer Faces component. For example, the following
code declares the namespace with the short name p, then passes the type, min, max,
required, and title attributes through to the HTML5 input component:
<html ... xmlns:p="http://xmlns.jcp.org/jsf/passthrough"
...
<h:form prependId="false">
<h:inputText id="nights" p:type="number" value="#{bean.nights}"
p:min="1" p:max="30" p:required="required"
p:title="Enter a number between 1 and 30 inclusive.">
...
This will cause the following markup to be rendered (assuming that bean.nights
has a default value set to 1):
<input id="nights" type="number" value="1" min="1" max="30"
required="required"
title="Enter a number between 1 and 30 inclusive.">
■
To pass a single attribute, nest the f:passThroughAttribute tag within a
component tag. For example:
<h:inputText value="#{user.email}">
<f:passThroughAttribute name="type" value="email" />
</h:inputText>
This code would be rendered similarly to the following:
<input value="me@me.com" type="email" />
■
To pass a group of attributes, nest the f:passThroughAttributes tag within a
component tag, specifying an EL value that must evaluate to a Map<String,
Object>. For example:
<h:inputText value="#{bean.nights">
<f:passThroughAttributes value="#{bean.nameValuePairs}" />
</h:inputText>
If the bean used the following Map declaration and initialized the map in the
constructor as follows, the markup would be similar to the output of the code that
uses the pass-through attribute namespace:
private Map<String, Object> nameValuePairs;
...
public Bean() {
this.nameValuePairs = new HashMap<>();
this.nameValuePairs.put("type", "number");
this.nameValuePairs.put("min", "1");
this.nameValuePairs.put("max", "30");
this.nameValuePairs.put("required", "required");
this.nameValuePairs.put("title",
"Enter a number between 1 and 4 inclusive.");
}
Introduction to Facelets 8-19
HTML5-Friendly Markup
8.9.3 The reservation Example Application
The reservation example application provides a set of HTML5 input elements of
various types to simulate purchasing tickets for a theatrical event. It consists of two
Facelets pages, reservation.xhtml and confirmation.xhtml, and a backing bean,
ReservationBean.java. The pages use both pass-through attributes and pass-through
elements.
The source code for this application is in the
tut-install/examples/web/jsf/reservation/ directory.
8.9.3.1 The Facelets Pages for the reservation Application
The first important feature of the Facelets pages for the reservation application is the
DOCTYPE header. Most Facelets pages in JavaServer Faces applications refer to the
XHTML DTD. The facelets pages for this application begin simply with the following
DOCTYPE header, which indicates an HTML5 page:
<!DOCTYPE html>
The namespace declarations in the html element of the reservation.xhtml page
specify both the jsf and the passthrough namespaces:
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://xmlns.jcp.org/jsf/passthrough"
xmlns:jsf="http://xmlns.jcp.org/jsf">
Next, an empty h:head tag followed by an h:outputStylesheet tag within the h:body
tag illustrates the use of a relocatable resource (as described in Relocatable Resources):
<h:head>
</h:head>
<h:body>
<h:outputStylesheet name="css/stylesheet.css" target="head"/>
The reservation.xhtml page uses pass-through elements for most of the form fields
on the page. This allows it to use some HTML5-specific input element types, such as
date and email. For example, the following element renders both a date format and a
calendar from which you can choose a date. The jsf prefix on the id attribute makes
the element a pass-through one:
<input type="date" jsf:id="date" name="date"
value="#{reservationBean.date}" required="required"
title="Enter or choose a date."/>
The field for the number of tickets, however, uses the h:passThroughAttributes tag to
pass a Map defined in the managed bean. It also recalculates the total in response to a
change in the field:
<h:inputText id="tickets" value="#{reservationBean.tickets}">
<f:passThroughAttributes value="#{reservationBean.ticketAttrs}"/>
<f:ajax event="change" render="total"
listener="#{reservationBean.calculateTotal}"/>
</h:inputText>
The field for the price specifies the number type as a pass-through attribute of the
h:inputText element, offering a range of four ticket prices. Here, the p prefix on the
8-20 The Java EE 7 Tutorial
HTML5-Friendly Markup
HTML5 attributes passes them through to the browser uninterpreted by the JavaServer
Faces input component:
<h:inputText id="price" p:type="number"
value="#{reservationBean.price}"
p:min="80" p:max="120"
p:step="20" p:required="required"
p:title="Enter a price: 80, 100, 120, or 140.">
<f:ajax event="change" render="total"
listener="#{reservationBean.calculateTotal}"/>
</h:inputText>
The output of the calculateTotal method that is specified as the listener for the Ajax
event is rendered in the output element whose id and name value is total. See
Chapter 13, "Using Ajax with JavaServer Faces Technology", for more information.
The second Facelets page, confirmation.xhtml, uses a pass-through output element
to display the values entered by the user and provides a Facelets h:commandButton tag
to allow the user to return to the reservation.xhtml page.
8.9.3.2 The Managed Bean for the reservation Application
The session-scoped managed bean for the reservation application,
ReservationBean.java, contains properties for all the elements on the Facelets pages.
It also contains two methods, calculateTotal and clear, that act as listeners for Ajax
events on the reservation.xhtml page.
8.9.3.3 To Build, Package, and Deploy the reservation Example Using NetBeans
IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsf
4.
Select the reservation folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the reservation project and select Build.
This option builds the example application and deploys it to your GlassFish Server
instance.
8.9.3.4 To Build, Package, and Deploy the reservation Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/jsf/reservation/
3.
Enter the following command:
mvn install
Introduction to Facelets 8-21
HTML5-Friendly Markup
This command builds and packages the application into a WAR file,
reservation.war, that is located in the target directory. It then deploys the WAR
file to your GlassFish Server instance.
8.9.3.5 To Run the reservation Example
At the time of the publication of this tutorial, the browser that most fully implements
HTML5 is Google Chrome, and it is recommended that you use it to run this example.
Other browsers are catching up, however, and may work equally well by the time you
read this.
1.
Enter the following URL in your web browser:
http://localhost:8080/reservation
2.
Enter information in the fields of the reservation.xhtml page.
The Performance Date field has a date field with up and down arrows that allow
you to increment and decrement the month, day, and year as well as a larger down
arrow that brings up a date editor in calendar form.
The Number of Tickets and Ticket Price fields also have up and down arrows
that allow you to increment and decrement the values within the allowed range
and steps. The Estimated Total changes when you change either of these two
fields.
Email addresses and dates are checked for format, but not for validity (you can
make a reservation for a past date, for instance).
3.
Click Make Reservation to complete the reservation or Clear to restore the fields
to their default values.
4.
If you click Make Reservation, the confirmation.xhtml page appears, displaying
the submitted values.
Click Back to return to the reservation.xhtml page.
8-22 The Java EE 7 Tutorial
9
Expression Language
9
This chapter introduces the Expression Language (also referred to as the EL), which
provides an important mechanism for enabling the presentation layer (web pages) to
communicate with the application logic (managed beans). The EL is used by several
JavaEE technologies, such as JavaServer Faces technology, JavaServer Pages (JSP)
technology, and Contexts and Dependency Injection for Java EE (CDI). The EL can also
be used in stand-alone environments. This chapter only covers the use of the EL in
Java EE containers.
The following topics are addressed here:
■
Overview of the EL
■
Immediate and Deferred Evaluation Syntax
■
Value and Method Expressions
■
Operations on Collection Objects
■
Operators
■
Reserved Words
■
Examples of EL Expressions
■
Further Information about the Expression Language
9.1 Overview of the EL
The EL allows page authors to use simple expressions to dynamically access data from
JavaBeans components. For example, the test attribute of the following conditional
tag is supplied with an EL expression that compares 0 with the number of items in the
session-scoped bean named cart.
<c:if test="${sessionScope.cart.numberOfItems > 0}">
...
</c:if>
See Using the EL to Reference Managed Beans for more information on how to use the
EL in JavaServer Faces applications.
To summarize, the EL provides a way to use simple expressions to perform the
following tasks:
■
Dynamically read application data stored in JavaBeans components, various data
structures, and implicit objects
■
Dynamically write data, such as user input into forms, to JavaBeans components
■
Invoke arbitrary static and public methods
Expression Language 9-1
Immediate and Deferred Evaluation Syntax
■
Dynamically perform arithmetic, boolean, and string operations
■
Dynamically construct collection objects and perform operations on collections
In a JavaServer Faces page, an EL expression can be used either in static text or in the
attribute of a custom tag or standard action.
Finally, the EL provides a pluggable API for resolving expressions so that custom
resolvers that can handle expressions not already supported by the EL can be
implemented.
9.2 Immediate and Deferred Evaluation Syntax
The EL supports both immediate and deferred evaluation of expressions. Immediate
evaluation means that the expression is evaluated and the result returned as soon as
the page is first rendered. Deferred evaluation means that the technology using the
expression language can use its own machinery to evaluate the expression sometime
later during the page's lifecycle, whenever it is appropriate to do so.
Those expressions that are evaluated immediately use the ${} syntax. Expressions
whose evaluation is deferred use the #{} syntax.
Because of its multiphase lifecycle, JavaServer Faces technology uses mostly deferred
evaluation expressions. During the lifecycle, component events are handled, data is
validated, and other tasks are performed in a particular order. Therefore, a JavaServer
Faces implementation must defer evaluation of expressions until the appropriate point
in the lifecycle.
Other technologies using the EL might have different reasons for using deferred
expressions.
9.2.1 Immediate Evaluation
All expressions using the ${} syntax are evaluated immediately. These expressions can
appear as part of a template (static) text or as the value of a tag attribute that can
accept runtime expressions.
The following example shows a tag whose value attribute references an immediate
evaluation expression that updates the quantity of books retrieved from the backing
bean named catalog:
<h:outputText value="${catalog.bookQuantity}" />
The JavaServer Faces implementation evaluates the expression
${catalog.bookQuantity}, converts it, and passes the returned value to the tag
handler. The value is updated on the page.
9.2.2 Deferred Evaluation
Deferred evaluation expressions take the form #{expr} and can be evaluated at other
phases of a page lifecycle as defined by whatever technology is using the expression.
In the case of JavaServer Faces technology, its controller can evaluate the expression at
different phases of the lifecycle, depending on how the expression is being used in the
page.
The following example shows a JavaServer Faces h:inputText tag, which represents a
field component into which a user enters a value. The h:inputText tag's value
attribute references a deferred evaluation expression that points to the name property
of the customer bean:
9-2 The Java EE 7 Tutorial
Value and Method Expressions
<h:inputText id="name" value="#{customer.name}" />
For an initial request of the page containing this tag, the JavaServer Faces
implementation evaluates the #{customer.name} expression during the
render-response phase of the lifecycle. During this phase, the expression merely
accesses the value of name from the customer bean, as is done in immediate evaluation.
For a postback request, the JavaServer Faces implementation evaluates the expression
at different phases of the lifecycle, during which the value is retrieved from the
request, validated, and propagated to the customer bean.
As shown in this example, deferred evaluation expressions can be
■
Value expressions that can be used to both read and write data
■
Method expressions
Value expressions (both immediate and deferred) and method expressions are
explained in the next section.
9.3 Value and Method Expressions
The EL defines two kinds of expressions: value expressions and method expressions.
Value expressions can be evaluated to yield a value, and method expressions are used
to reference a method.
9.3.1 Value Expressions
Value expressions can be further categorized into rvalue and lvalue expressions. An
lvalue expression can specify a target, such as an object, a bean property, or elements
of a collection, that can be assigned a value. An rvalue expression cannot specify such
a target.
All expressions that are evaluated immediately use the ${} delimiters, and although
the expression can be an lvalue expression, no assignments will ever happen.
Expressions whose evaluation can be deferred use the #{} delimiters and can act as
both rvalue and lvalue expressions; if the expression is an lvalue expression, it can be
assigned a new value. Consider the following two value expressions:
${customer.name}
#{customer.name}
The former uses immediate evaluation syntax, whereas the latter uses deferred
evaluation syntax. The first expression accesses the name property, gets its value, and
passes the value to the tag handler. With the second expression, the tag handler can
defer the expression evaluation to a later time in the page lifecycle if the technology
using this tag allows.
In the case of JavaServer Faces technology, the latter tag's expression is evaluated
immediately during an initial request for the page. During a postback request, this
expression can be used to set the value of the name property with user input.
9.3.1.1 Referencing Objects
A top-level identifier (such as customer in the expression customer.name) can refer to
the following objects:
■
Lambda parameters
■
EL variables
Expression Language 9-3
Value and Method Expressions
■
Managed beans
■
Implicit objects
■
Classes of static fields and methods
To refer to these objects, you write an expression using a variable that is the name of
the object. The following expression references a managed bean called customer:
${customer}
You can use a custom EL resolver to alter the way variables are resolved. For instance,
you can provide an EL resolver that intercepts objects with the name customer, so that
${customer} returns a value in the EL resolver instead. (JavaServer Faces technology
uses an EL resolver to handle managed beans.)
An enum constant is a special case of a static field, and you can reference such a
constant directly. For example, consider this enum class:
public enum Suit {hearts, spades, diamonds, clubs}
In the following expression, in which mySuit is an instance of Suit, you can compare
suit.hearts to the instance:
${mySuit == suit.hearts}
9.3.1.2 Referencing Object Properties or Collection Elements
To refer to properties of a bean, static fields or methods of a class, or items of a
collection, you use the . or [] notation. The same syntax can be used for attributes of
an implicit object, because attributes are placed in a map.
To reference the name property of the customer bean, use either the expression
${customer.name} or the expression ${customer["name"]}. Here, the part inside the
brackets is a String literal that is the name of the property to reference. The [] syntax
is more general than the . syntax, because the part inside the brackets can be any
String expression, not just literals.
You can use double or single quotes for the String literal. You can also combine the []
and . notations, as shown here:
${customer.address["street"]}
You can reference a static field or method using the syntax classname.field, as in the
following example:
Boolean.FALSE
The classname is the name of the class without the package name. By default, all the
java.lang packages are imported. You can import other packages, classes, and static
fields as needed.
If you are accessing an item in an array or list, you must use the [] notation and
specify an index in the array or list. The index is an expression that can be converted to
int. The following example references the first of the customer orders, assuming that
customer.orders is a List:
${customer.orders[1]}
If you are accessing an item in a Map, you must specify the key for the Map. If the key is
a String literal, the dot (.) notation can be used. Assuming that customer.orders is a
Map with a String key, the following examples reference the item with the key
"socks":
9-4 The Java EE 7 Tutorial
Value and Method Expressions
${customer.orders["socks"]}
${customer.orders.socks}
9.3.1.3 Referencing Literals
The EL defines the following literals:
■
Boolean: true and false
■
Integer: As in Java
■
Floating-point: As in Java
■
■
String: With single and double quotes; " is escaped as \", ' is escaped as \', and \
is escaped as \\
Null: null
Here are some examples:
■
${"literal"}
■
${true}
■
${57}
9.3.1.4 Parameterized Method Calls
The EL offers support for parameterized method calls.
Both the . and [] operators can be used for invoking method calls with parameters, as
shown in the following expression syntax:
■
expr-a[expr-b](parameters)
■
expr-a.identifier-b(parameters)
In the first expression syntax, expr-a is evaluated to represent a bean object. The
expression expr-b is evaluated and cast to a string that represents a method in the bean
represented by expr-a. In the second expression syntax, expr-a is evaluated to represent
a bean object, and identifier-b is a string that represents a method in the bean object.
The parameters in parentheses are the arguments for the method invocation.
Parameters can be zero or more values of expressions, separated by commas.
Parameters are supported for both value expressions and method expressions. In the
following example, which is a modified tag from the guessnumber application, a
random number is provided as an argument rather than from user input to the method
call:
<h:inputText value="#{userNumberBean.userNumber('5')}">
The preceding example uses a value expression.
Consider the following example of a JavaServer Faces component tag that uses a
method expression:
<h:commandButton action="#{trader.buy}" value="buy"/>
The EL expression trader.buy calls the trader bean's buy method. You can modify the
tag to pass on a parameter. Here is the revised tag in which a parameter is passed:
<h:commandButton action="#{trader.buy('SOMESTOCK')}" value="buy"/>
In the preceding example, you are passing the string 'SOMESTOCK' (a stock symbol) as
a parameter to the buy method.
Expression Language 9-5
Value and Method Expressions
9.3.1.5 Where Value Expressions Can Be Used
Value expressions using the ${} delimiters can be used
■
In static text
■
In any standard or custom tag attribute that can accept an expression
The value of an expression in static text is computed and inserted into the current
output. Here is an example of an expression embedded in static text:
<some:tag>
some text ${expr} some text
</some:tag>
A tag attribute can be set in the following ways.
■
With a single expression construct:
<some:tag value="${expr}"/>
<another:tag value="#{expr}"/>
These expressions are evaluated, and the result is converted to the attribute's
expected type.
■
With one or more expressions separated or surrounded by text:
<some:tag value="some${expr}${expr}text${expr}"/>
<another:tag value="some#{expr}#{expr}text#{expr}"/>
These kinds of expression, called composite expressions, are evaluated from left
to right. Each expression embedded in the composite expression is converted to a
String and then concatenated with any intervening text. The resulting String is
then converted to the attribute's expected type.
■
With text only:
<some:tag value="sometext"/>
The attribute's String value is converted to the attribute's expected type.
You can use the string concatenation operator += to create a single expression from
what would otherwise be a composite expression. For example, you could change the
composite expression
<some:tag value="sometext ${expr} moretext"/>
to
<some:tag value="${sometext += expr += moretext}"/>
All expressions used to set attribute values are evaluated in the context of an expected
type. If the result of the expression evaluation does not match the expected type
exactly, a type conversion will be performed. For example, the expression ${1.2E4}
provided as the value of an attribute of type float will result in the following
conversion:
Float.valueOf("1.2E4").floatValue()
9-6 The Java EE 7 Tutorial
Value and Method Expressions
9.3.2 Method Expressions
Another feature of the EL is its support of deferred method expressions. A method
expression is used to refer to a public method of a bean and has the same syntax as an
lvalue expression.
In JavaServer Faces technology, a component tag represents a component on a page.
The component tag uses method expressions to specify methods that can be invoked
to perform some processing for the component. These methods are necessary for
handling events that the components generate and for validating component data, as
shown in this example:
<h:form>
<h:inputText id="name"
value="#{customer.name}"
validator="#{customer.validateName}"/>
<h:commandButton id="submit"
action="#{customer.submit}" />
</h:form>
The h:inputText tag displays as a field. The validator attribute of this h:inputText
tag references a method, called validateName, in the bean, called customer.
Because a method can be invoked during different phases of the lifecycle, method
expressions must always use the deferred evaluation syntax.
Like lvalue expressions, method expressions can use the . and the [] operators. For
example, #{object.method} is equivalent to #{object["method"]}. The literal inside
the [] is converted to String and is used to find the name of the method that matches
it.
Method expressions can be used only in tag attributes and only in the following ways:
■
With a single expression construct, where bean refers to a JavaBeans component
and method refers to a method of the JavaBeans component:
<some:tag value="#{bean.method}"/>
The expression is evaluated to a method expression, which is passed to the tag
handler. The method represented by the method expression can then be invoked
later.
■
With text only:
<some:tag value="sometext"/>
Method expressions support literals primarily to support action attributes in
JavaServer Faces technology. When the method referenced by this method
expression is invoked, the method returns the String literal, which is then
converted to the expected return type, as defined in the tag's tag library descriptor.
9.3.3 Lambda Expressions
A lambda expression is a value expression with parameters. The syntax is similar to
that of the lambda expression in the Java programming language, except that in the
EL, the body of the lambda expression is an EL expression.
For basic information on lambda expressions, see
http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpress
ions.html.
Expression Language 9-7
Operations on Collection Objects
Lambda expressions are part of Java SE 8, but you can use
them in EL expressions with Java SE 7, the Java version associated
with the Java EE 7 platform.
Note:
A lambda expression uses the arrow token (->) operator. The identifiers to the left of
the operator are called lambda parameters. The body, to the right of the operator, must
be an EL expression. The lambda parameters are enclosed in parentheses; the
parentheses can be omitted if there is only one parameter. Here are some examples:
x -> x+1
(x, y) -> x + y
() -> 64
A lambda expression behaves like a function. It can be invoked immediately. For
example, the following invocation evaluates to 7:
((x, y) -> x + y)(3, 4)
You can use a lambda expression in conjunction with the assignment and semicolon
operators. For example, the following code assigns the previous lambda expression to
a variable and then invokes it. The result is again 7:
v = (x, y) -> x + y; v(3, 4)
A lambda expression can also be passed as an argument to a method and be invoked
in the method. It can also be nested in another lambda expression.
9.4 Operations on Collection Objects
The EL supports operations on collection objects: sets, lists, and maps. It allows the
dynamic creation of collection objects, which can then be operated on using streams
and pipelines.
Like lambda expressions, operations on collection objects are
part of Java SE 8, but you can use them in EL expressions with Java SE
7, the Java version associated with the Java EE 7 platform.
Note:
For example, you can construct a set as follows:
{1,2,3}
You can construct a list as follows; a list can contain various types of items:
[1,2,3]
[1, "two", [three,four]]
You can construct a map by using a colon to define the entries, as follows:
{"one":1, "two":2, "three":3}
You operate on collection objects using method calls to the stream of elements derived
from the collection. Some operations return another stream, which allows additional
operations. Therefore, you can chain these operations together in a pipeline.
A stream pipeline consists of the following:
■
A source (the Stream object)
9-8 The Java EE 7 Tutorial
Operators
■
■
Any number of intermediate operations that return a stream (for example, filter
and map)
A terminal operation that does not return a stream (for example, toList())
The stream method obtains a Stream from a java.util.Collection or a Java array.
The stream operations do not modify the original collection object.
For example, you might generate a list of titles of history books as follows:
books.stream().filter(b->b.category == 'history')
.map(b->b.title)
.toList()
The following simpler example returns a sorted version of the original list:
[1,3,5,2].stream().sorted().toList()
Streams and stream operations are documented in the Java SE 8 API documentation,
available at http://docs.oracle.com/javase/8/docs/api/. The following
subset of operations is supported by the EL:
allMatch
anyMatch
average
count
distinct
filter
findFirst
flatMap
forEach
iterator
limit
map
max
min
noneMatch
peek
reduce
sorted
substream
sum
toArray
toList
See the EL specification at http://www.jcp.org/en/jsr/detail?id=341 for
details on these operations.
9.5 Operators
In addition to the . and [] operators discussed in Value and Method Expressions, the
EL provides the following operators, which can be used in rvalue expressions only.
■
Arithmetic: +, - (binary), *, / and div, % and mod, - (unary).
■
String concatenation: +=.
■
Logical: and, &&, or, ||, not, !.
Expression Language 9-9
Reserved Words
■
■
■
Relational: ==, eq, !=, ne, <, lt, >, gt, <=, ge, >=, le. Comparisons can be made
against other values or against Boolean, string, integer, or floating-point literals.
Empty: The empty operator is a prefix operation that can be used to determine
whether a value is null or empty.
Conditional: A ? B : C. Evaluate B or C, depending on the result of the evaluation
of A.
■
Lambda expression: ->, the arrow token.
■
Assignment: =.
■
Semicolon: ;.
The precedence of operators, highest to lowest, left to right, is as follows:
■
[] .
■
() (used to change the precedence of operators)
■
- (unary) not ! empty
■
* / div % mod
■
+ - (binary)
■
+=
■
<> <= >= lt gt le ge
■
== != eq ne
■
&& and
■
|| or
■
? :
■
->
■
=
■
;
9.6 Reserved Words
The following words are reserved for the EL and should not be used as identifiers:
and
or
not
eq
ne
lt
gt
le
ge
true
false
null
instanceof
empty
div
mod
9-10 The Java EE 7 Tutorial
Further Information about the Expression Language
9.7 Examples of EL Expressions
Table 9–1 contains example EL expressions and the result of evaluating them.
Table 9–1
Example Expressions
EL Expression
Result
${1> (4/2)}
false
${4.0>= 3}
true
${100.0 == 100}
true
${(10*10) ne 100}
false
${'a' > 'b'}
false
${'hip' lt 'hit'}
true
${4> 3}
true
${1.2E4 + 1.4}
12001.4
${3 div 4}
0.75
${10 mod 4}
2
${((x, y) -> x + y)(3, 5.5)}
8.5
[1,2,3,4].stream().sum()
10
[1,3,5,2].stream().sorted().toList()
[1, 2, 3, 5]
${!empty param.Add}
False if the request parameter named Add is null
or an empty string
${pageContext.request.contextPath}
The context path
${sessionScope.cart.numberOfItems}
The value of the numberOfItems property of the
session-scoped attribute named cart
${param['mycom.productId']}
The value of the request parameter named
mycom.productId
${header["host"]}
The host
${departments[deptName]}
The value of the entry named deptName in the
departments map
${requestScope['javax.servlet.forward.servlet_path']} The value of the request-scoped attribute named
javax.servlet.forward.servlet_path
#{customer.lName}
Gets the value of the property lName from the
customer bean during an initial request; sets the
value of lName during a postback
#{customer.calcTotal}
The return value of the method calcTotal of the
customer bean
9.8 Further Information about the Expression Language
For more information about the EL, see
■
The Expression Language 3.0 specification:
http://www.jcp.org/en/jsr/detail?id=341
■
The EL specification website:
https://java.net/projects/el-spec/
Expression Language
9-11
Further Information about the Expression Language
9-12 The Java EE 7 Tutorial
10
Using JavaServer Faces Technology in Web
Pages
10
Web pages (Facelets pages, in most cases) represent the presentation layer for web
applications. The process of creating web pages for a JavaServer Faces application
includes using component tags to add components to the page and wire them to
backing beans, validators, listeners, converters, and other server-side objects that are
associated with the page.
This chapter explains how to create web pages using various types of component and
core tags. In the next chapter, you will learn about adding converters, validators, and
listeners to component tags to provide additional functionality to components.
Many of the examples in this chapter are taken from Chapter 57, "Duke's Bookstore
Case Study Example."
The following topics are addressed here:
■
Setting Up a Page
■
Adding Components to a Page Using HTML Tag Library Tags
■
Using Core Tags
10.1 Setting Up a Page
A typical JavaServer Faces web page includes the following elements:
■
A set of namespace declarations that declare the JavaServer Faces tag libraries
■
Optionally, the HTML head (h:head) and body (h:body) tags
■
A form tag (h:form) that represents the user input components
To add the JavaServer Faces components to your web page, you need to provide the
page access to the two standard tag libraries: the JavaServer Faces HTML render kit
tag library and the JavaServer Faces core tag library. The JavaServer Faces standard
HTML tag library defines tags that represent common HTML user interface
components. This library is linked to the HTML render kit at
http://docs.oracle.com/javaee/7/javaserverfaces/2.2/renderkitdoc
s/. The JavaServer Faces core tag library defines tags that perform core actions and are
independent of a particular render kit.
For a complete list of JavaServer Faces Facelets tags and their attributes, refer to the
documentation at
http://docs.oracle.com/javaee/7/javaserverfaces/2.2/vdldocs/face
lets/.
Using JavaServer Faces Technology in Web Pages 10-1
Adding Components to a Page Using HTML Tag Library Tags
To use any of the JavaServer Faces tags, you need to include appropriate directives at
the top of each page specifying the tag libraries.
For Facelets applications, the XML namespace directives uniquely identify the tag
library URI and the tag prefix.
For example, when you create a Facelets XHTML page, include namespace directives
as follows:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
The XML namespace URI identifies the tag library location, and the prefix value is
used to distinguish the tags belonging to that specific tag library. You can also use
other prefixes instead of the standard h or f. However, when including the tag in the
page you must use the prefix that you have chosen for the tag library. For example, in
the following web page the form tag must be referenced using the h prefix because the
preceding tag library directive uses the h prefix to distinguish the tags defined in the
HTML tag library:
<h:form ...>
The sections Adding Components to a Page Using HTML Tag Library Tags and Using
Core Tags describe how to use the component tags from the JavaServer Faces standard
HTML tag library and the core tags from the JavaServer Faces core tag library.
10.2 Adding Components to a Page Using HTML Tag Library Tags
The tags defined by the JavaServer Faces standard HTML tag library represent HTML
form components and other basic HTML elements. These components display data or
accept data from the user. This data is collected as part of a form and is submitted to
the server, usually when the user clicks a button. This section explains how to use each
of the component tags shown in Table 10–1.
Table 10–1
The Component Tags
Tag
Functions
h:column
Represents a column of
A column of data in
data in a data component an HTML table
h:commandButton
Submits a form to the
application
An HTML <input
A button
type=value> element
for which the type
value can be
"submit", "reset", or
"image"
h:commandLink
Links to another page or
location on a page
An HTML <a href>
element
A link
h:dataTable
Represents a data
wrapper
An HTML <table>
element
A table that can
be updated
dynamically
h:form
Represents an input form An HTML <form>
(inner tags of the form
element
receive the data that will
be submitted with the
form)
No appearance
h:graphicImage
Displays an image
An image
10-2 The Java EE 7 Tutorial
Rendered As
An HTML <img>
element
Appearance
A column in a
table
Adding Components to a Page Using HTML Tag Library Tags
Table 10–1 (Cont.) The Component Tags
Tag
Functions
Rendered As
Appearance
h:inputFile
Allows a user to upload a An HTML <input
file
type="file">
element
A field with a
Browse... button
h:inputHidden
Allows a page author to An HTML <input
include a hidden variable type="hidden">
in a page
element
No appearance
h:inputSecret
Allows a user to input a
string without the actual
string appearing in the
field
An HTML <input
type="password">
element
A field that
displays a row of
characters instead
of the actual
string entered
h:inputText
Allows a user to input a
string
An HTML <input
type="text">
element
A field
h:inputTextarea
Allows a user to enter a
multiline string
An HTML
<textarea> element
A multirow field
h:message
Displays a localized
message
An HTML <span> tag A text string
if styles are used
h:messages
Displays localized
messages
A set of HTML
<span> tags if styles
are used
A text string
h:outputFormat
Displays a formatted
message
Plain text
Plain text
h:outputLabel
Displays a nested
component as a label for
a specified input field
An HTML <label>
element
Plain text
h:outputLink
Links to another page or
location on a page
without generating an
action event
An HTML <a>
element
A link
h:outputText
Displays a line of text
Plain text
Plain text
h:panelGrid
Displays a table
An HTML <table>
element with <tr>
and <td> elements
A table
h:panelGroup
Groups a set of
components under one
parent
A HTML <div> or
<span> element
A row in a table
h:selectBooleanCheck Allows a user to change
box
the value of a Boolean
choice
An HTML <input
type="checkbox">
element
A check box
h:selectManyCheckbox Displays a set of check
boxes from which the
user can select multiple
values
A set of HTML
<input> elements of
type checkbox
A group of check
boxes
h:selectManyListbox
Allows a user to select
multiple items from a set
of items all displayed at
once
An HTML <select>
element
A box
h:selectManyMenu
Allows a user to select
multiple items from a set
of items
An HTML <select>
element
A menu
Using JavaServer Faces Technology in Web Pages 10-3
Adding Components to a Page Using HTML Tag Library Tags
Table 10–1 (Cont.) The Component Tags
Tag
Functions
Rendered As
Appearance
h:selectOneListbox
Allows a user to select
one item from a set of
items all displayed at
once
An HTML <select>
element
A box
h:selectOneMenu
Allows a user to select
one item from a set of
items
An HTML <select>
element
A menu
h:selectOneRadio
Allows a user to select
one item from a set of
items
An HTML <input
type="radio">
element
A group of
options
The tags correspond to components in the javax.faces.component package. The
components are discussed in more detail in Chapter 12, "Developing with JavaServer
Faces Technology."
The next section explains the important attributes that are common to most
component tags. For each of the components discussed in the following sections,
Writing Bean Properties explains how to write a bean property bound to that
particular component or its value.
For reference information about the tags and their attributes, see the API
documentation for the Facelets tag library at
http://docs.oracle.com/javaee/7/javaserverfaces/2.2/vdldocs/face
lets/.
10.2.1 Common Component Tag Attributes
Most of the component tags support the attributes shown in Table 10–2.
Table 10–2
Common Component Tag Attributes
Attribute
Description
binding
Identifies a bean property and binds the component instance to it.
id
Uniquely identifies the component.
immediate
If set to true, indicates that any events, validation, and conversion associated
with the component should happen when request parameter values are
applied.
rendered
Specifies a condition under which the component should be rendered. If the
condition is not satisfied, the component is not rendered.
style
Specifies a Cascading Style Sheet (CSS) style for the tag.
styleClass
Specifies a CSS class that contains definitions of the styles.
value
Specifies the value of the component in the form of a value expression.
All the tag attributes except id can accept expressions, as defined by the EL, described
in Expression Language.
An attribute such as rendered or value can be set on the page and then modified in
the backing bean for the page.
10-4 The Java EE 7 Tutorial
Adding Components to a Page Using HTML Tag Library Tags
10.2.1.1 The id Attribute
The id attribute is not usually required for a component tag but is used when another
component or a server-side class must refer to the component. If you don't include an
id attribute, the JavaServer Faces implementation automatically generates a
component ID. Unlike most other JavaServer Faces tag attributes, the id attribute takes
expressions using only the evaluation syntax described in Immediate Evaluation,
which uses the ${} delimiters. For more information on expression syntax, see Value
Expressions.
10.2.1.2 The immediate Attribute
Input components and command components (those that implement the
ActionSource interface, such as buttons and links) can set the immediate attribute to
true to force events, validations, and conversions to be processed when request
parameter values are applied.
You need to carefully consider how the combination of an input component's
immediate value and a command component's immediate value determines what
happens when the command component is activated.
Suppose that you have a page with a button and a field for entering the quantity of a
book in a shopping cart. If the immediate attributes of both the button and the field are
set to true, the new value entered in the field will be available for any processing
associated with the event that is generated when the button is clicked. The event
associated with the button as well as the events, validation, and conversion associated
with the field are all handled when request parameter values are applied.
If the button's immediate attribute is set to true but the field's immediate attribute is
set to false, the event associated with the button is processed without updating the
field's local value to the model layer. The reason is that any events, conversion, and
validation associated with the field occur after request parameter values are applied.
The bookshowcart.xhtml page of the Duke's Bookstore case study has examples of
components using the immediate attribute to control which component's data is
updated when certain buttons are clicked. The quantity field for each book does not
set the immediate attribute, so the value is false (the default).
<h:inputText id="quantity"
size="4"
value="#{item.quantity}"
title="#{bundle.ItemQuantity}">
<f:validateLongRange minimum="0"/>
...
</h:inputText>
The immediate attribute of the Continue Shopping hyperlink is set to true, while the
immediate attribute of the Update Quantities hyperlink is set to false:
<h:commandLink id="continue"
action="bookcatalog"
immediate="true">
<h:outputText value="#{bundle.ContinueShopping}"/>
</h:commandLink>
...
<h:commandLink id="update"
action="#{showcart.update}"
immediate="false">
<h:outputText value="#{bundle.UpdateQuantities}"/>
</h:commandLink>
Using JavaServer Faces Technology in Web Pages 10-5
Adding Components to a Page Using HTML Tag Library Tags
If you click the Continue Shopping hyperlink, none of the changes entered into the
quantity input fields will be processed. If you click the Update Quantities hyperlink,
the values in the quantity fields will be updated in the shopping cart.
10.2.1.3 The rendered Attribute
A component tag uses a Boolean EL expression along with the rendered attribute to
determine whether the component will be rendered. For example, the commandLink
component in the following section of a page is not rendered if the cart contains no
items:
<h:commandLink id="check"
...
rendered="#{cart.numberOfItems > 0}">
<h:outputText
value="#{bundle.CartCheck}"/>
</h:commandLink>
Unlike nearly every other JavaServer Faces tag attribute, the rendered attribute is
restricted to using rvalue expressions. As explained in Value and Method Expressions,
these rvalue expressions can only read data; they cannot write the data back to the
data source. Therefore, expressions used with rendered attributes can use the
arithmetic operators and literals that rvalue expressions can use but lvalue expressions
cannot use. For example, the expression in the preceding example uses the > operator.
In this example and others, bundle refers to a
java.util.ResourceBundle file that contains locale-specific strings
to be displayed. Resource bundles are discussed in Chapter 20,
"Internationalizing and Localizing Web Applications".
Note:
10.2.1.4 The style and styleClass Attributes
The style and styleClass attributes allow you to specify CSS styles for the rendered
output of your tags. Displaying Error Messages with the h:message and h:messages
Tags describes an example of using the style attribute to specify styles directly in the
attribute. A component tag can instead refer to a CSS class.
The following example shows the use of a dataTable tag that references the style class
list-background:
<h:dataTable id="items"
...
styleClass="list-background"
value="#{cart.items}"
var="book">
The style sheet that defines this class is stylesheet.css, which will be included in the
application. For more information on defining styles, see the Cascading Style Sheets
specifications and drafts at http://www.w3.org/Style/CSS/.
10.2.1.5 The value and binding Attributes
A tag representing an output component uses the value and binding attributes to bind
its component's value or instance, respectively, to a data object. The value attribute is
used more commonly than the binding attribute, and examples appear throughout
this chapter. For more information on these attributes, see Creating a Managed Bean,
Writing Properties Bound to Component Values, and Writing Properties Bound to
Component Instances.
10-6 The Java EE 7 Tutorial
Adding Components to a Page Using HTML Tag Library Tags
10.2.2 Adding HTML Head and Body Tags
The HTML head (h:head) and body (h:body) tags add HTML page structure to
JavaServer Faces web pages.
■
The h:head tag represents the head element of an HTML page.
■
The h:body tag represents the body element of an HTML page.
The following is an example of an XHTML page using the usual head and body
markup tags:
<!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">
<head>
<title>Add a title</title>
</head>
<body>
Add Content
</body>
</html>
The following is an example of an XHTML page using h:head and h:body tags:
<!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://xmlns.jcp.org/jsf/html">
<h:head>
Add a title
</h:head>
<h:body>
Add Content
</h:body>
</html>
Both of the preceding example code segments render the same HTML elements. The
head and body tags are useful mainly for resource relocation. For more information on
resource relocation, see Resource Relocation Using h:outputScript and
h:outputStylesheet Tags.
10.2.3 Adding a Form Component
An h:form tag represents an input form, which includes child components that can
contain data that is either presented to the user or submitted with the form.
Figure 10–1 shows a typical login form in which a user enters a user name and
password, then submits the form by clicking the Login button.
Figure 10–1 A Typical Form
User Name:
Password:
Duke
**********
Login
The h:form tag represents the form on the page and encloses all the components that
display or collect data from the user, as shown here:
Using JavaServer Faces Technology in Web Pages 10-7
Adding Components to a Page Using HTML Tag Library Tags
<h:form>
... other JavaServer Faces tags and other content...
</h:form>
The h:form tag can also include HTML markup to lay out the components on the
page. Note that the h:form tag itself does not perform any layout; its purpose is to
collect data and to declare attributes that can be used by other components in the form.
A page can include multiple h:form tags, but only the values from the form submitted
by the user will be included in the postback request.
10.2.4 Using Text Components
Text components allow users to view and edit text in web applications. The basic types
of text components are as follows:
■
■
■
Label, which displays read-only text
Field, which allows users to enter text (on one or more lines), often to be submitted
as part of a form
Password field, which is a type of field that displays a set of characters, such as
asterisks, instead of the password text that the user enters
Figure 10–2 shows examples of these text components.
Figure 10–2 Example Text Components
Label
User Name:
Password:
Comments:
Duke
Text Field
**********
Password Field
A user can enter text across
multiple lines.
Text Area
Text components can be categorized as either input or output. A JavaServer Faces
output component, such as a label, is rendered as read-only text. A JavaServer Faces
input component, such as a field, is rendered as editable text.
The input and output components can each be rendered in various ways to display
more specialized text.
Table 10–3 lists the tags that represent the input components.
Table 10–3
Input Tags
Tag
Function
h:inputHidden
Allows a page author to include a hidden variable in a page
h:inputSecret
The standard password field: accepts one line of text with no spaces
and displays it as a set of asterisks as it is entered
h:inputText
The standard field: accepts a one-line text string
h:inputTextarea
The standard multiline field: accepts multiple lines of text
The input tags support the tag attributes shown in Table 10–4 in addition to those
described in Common Component Tag Attributes. Note that this table does not include
all the attributes supported by the input tags but just those that are used most often.
For the complete list of attributes, refer to the documentation at
10-8 The Java EE 7 Tutorial
Adding Components to a Page Using HTML Tag Library Tags
http://docs.oracle.com/javaee/7/javaserverfaces/2.2/vdldocs/face
lets/.
Table 10–4
Input Tag Attributes
Attribute
Description
converter
Identifies a converter that will be used to convert the component's
local data. See Using the Standard Converters for more information on
how to use this attribute.
converterMessage
Specifies an error message to display when the converter registered on
the component fails.
dir
Specifies the direction of the text displayed by this component.
Acceptable values are ltr, meaning left to right, and rtl, meaning
right to left.
label
Specifies a name that can be used to identify this component in error
messages.
lang
Specifies the code for the language used in the rendered markup, such
as en or pt-BR.
required
Takes a boolean value that indicates whether the user must enter a
value in this component.
requiredMessage
Specifies an error message to display when the user does not enter a
value into the component.
validator
Identifies a method expression pointing to a managed bean method
that performs validation on the component's data. See Referencing a
Method That Performs Validation for an example of using the
f:validator tag.
validatorMessage
Specifies an error message to display when the validator registered on
the component fails to validate the component's local value.
valueChangeListener Identifies a method expression that points to a managed bean method
that handles the event of entering a value in this component. See
Referencing a Method That Handles a Value-Change Event for an
example of using valueChangeListener.
Table 10–5 lists the tags that represent the output components.
Table 10–5
Output Tags
Tag
Function
h:outputFormat
Displays a formatted message
h:outputLabel
The standard read-only label: displays a component as a label for a
specified input field
h:outputLink
Displays an <a href> tag that links to another page without generating
an action event
h:outputText
Displays a one-line text string
The output tags support the converter tag attribute in addition to those listed in
Common Component Tag Attributes.
The rest of this section explains how to use some of the tags listed in Table 10–3 and
Output Tags. The other tags are written in a similar way.
Using JavaServer Faces Technology in Web Pages 10-9
Adding Components to a Page Using HTML Tag Library Tags
10.2.4.1 Rendering a Field with the h:inputText Tag
The h:inputText tag is used to display a field. A similar tag, the h:outputText tag,
displays a read-only, single-line string. This section shows you how to use the
h:inputText tag. The h:outputText tag is written in a similar way.
Here is an example of an h:inputText tag:
<h:inputText id="name"
label="Customer Name"
size="30"
value="#{cashierBean.name}"
required="true"
requiredMessage="#{bundle.ReqCustomerName}">
<f:valueChangeListener
type="javaeetutorial.dukesbookstore.listeners.NameChanged" />
</h:inputText>
The label attribute specifies a user-friendly name that will be used in the substitution
parameters of error messages displayed for this component.
The value attribute refers to the name property of a managed bean named
CashierBean. This property holds the data for the name component. After the user
submits the form, the value of the name property in CashierBean will be set to the text
entered in the field corresponding to this tag.
The required attribute causes the page to reload, displaying errors, if the user does not
enter a value in the name field. The JavaServer Faces implementation checks whether
the value of the component is null or is an empty string.
If your component must have a non-null value or a String value at least one character
in length, you should add a required attribute to your tag and set its value to true. If
your tag has a required attribute that is set to true and the value is null or a
zero-length string, no other validators that are registered on the tag are called. If your
tag does not have a required attribute set to true, other validators that are registered
on the tag are called, but those validators must handle the possibility of a null or
zero-length string. See Validating Null and Empty Strings for more information.
10.2.4.2 Rendering a Password Field with the h:inputSecret Tag
The h:inputSecret tag renders an <input type="password"> HTML tag. When the
user types a string into this field, a row of asterisks is displayed instead of the text
entered by the user. Here is an example:
<h:inputSecret redisplay="false"
value="#{loginBean.password}" />
In this example, the redisplay attribute is set to false. This will prevent the password
from being displayed in a query string or in the source file of the resulting HTML
page.
10.2.4.3 Rendering a Label with the h:outputLabel Tag
The h:outputLabel tag is used to attach a label to a specified input field for the
purpose of making it accessible. The following page uses an h:outputLabel tag to
render the label of a check box:
<h:selectBooleanCheckbox id="fanClub"
rendered="false"
binding="#{cashierBean.specialOffer}" />
<h:outputLabel for="fanClub"
rendered="false
10-10 The Java EE 7 Tutorial
Adding Components to a Page Using HTML Tag Library Tags
binding="#{cashierBean.specialOfferText}">
<h:outputText id="fanClubLabel"
value="#{bundle.DukeFanClub}" />
</h:outputLabel>
...
The h:selectBooleanCheckbox tag and the h:outputLabel tag have rendered
attributes that are set to false on the page but are set to true in the CashierBean under
certain circumstances. The for attribute of the h:outputLabel tag maps to the id of the
input field to which the label is attached. The h:outputText tag nested inside the
h:outputLabel tag represents the label component. The value attribute on the
h:outputText tag indicates the text that is displayed next to the input field.
Instead of using an h:outputText tag for the text displayed as a label, you can simply
use the h:outputLabel tag's value attribute. The following code snippet shows what
the previous code snippet would look like if it used the value attribute of the
h:outputLabel tag to specify the text of the label:
<h:selectBooleanCheckbox id="fanClub"
rendered="false"
binding="#{cashierBean.specialOffer}" />
<h:outputLabel for="fanClub"
rendered="false"
binding="#{cashierBean.specialOfferText}"
value="#{bundle.DukeFanClub}" />
</h:outputLabel>
...
10.2.4.4 Rendering a Link with the h:outputLink Tag
The h:outputLink tag is used to render a link that, when clicked, loads another page
but does not generate an action event. You should use this tag instead of the
h:commandLink tag if you always want the URL specified by the h:outputLink tag's
value attribute to open and do not want any processing to be performed when the
user clicks the link. Here is an example:
<h:outputLink value="javadocs">
Documentation for this demo
</h:outputLink>
The text in the body of the h:outputLink tag identifies the text that the user clicks to
get to the next page.
10.2.4.5 Displaying a Formatted Message with the h:outputFormat Tag
The h:outputFormat tag allows display of concatenated messages as a MessageFormat
pattern, as described in the API documentation for java.text.MessageFormat. Here is
an example of an h:outputFormat tag:
<h:outputFormat value="Hello, {0}!">
<f:param value="#{hello.name}"/>
</h:outputFormat>
The value attribute specifies the MessageFormat pattern. The f:param tag specifies the
substitution parameters for the message. The value of the parameter replaces the {0}
in the sentence. If the value of "#{hello.name}" is "Bill", the message displayed in the
page is as follows:
Hello, Bill!
Using JavaServer Faces Technology in Web Pages 10-11
Adding Components to a Page Using HTML Tag Library Tags
An h:outputFormat tag can include more than one f:param tag for those messages
that have more than one parameter that must be concatenated into the message. If you
have more than one parameter for one message, make sure that you put the f:param
tags in the proper order so that the data is inserted in the correct place in the message.
Here is the preceding example modified with an additional parameter:
<h:outputFormat value="Hello, {0}! You are visitor number {1} to the page.">
<f:param value="#{hello.name}" />
<f:param value="#{bean.numVisitor}"/>
</h:outputFormat>
The value of {1} is replaced by the second parameter. The parameter is an EL
expression, bean.numVisitor, in which the property numVisitor of the managed bean
bean keeps track of visitors to the page. This is an example of a
value-expression-enabled tag attribute accepting an EL expression. The message
displayed in the page is now as follows:
Hello, Bill! You are visitor number 10 to the page.
10.2.5 Using Command Component Tags for Performing Actions and Navigation
In JavaServer Faces applications, the button and link component tags are used to
perform actions, such as submitting a form, and for navigating to another page. These
tags are called command component tags because they perform an action when
activated.
The h:commandButton tag is rendered as a button. The h:commandLink tag is rendered
as a link.
In addition to the tag attributes listed in Common Component Tag Attributes, the
h:commandButton and h:commandLink tags can use the following attributes.
■
■
action, which is either a logical outcome String or a method expression pointing
to a bean method that returns a logical outcome String. In either case, the logical
outcome String is used to determine what page to access when the command
component tag is activated.
actionListener, which is a method expression pointing to a bean method that
processes an action event fired by the command component tag.
See Referencing a Method That Performs Navigation for more information on using
the action attribute. See Referencing a Method That Handles an Action Event for
details on using the actionListener attribute.
10.2.5.1 Rendering a Button with the h:commandButton Tag
If you are using an h:commandButton component tag, the data from the current page is
processed when a user clicks the button, and the next page is opened. Here is an
example of the h:commandButton tag:
<h:commandButton value="Submit"
action="#{cashierBean.submit}"/>
Clicking the button will cause the submit method of CashierBean to be invoked
because the action attribute references this method. The submit method performs
some processing and returns a logical outcome.
The value attribute of the example h:commandButton tag references the button's label.
For information on how to use the action attribute, see Referencing a Method That
Performs Navigation.
10-12 The Java EE 7 Tutorial
Adding Components to a Page Using HTML Tag Library Tags
10.2.5.2 Rendering a Link with the h:commandLink Tag
The h:commandLink tag represents an HTML link and is rendered as an HTML <a>
element.
An h:commandLink tag must include a nested h:outputText tag, which represents the
text that the user clicks to generate the event. Here is an example:
<h:commandLink id="Duke" action="bookstore">
<f:actionListener
type="javaeetutorial.dukesbookstore.listeners.LinkBookChangeListener" />
<h:outputText value="#{bundle.Book201}"/>
/h:commandLink>
This tag will render HTML that looks something like the following:
<a id="_idt16:Duke" href="#"
onclick="mojarra.jsfcljs(document.getElementById('j_idt16'),
{'j_idt16:Duke':'j_idt16:Duke'},'');
return false;">My Early Years: Growing Up on Star7, by Duke</a>
Note: The h:commandLink tag will render JavaScript scripting
language. If you use this tag, make sure that your browser is
enabled for JavaScript technology.
10.2.6 Adding Graphics and Images with the h:graphicImage Tag
In a JavaServer Faces application, use the h:graphicImage tag to render an image on a
page:
<h:graphicImage id="mapImage" url="/resources/images/book_all.jpg"/>
In this example, the url attribute specifies the path to the image. The URL of the
example tag begins with a slash (/), which adds the relative context path of the web
application to the beginning of the path to the image.
Alternatively, you can use the facility described in Web Resources to point to the image
location. Here are two examples:
<h:graphicImage id="mapImage"
name="book_all.jpg"
library="images"
alt="#{bundle.ChooseBook}"
usemap="#bookMap" />
<h:graphicImage value="#{resource['images:wave.med.gif']}"/>
You can use similar syntax to refer to an image in a style sheet. The following syntax in
a style sheet specifies that the image is to be found at
resources/img/top-background.jpg:
header {
position: relative;
height: 150px;
background: #fff url(#{resource['img:top-background.jpg']}) repeat-x;
...
Using JavaServer Faces Technology in Web Pages 10-13
Adding Components to a Page Using HTML Tag Library Tags
10.2.7 Laying Out Components with the h:panelGrid and h:panelGroup Tags
In a JavaServer Faces application, you use a panel as a layout container for a set of
other components. A panel is rendered as an HTML table. Table 10–6 lists the tags
used to create panels.
Table 10–6
Panel Component Tags
Tag
Attributes
Function
h:panelGrid
columns, columnClasses, footerClass,
headerClass, panelClass, rowClasses,
role
Displays a table
h:panelGroup
layout
Groups a set of components
under one parent
The h:panelGrid tag is used to represent an entire table. The h:panelGroup tag is used
to represent rows in a table. Other tags are used to represent individual cells in the
rows.
The columns attribute defines how to group the data in the table and therefore is
required if you want your table to have more than one column. The h:panelGrid tag
also has a set of optional attributes that specify CSS classes: columnClasses,
footerClass, headerClass, panelClass, and rowClasses. The role attribute can have
the value "presentation" to indicate that the purpose of the table is to format the
display rather than to show data.
If the headerClass attribute value is specified, the h:panelGrid tag must have a
header as its first child. Similarly, if a footerClass attribute value is specified, the
h:panelGrid tag must have a footer as its last child.
Here is an example:
<h:panelGrid columns="2"
headerClass="list-header"
styleClass="list-background"
rowClasses="list-row-even, list-row-odd"
summary="#{bundle.CustomerInfo}"
title="#{bundle.Checkout}"
role="presentation">
<f:facet name="header">
<h:outputText value="#{bundle.Checkout}"/>
</f:facet>
<h:outputLabel for="name" value="#{bundle.Name}" />
<h:inputText id="name" size="30"
value="#{cashierBean.name}"
required="true"
requiredMessage="#{bundle.ReqCustomerName}">
<f:valueChangeListener
type="javaeetutorial.dukesbookstore.listeners.NameChanged" />
</h:inputText>
<h:message styleClass="error-message" for="name"/>
<h:outputLabel for="ccno" value="#{bundle.CCNumber}"/>
<h:inputText id="ccno"
size="19"
converterMessage="#{bundle.CreditMessage}"
required="true"
requiredMessage="#{bundle.ReqCreditCard}">
<f:converter converterId="ccno"/>
10-14 The Java EE 7 Tutorial
Adding Components to a Page Using HTML Tag Library Tags
<f:validateRegex
pattern="\d{16}|\d{4} \d{4} \d{4} \d{4}|\d{4}-\d{4}-\d{4}-\d{4}" />
</h:inputText>
<h:message styleClass="error-message" for="ccno"/>
...
</h:panelGrid>
The preceding h:panelGrid tag is rendered as a table that contains components in
which a customer inputs personal information. This h:panelGrid tag uses style sheet
classes to format the table. The following code shows the list-header definition:
.list-header {
background-color: #ffffff;
color: #000000;
text-align: center;
}
Because the h:panelGrid tag specifies a headerClass, the h:panelGrid tag must
contain a header. The example h:panelGrid tag uses an f:facet tag for the header.
Facets can have only one child, so an h:panelGroup tag is needed if you want to group
more than one component within an f:facet. The example h:panelGrid tag has only
one cell of data, so an h:panelGroup tag is not needed. (For more information about
facets, see Using Data-Bound Table Components.
The h:panelGroup tag has an attribute, layout, in addition to those listed in Common
Component Tag Attributes. If the layout attribute has the value block, an HTML div
element is rendered to enclose the row; otherwise, an HTML span element is rendered
to enclose the row. If you are specifying styles for the h:panelGroup tag, you should
set the layout attribute to block in order for the styles to be applied to the components
within the h:panelGroup tag. You should do this because styles, such as those that set
width and height, are not applied to inline elements, which is how content enclosed by
the span element is defined.
An h:panelGroup tag can also be used to encapsulate a nested tree of components so
that the tree of components appears as a single component to the parent component.
Data, represented by the nested tags, is grouped into rows according to the value of
the columns attribute of the h:panelGrid tag. The columns attribute in the example is
set to 2, and therefore the table will have two columns. The column in which each
component is displayed is determined by the order in which the component is listed
on the page modulo 2. So, if a component is the fifth one in the list of components, that
component will be in the 5 modulo 2 column, or column 1.
10.2.8 Displaying Components for Selecting One Value
Another commonly used component is one that allows a user to select one value,
whether it is the only value available or one of a set of choices. The most common tags
for this kind of component are as follows:
■
An h:selectBooleanCheckbox tag, displayed as a check box, which represents a
Boolean state
■
An h:selectOneRadio tag, displayed as a set of options
■
An h:selectOneMenu tag, displayed as a scrollable list
■
An h:selectOneListbox tag, displayed as an unscrollable list
Figure 10–3 shows examples of these components.
Using JavaServer Faces Technology in Web Pages 10-15
Adding Components to a Page Using HTML Tag Library Tags
Figure 10–3 Example Components for Selecting One Item
Genre:
Fiction
Non-fiction
Radio
Buttons
Reference
Biography
Availability:
Language: Chinese
Dutch
English
French
German
Spanish
Swahili
Format: Hardcover
Paperback
Large-print
Cassette
DVD
Illustrated
In print
Check Box
Drop-Down Menu
List Box
10.2.8.1 Displaying a Check Box Using the h:selectBooleanCheckbox Tag
The h:selectBooleanCheckbox tag is the only tag that JavaServer Faces technology
provides for representing a Boolean state.
Here is an example that shows how to use the h:selectBooleanCheckbox tag:
<h:selectBooleanCheckbox id="fanClub"
rendered="false"
binding="#{cashierBean.specialOffer}" />
<h:outputLabel for="fanClub"
rendered="false"
binding="#{cashierBean.specialOfferText}"
value="#{bundle.DukeFanClub}" />
The h:selectBooleanCheckbox tag and the h:outputLabel tag have rendered
attributes that are set to false on the page but are set to true in the CashierBean under
certain circumstances. When the h:selectBooleanCheckbox tag is rendered, it displays
a check box to allow users to indicate whether they want to join the Duke Fan Club.
When the h:outputLabel tag is rendered, it displays the label for the check box. The
label text is represented by the value attribute.
10.2.8.2 Displaying a Menu Using the h:selectOneMenu Tag
A component that allows the user to select one value from a set of values can be
rendered as a box or a set of options. This section describes the h:selectOneMenu tag.
The h:selectOneRadio and h:selectOneListbox tags are used in a similar way. The
h:selectOneListbox tag is similar to the h:selectOneMenu tag except that
h:selectOneListbox defines a size attribute that determines how many of the items
are displayed at once.
The h:selectOneMenu tag represents a component that contains a list of items from
which a user can select one item. This menu component is sometimes known as a
drop-down list or a combo box. The following code snippet shows how the
h:selectOneMenu tag is used to allow the user to select a shipping method:
<h:selectOneMenu id="shippingOption"
required="true"
value="#{cashierBean.shippingOption}">
<f:selectItem itemValue="2"
itemLabel="#{bundle.QuickShip}"/>
<f:selectItem itemValue="5"
itemLabel="#{bundle.NormalShip}"/>
<f:selectItem itemValue="7"
itemLabel="#{bundle.SaverShip}"/>
</h:selectOneMenu>
10-16 The Java EE 7 Tutorial
Adding Components to a Page Using HTML Tag Library Tags
The value attribute of the h:selectOneMenu tag maps to the property that holds the
currently selected item's value. In this case, the value is set by the backing bean. You
are not required to provide a value for the currently selected item. If you don't provide
a value, the browser determines which one is selected.
Like the h:selectOneRadio tag, the h:selectOneMenu tag must contain either an
f:selectItems tag or a set of f:selectItem tags for representing the items in the list.
Using the f:selectItem and f:selectItems Tags describes these tags.
10.2.9 Displaying Components for Selecting Multiple Values
In some cases, you need to allow your users to select multiple values rather than just
one value from a list of choices. You can do this using one of the following component
tags:
■
An h:selectManyCheckbox tag, displayed as a set of check boxes
■
An h:selectManyMenu tag, displayed as a menu
■
An h:selectManyListbox tag, displayed as a box
Figure 10–4 shows examples of these components.
Figure 10–4 Example Components for Selecting Multiple Values
Genre:
Check
Boxes
Fiction
Non-fiction
Reference
Biography
Language:
Chinese
Dutch
English
French
German
Spanish
Swahili
Format:
Drop-Down Menu
Hardcover
Paperback
Large-print
Cassette
DVD
Illustrated
List Box
These tags allow the user to select zero or more values from a set of values. This
section explains the h:selectManyCheckbox tag. The h:selectManyListbox and
h:selectManyMenu tags are used in a similar way.
Unlike a menu, a list displays a subset of items in a box; a menu displays only one
item at a time when the user is not selecting the menu. The size attribute of the
h:selectManyListbox tag determines the number of items displayed at one time. The
box includes a scroll bar for scrolling through any remaining items in the list.
The h:selectManyCheckbox tag renders a group of check boxes, with each check box
representing one value that can be selected:
<h:selectManyCheckbox id="newslettercheckbox"
layout="pageDirection"
value="#{cashierBean.newsletters}">
<f:selectItems value="#{cashierBean.newsletterItems}"/>
</h:selectManyCheckbox>
The value attribute of the h:selectManyCheckbox tag identifies the newsletters
property of the CashierBean managed bean. This property holds the values of the
currently selected items from the set of check boxes. You are not required to provide a
value for the currently selected items. If you don't provide a value, the first item in the
list is selected by default. In the CashierBean managed bean, this value is instantiated
to 0, so no items are selected by default.
Using JavaServer Faces Technology in Web Pages 10-17
Adding Components to a Page Using HTML Tag Library Tags
The layout attribute indicates how the set of check boxes is arranged on the page.
Because layout is set to pageDirection, the check boxes are arranged vertically. The
default is lineDirection, which aligns the check boxes horizontally.
The h:selectManyCheckbox tag must also contain a tag or set of tags representing the
set of check boxes. To represent a set of items, you use the f:selectItems tag. To
represent each item individually, you use the f:selectItem tag. The following section
explains these tags in more detail.
10.2.10 Using the f:selectItem and f:selectItems Tags
The f:selectItem and f:selectItems tags represent components that can be nested
inside a component that allows you to select one or multiple items. An f:selectItem
tag contains the value, label, and description of a single item. An f:selectItems tag
contains the values, labels, and descriptions of the entire list of items.
You can use either a set of f:selectItem tags or a single f:selectItems tag within
your component tag.
The advantages of using the f:selectItems tag are as follows.
■
■
■
Items can be represented by using different data structures, including Array, Map,
and Collection. The value of the f:selectItems tag can represent even a generic
collection of POJOs.
Different lists can be concatenated into a single component, and the lists can be
grouped within the component.
Values can be generated dynamically at runtime.
The advantages of using f:selectItem are as follows.
■
Items in the list can be defined from the page.
■
Less code is needed in the backing bean for the f:selectItem properties.
The rest of this section shows you how to use the f:selectItems and f:selectItem
tags.
10.2.10.1 Using the f:selectItems Tag
The following example from Displaying Components for Selecting Multiple Values
shows how to use the h:selectManyCheckbox tag:
<h:selectManyCheckbox id="newslettercheckbox"
layout="pageDirection"
value="#{cashierBean.newsletters}">
<f:selectItems value="#{cashierBean.newsletterItems}"/>
</h:selectManyCheckbox>
The value attribute of the f:selectItems tag is bound to the managed bean property
cashierBean.newsletterItems. The individual SelectItem objects are created
programmatically in the managed bean.
See UISelectItems Properties for information on how to write a managed bean
property for one of these tags.
10.2.10.2 Using the f:selectItem Tag
The f:selectItem tag represents a single item in a list of items. Here is the example
from Displaying a Menu Using the h:selectOneMenu Tag once again:
<h:selectOneMenu id="shippingOption"
10-18 The Java EE 7 Tutorial
Adding Components to a Page Using HTML Tag Library Tags
required="true"
value="#{cashierBean.shippingOption}">
<f:selectItem itemValue="2"
itemLabel="#{bundle.QuickShip}"/>
<f:selectItem itemValue="5"
itemLabel="#{bundle.NormalShip}"/>
<f:selectItem itemValue="7"
itemLabel="#{bundle.SaverShip}"/>
</h:selectOneMenu>
The itemValue attribute represents the value for the f:selectItem tag. The itemLabel
attribute represents the String that appears in the list component on the page.
The itemValue and itemLabel attributes are value-binding enabled, meaning that they
can use value-binding expressions to refer to values in external objects. These
attributes can also define literal values, as shown in the example h:selectOneMenu tag.
10.2.11 Displaying the Results from Selection Components
If you display components that allow a user to select values, you may also want to
display the result of the selection.
For example, you might want to thank a user who selected the checkbox to join the
Duke Fan Club, as described in Displaying a Check Box Using the
h:selectBooleanCheckbox Tag. Because the checkbox is bound to the specialOffer
property of CashierBean, a UISelectBoolean value, you can call the isSelected
method of the property to determine whether to render a thank-you message:
<h:outputText value="#{bundle.DukeFanClubThanks}"
rendered="#{cashierBean.specialOffer.isSelected()}"/>
Similarly, you might want to acknowledge that a user subscribed to newsletters using
the h:selectManyCheckbox tag, as described in Displaying Components for Selecting
Multiple Values. To do so, you can retrieve the value of the newsletters property, the
String array that holds the selected items:
<h:outputText value="#{bundle.NewsletterThanks}"
rendered="#{!empty cashierBean.newsletters}"/>
<ul>
<ui:repeat value="#{cashierBean.newsletters}" var="nli">
<li><h:outputText value="#{nli}" /></li>
</ui:repeat>
</ul>
An introductory thank-you message is displayed only if the newsletters array is not
empty. Then a ui:repeat tag, a simple way to show values in a loop, displays the
contents of the selected items in an itemized list. (This tag is listed in Table 8–2.)
10.2.12 Using Data-Bound Table Components
Data-bound table components display relational data in a tabular format. In a
JavaServer Faces application, the h:dataTable component tag supports binding to a
collection of data objects and displays the data as an HTML table. The h:column tag
represents a column of data within the table, iterating over each record in the data
source, which is displayed as a row. Here is an example:
<h:dataTable id="items"
captionClass="list-caption
columnClasses="list-column-center, list-column-left,
list-column-right, list-column-center"
Using JavaServer Faces Technology in Web Pages 10-19
Adding Components to a Page Using HTML Tag Library Tags
footerClass="list-footer"
headerClass="list-header"
rowClasses="list-row-even, list-row-odd"
styleClass="list-background"
summary="#{bundle.ShoppingCart}"
value="#{cart.items}"
border="1"
var="item">
<h:column>
<f:facet name="header">
<h:outputText value="#{bundle.ItemQuantity}" />
</f:facet>
<h:inputText id="quantity"
size="4"
value="#{item.quantity}"
title="#{bundle.ItemQuantity}">
<f:validateLongRange minimum="1"/>
<f:valueChangeListener
type="javaeetutorial.dukesbookstore.listeners.QuantityChanged"/>
</h:inputText>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{bundle.ItemTitle}"/>
</f:facet>
<h:commandLink action="#{showcart.details}">
<h:outputText value="#{item.item.title}"/>
</h:commandLink>
</h:column>
...
<f:facet name="footer"
<h:panelGroup>
<h:outputText value="#{bundle.Subtotal}"/>
<h:outputText value="#{cart.total}" />
<f:convertNumber currencySymbol="$" type="currency" />
</h:outputText>
</h:panelGroup>
</f:facet>
<f:facet name="caption">
<h:outputText value="#{bundle.Caption}"/>
</f:facet>
</h:dataTable>
The example h:dataTable tag displays the books in the shopping cart as well as the
quantity of each book in the shopping cart, the prices, and a set of buttons the user can
click to remove books from the shopping cart.
The h:column tags represent columns of data in a data component. While the data
component is iterating over the rows of data, it processes the column component
associated with each h:column tag for each row in the table.
The h:dataTable tag shown in the preceding code example iterates through the list of
books (cart.items) in the shopping cart and displays their titles, authors, and prices.
Each time the h:dataTable tag iterates through the list of books, it renders one cell in
each column.
The h:dataTable and h:column tags use facets to represent parts of the table that are
not repeated or updated. These parts include headers, footers, and captions.
In the preceding example, h:column tags include f:facet tags for representing column
headers or footers. The h:column tag allows you to control the styles of these headers
10-20 The Java EE 7 Tutorial
Adding Components to a Page Using HTML Tag Library Tags
and footers by supporting the headerClass and footerClass attributes. These
attributes accept space-separated lists of CSS classes, which will be applied to the
header and footer cells of the corresponding column in the rendered table.
Facets can have only one child, so an h:panelGroup tag is needed if you want to group
more than one component within an f:facet. Because the facet tag representing the
footer includes more than one tag, the h:panelGroup tag is needed to group those tags.
Finally, this h:dataTable tag includes an f:facet tag with its name attribute set to
caption, causing a table caption to be rendered above the table.
This table is a classic use case for a data component because the number of books
might not be known to the application developer or the page author when that
application is developed. The data component can dynamically adjust the number of
rows of the table to accommodate the underlying data.
The value attribute of an h:dataTable tag references the data to be included in the
table. This data can take the form of any of the following:
■
A list of beans
■
An array of beans
■
A single bean
■
A javax.faces.model.DataModel object
■
A java.sql.ResultSet object
■
A javax.servlet.jsp.jstl.sql.Result object
■
A javax.sql.RowSet object
All data sources for data components have a DataModel wrapper. Unless you explicitly
construct a DataModel wrapper, the JavaServer Faces implementation will create one
around data of any of the other acceptable types. See Writing Bean Properties for more
information on how to write properties for use with a data component.
The var attribute specifies a name that is used by the components within the
h:dataTable tag as an alias to the data referenced in the value attribute of
h:dataTable.
In the example h:dataTable tag, the value attribute points to a list of books. The var
attribute points to a single book in that list. As the h:dataTable tag iterates through
the list, each reference to item points to the current book in the list.
The h:dataTable tag also has the ability to display only a subset of the underlying
data. This feature is not shown in the preceding example. To display a subset of the
data, you use the optional first and rows attributes.
The first attribute specifies the first row to be displayed. The rows attribute specifies
the number of rows, starting with the first row, to be displayed. For example, if you
wanted to display records 2 through 10 of the underlying data, you would set first to
2 and rows to 9. When you display a subset of the data in your pages, you might want
to consider including a link or button that causes subsequent rows to display when
clicked. By default, both first and rows are set to zero, and this causes all the rows of
the underlying data to display.
Table 10–7 shows the optional attributes for the h:dataTable tag.
Table 10–7
Optional Attributes for the h:dataTable Tag
Attribute
Defines Styles For
captionClass
Table caption
Using JavaServer Faces Technology in Web Pages 10-21
Adding Components to a Page Using HTML Tag Library Tags
Table 10–7 (Cont.) Optional Attributes for the h:dataTable Tag
Attribute
Defines Styles For
columnClasses
All the columns
footerClass
Footer
headerClass
Header
rowClasses
Rows
styleClass
The entire table
Each of the attributes in Table 10–7 can specify more than one style. If columnClasses
or rowClasses specifies more than one style, the styles are applied to the columns or
rows in the order that the styles are listed in the attribute. For example, if
columnClasses specifies styles list-column-center and list-column-right, and if
the table has two columns, the first column will have style list-column-center, and
the second column will have style list-column-right.
If the style attribute specifies more styles than there are columns or rows, the
remaining styles will be assigned to columns or rows starting from the first column or
row. Similarly, if the style attribute specifies fewer styles than there are columns or
rows, the remaining columns or rows will be assigned styles starting from the first
style.
10.2.13 Displaying Error Messages with the h:message and h:messages Tags
The h:message and h:messages tags are used to display error messages when
conversion or validation fails. The h:message tag displays error messages related to a
specific input component, whereas the h:messages tag displays the error messages for
the entire page.
Here is an example h:message tag from the guessnumber-jsf application:
<p>
<h:inputText id="userNo"
title="Type a number from 0 to 10:"
value="#{userNumberBean.userNumber}">
<f:validateLongRange minimum="#{userNumberBean.minimum}"
maximum="#{userNumberBean.maximum}"/>
</h:inputText>
<h:commandButton id="submit" value="Submit"
action="response"/>
</p>
<h:message showSummary="true" showDetail="false"
style="color: #d20005;
font-family: 'New Century Schoolbook', serif;
font-style: oblique;
text-decoration: overline"
id="errors1"
for="userNo"/>
The for attribute refers to the ID of the component that generated the error message.
The error message is displayed at the same location that the h:message tag appears in
the page. In this case, the error message will appear below the Submit button.
The style attribute allows you to specify the style of the text of the message. In the
example in this section, the text will be a shade of red, New Century Schoolbook, serif
font family, and oblique style, and a line will appear over the text. The message and
messages tags support many other attributes for defining styles. For more information
10-22 The Java EE 7 Tutorial
Adding Components to a Page Using HTML Tag Library Tags
on these attributes, refer to the documentation at
http://docs.oracle.com/javaee/7/javaserverfaces/2.2/vdldocs/face
lets/.
Another attribute supported by the h:messages tag is the layout attribute. Its default
value is list, which indicates that the messages are displayed in a bullet list using the
HTML ul and li elements. If you set the attribute value to table, the messages will be
rendered in a table using the HTML table element.
The preceding example shows a standard validator that is registered on the input
component. The message tag displays the error message that is associated with this
validator when the validator cannot validate the input component's value. In general,
when you register a converter or validator on a component, you are queueing the error
messages associated with the converter or validator on the component. The h:message
and h:messages tags display the appropriate error messages that are queued on the
component when the validators or converters registered on that component fail to
convert or validate the component's value.
Standard error messages are provided with standard converters and standard
validators. An application architect can override these standard messages and supply
error messages for custom converters and validators by registering custom error
messages with the application.
10.2.14 Creating Bookmarkable URLs with the h:button and h:link Tags
The ability to create bookmarkable URLs refers to the ability to generate links based on
a specified navigation outcome and on component parameters.
In HTTP, most browsers by default send GET requests for URL retrieval and POST
requests for data processing. The GET requests can have query parameters and can be
cached, which is not advised for POST requests, which send data to servers for
processing. The other JavaServer Faces tags capable of generating links use either
simple GET requests, as in the case of h:outputLink, or POST requests, as in the case
of h:commandLink or h:commandButton tags. GET requests with query parameters
provide finer granularity to URL strings. These URLs are created with one or more
name=value parameters appended to the simple URL after a ? character and separated
by either &; or & strings.
To create a bookmarkable URL, use an h:link or h:button tag. Both of these tags can
generate a link based on the outcome attribute of the component. For example:
<h:link outcome="somepage" value="Message" />
The h:link tag will generate a URL link that points to the somepage.xhtml file on the
same server. The following sample HTML is generated from the preceding tag,
assuming that the application name is simplebookmark:
<a href="/simplebookmark/somepage.xhtml>Message</a>
This is a simple GET request that cannot pass any data from page to page. To create
more complex GET requests and utilize the complete functionality of the h:link tag,
use view parameters.
10.2.15 Using View Parameters to Configure Bookmarkable URLs
To pass a parameter from one page to another, use the includeViewParams attribute in
your h:link tag and, in addition, use an f:param tag to specify the name and value to
be passed. Here the h:link tag specifies the outcome page as personal.xhtml and
provides a parameter named Result whose value is a managed bean property:
Using JavaServer Faces Technology in Web Pages 10-23
Adding Components to a Page Using HTML Tag Library Tags
<h:body>
<h:form>
<h:graphicImage url="#{resource['images:duke.waving.gif']}"
alt="Duke waving his hand"/>
<h2>Hello, #{hello.name}!</h2>
<p>I've made your
<h:link outcome="personal" value="personal greeting page!"
includeViewParams="true">
<f:param name="Result" value="#{hello.name}"/>
</h:link>
</p>
<h:commandButton id="back" value="Back" action="index" />
</h:form>
</h:body>
If the includeViewParams attribute is set on the component, the view parameters are
added to the hyperlink. Therefore, the resulting URL will look something like this if
the value of hello.name is Timmy:
http://localhost:8080/bookmarks/personal.xhtml?Result=Timmy
On the outcome page, specify the core tags f:metadata and f:viewparam as the source
of parameters for configuring the URLs. View parameters are declared as part of
f:metadata for a page, as shown in the following example:
<f:metadata>
<f:viewParam name="Result" value="#{hello.name}"/>
</f:metadata>
This allows you to specify the bean property value on the page:
<h:outputText value="Howdy, #{hello.name}!" />
As a view parameter, the name also appears in the page's URL. If you edit the URL,
you change the output on the page.
Because the URL can be the result of various parameter values, the order of the URL
creation has been predefined. The order in which the various parameter values are
read is as follows:
1.
Component
2.
Navigation-case parameters
3.
View parameters
10.2.16 The bookmarks Example Application
The bookmarks example application modifies the hello1 application described in A
Web Module That Uses JavaServer Faces Technology: The hello1 Example to use a
bookmarkable URL that uses view parameters.
Like hello1, the application includes the Hello.java managed bean, an index.xhtml
page, and a response.xhtml page. In addition, it includes a personal.xhtml page, to
which a bookmarkable URL and view parameters are passed from the response.xhtml
page, as described in Using View Parameters to Configure Bookmarkable URLs.
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
bookmarks example. The source code for this example is in the
tut-install/examples/web/jsf/bookmarks/ directory.
10-24 The Java EE 7 Tutorial
Adding Components to a Page Using HTML Tag Library Tags
10.2.16.1 To Build, Package, and Deploy the bookmarks Example Using NetBeans
IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsf
4.
Select the bookmarks folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the bookmarks project and select Build.
This option builds the example application and deploys it to your GlassFish Server
instance.
10.2.16.2 To Build, Package, and Deploy the bookmarks Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/jsf/bookmarks/
3.
Enter the following command:
mvn install
This command builds and packages the application into a WAR file,
bookmarks.war, that is located in the target directory. It then deploys the WAR
file to your GlassFish Server instance.
10.2.16.3 To Run the bookmarks Example
1.
Enter the following URL in your web browser:
http://localhost:8080/bookmarks
2.
In the text field, enter a name and click Submit.
3.
On the response page, move your mouse over the "personal greeting page" link to
view the URL with the view parameter, then click the link.
The personal.xhtml page opens, displaying a greeting to the name you typed.
4.
In the URL field, modify the Result parameter value and press Return.
The name in the greeting changes to what you typed.
10.2.17 Resource Relocation Using h:outputScript and h:outputStylesheet Tags
Resource relocation refers to the ability of a JavaServer Faces application to specify the
location where a resource can be rendered. Resource relocation can be defined with the
following HTML tags:
■
h:outputScript
■
h:outputStylesheet
Using JavaServer Faces Technology in Web Pages 10-25
Adding Components to a Page Using HTML Tag Library Tags
These tags have name and target attributes, which can be used to define the render
location. For a complete list of attributes for these tags, see the documentation at
http://docs.oracle.com/javaee/7/javaserverfaces/2.2/vdldocs/face
lets/.
For the h:outputScript tag, the name and target attributes define where the output of
a resource may appear. Here is an example:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head id="head">
<title>Resource Relocation</title>
</h:head>
<h:body id="body">
<h:form id="form">
<h:outputScript name="hello.js"/>
<h:outputStylesheet name="hello.css"/>
</h:form>
</h:body>
</html>
Because the target attribute is not defined in the tags, the style sheet hello.css is
rendered in the head element of the page, and the hello.js script is rendered in the
body of the page.
Here is the HTML generated by the preceding code:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Resource Relocation</title>
<link type="text/css" rel="stylesheet"
href="/context-root/javax.faces.resource/hello.css"/>
</head>
<body>
<form id="form" name="form" method="post"
action="..." enctype="...">
<script type="text/javascript"
src="/context-root/javax.faces.resource/hello.js">
</script>
</form>
</body>
</html>
If you set the target attribute for the h:outputScript tag, the incoming GET request
provides the location parameter. Here is an example:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head id="head">
<title>Resource Relocation</title>
</h:head>
<h:body id="body">
<h:form id="form">
<h:outputScript name="hello.js" target="#{param.location}"/>
<h:outputStylesheet name="hello.css"/>
</h:form>
</h:body>
</html>
In this case, if the incoming request does not provide a location parameter, the default
locations will still apply: The style sheet is rendered in the head, and the script is
10-26 The Java EE 7 Tutorial
Using Core Tags
rendered inline. However, if the incoming request specifies the location parameter as
the head, both the style sheet and the script will be rendered in the head element.
The HTML generated by the preceding code is as follows:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Resource Relocation</title>
<link type="text/css" rel="stylesheet"
href="/context-root/javax.faces.resource/hello.css"/>
<script type="text/javascript"
src="/context-root/javax.faces.resource/hello.js">
</script>
</head>
<body>
<form id="form" name="form" method="post"
action="..." enctype="...">
</form>
</body>
</html>
Similarly, if the incoming request provides the location parameter as the body, the
script will be rendered in the body element.
The preceding section describes simple uses for resource relocation. That feature can
add even more functionality for the components and pages. A page author does not
have to know the location of a resource or its placement.
By using a @ResourceDependency annotation for the components, component authors
can define the resources for the component, such as a style sheet and script. This
allows the page authors freedom from defining resource locations.
10.3 Using Core Tags
The tags included in the JavaServer Faces core tag library are used to perform core
actions that are not performed by HTML tags.
Table 10–8 lists the event-handling core tags.
Table 10–8
Event-Handling Core Tags
Tag
Function
f:actionListener
Adds an action listener to a parent component
f:phaseListener
Adds a PhaseListener to a page
f:setPropertyActionListener
Registers a special action listener whose sole purpose is to
push a value into a managed bean when a form is
submitted
f:valueChangeListener
Adds a value-change listener to a parent component
Table 10–9 lists the data-conversion core tags.
Table 10–9
Data-Conversion Core Tags
Tag
Function
f:converter
Adds an arbitrary converter to the parent component
f:convertDateTime
Adds a DateTimeConverter instance to the parent component
f:convertNumber
Adds a NumberConverter instance to the parent component
Using JavaServer Faces Technology in Web Pages 10-27
Using Core Tags
Table 10–10 lists the facet core tags.
Table 10–10
Facet Core Tags
Tag
Function
f:facet
Adds a nested component that has a special relationship to its
enclosing tag
f:metadata
Registers a facet on a parent component
Table 10–11 lists the core tags that represent items in a list.
Table 10–11
Core Tags That Represent Items in a List
Tag
Function
f:selectItem
Represents one item in a list of items
f:selectItems
Represents a set of items
Table 10–12 lists the validator core tags.
Table 10–12
Validator Core Tags
Tag
Function
f:validateDoubleRange
Adds a DoubleRangeValidator to a component
f:validateLength
Adds a LengthValidator to a component
f:validateLongRange
Adds a LongRangeValidator to a component
f:validator
Adds a custom validator to a component
f:validateRegEx
Adds a RegExValidator to a component
f:validateBean
Delegates the validation of a local value to a BeanValidator
f:validateRequired
Enforces the presence of a value in a component
Table 10–13 lists the core tags that fall into other categories.
Table 10–13
Miscellaneous Core Tags
Tag Category
Tag
Function
Attribute configuration
f:attribute
Adds configurable attributes to a parent
component
Localization
f:loadBundle
Specifies a ResourceBundle that is exposed as a
Map
Parameter substitution
f:param
Substitutes parameters into a MessageFormat
instance and adds query string name-value pairs
to a URL
Ajax
f:ajax
Associates an Ajax action with a single
component or a group of components based on
placement
Event
f:event
Allows installing a
ComponentSystemEventListener on a component
These tags, which are used in conjunction with component tags, are explained in other
sections of this tutorial.
10-28 The Java EE 7 Tutorial
Using Core Tags
Table 10–14 lists the sections that explain how to use specific core tags.
Table 10–14
Where the Core Tags Are Explained
Tags
Where Explained
Event-handling tags
Registering Listeners on Components
Data-conversion tags
Using the Standard Converters
f:facet
Using Data-Bound Table Components and Laying Out Components
with the h:panelGrid and h:panelGroup Tags
f:loadBundle
Setting the Resource Bundle
f:metadata
Using View Parameters to Configure Bookmarkable URLs
f:param
Displaying a Formatted Message with the h:outputFormat Tag
f:selectItem and
f:selectItems
Using the f:selectItem and f:selectItems Tags
Validator tags
Using the Standard Validators
f:ajax
Chapter 13, "Using Ajax with JavaServer Faces Technology"
Using JavaServer Faces Technology in Web Pages 10-29
Using Core Tags
10-30 The Java EE 7 Tutorial
11
Using Converters, Listeners, and Validators
11
The previous chapter described components and explained how to add them to a web
page. This chapter provides information on adding more functionality to the
components through converters, listeners, and validators.
■
■
■
Converters are used to convert data that is received from the input components.
Converters allow an application to bring the strongly typed features of the Java
programming language into the String-based world of HTTP servlet
programming.
Listeners are used to listen to the events happening in the page and perform
actions as defined.
Validators are used to validate the data that is received from the input
components. Validators allow an application to express constraints on form input
data to ensure that the necessary requirements are met before the input data is
processed.
The following topics are addressed here:
■
Using the Standard Converters
■
Registering Listeners on Components
■
Using the Standard Validators
■
Referencing a Managed Bean Method
11.1 Using the Standard Converters
The JavaServer Faces implementation provides a set of Converter implementations
that you can use to convert component data. The purpose of conversion is to take the
String-based data coming in from the Servlet API and convert it to strongly typed
Java objects suitable for the business domain. For more information on the conceptual
details of the conversion model, see Conversion Model.
The standard Converter implementations are located in the javax.faces.convert
package. Normally, converters are implicitly assigned based on the type of the EL
expression pointed to by the value of the component. However, these converters can
also be accessed by a converter ID. Table 11–1 shows the converter classes and their
associated converter IDs.
Table 11–1
Converter Classes and Converter IDs
Class in the javax.faces.convert Package
Converter ID
BigDecimalConverter
javax.faces.BigDecimal
Using Converters, Listeners, and Validators 11-1
Using the Standard Converters
Table 11–1 (Cont.) Converter Classes and Converter IDs
Class in the javax.faces.convert Package
Converter ID
BigIntegerConverter
javax.faces.BigInteger
BooleanConverter
javax.faces.Boolean
ByteConverter
javax.faces.Byte
CharacterConverter
javax.faces.Character
DateTimeConverter
javax.faces.DateTime
DoubleConverter
javax.faces.Double
EnumConverter
javax.faces.Enum
FloatConverter
javax.faces.Float
IntegerConverter
javax.faces.Integer
LongConverter
javax.faces.Long
NumberConverter
javax.faces.Number
ShortConverter
javax.faces.Short
A standard error message is associated with each of these converters. If you have
registered one of these converters onto a component on your page and the converter is
not able to convert the component's value, the converter's error message will display
on the page. For example, the following error message appears if
BigIntegerConverter fails to convert a value:
{0} must be a number consisting of one or more digits
In this case, the {0} substitution parameter will be replaced with the name of the input
component on which the converter is registered.
Two of the standard converters (DateTimeConverter and NumberConverter) have their
own tags, which allow you to configure the format of the component data using the
tag attributes. For more information about using DateTimeConverter, see Using
DateTimeConverter. For more information about using NumberConverter, see Using
NumberConverter. The following section explains how to convert a component's
value, including how to register other standard converters with a component.
11.1.1 Converting a Component's Value
To use a particular converter to convert a component's value, you need to register the
converter onto the component. You can register any of the standard converters in one
of the following ways.
■
■
■
■
Nest one of the standard converter tags inside the component's tag. These tags are
f:convertDateTime and f:convertNumber, which are described in Using
DateTimeConverter and Using NumberConverter, respectively.
Bind the value of the component to a managed bean property of the same type as
the converter. This is the most common technique.
Refer to the converter from the component tag's converter attribute, specifying
the ID of the converter class.
Nest an f:converter tag inside of the component tag, and use either the
f:converter tag's converterId attribute or its binding attribute to refer to the
converter.
11-2 The Java EE 7 Tutorial
Using the Standard Converters
As an example of the second technique, if you want a component's data to be
converted to an Integer, you can simply bind the component's value to a managed
bean property. Here is an example:
Integer age = 0;
public Integer getAge(){ return age;}
public void setAge(Integer age) {this.age = age;}
The data from the h:inputText tag in the this example will be converted to a
java.lang.Integer value. The Integer type is a supported type of NumberConverter.
If you don't need to specify any formatting instructions using the f:convertNumber tag
attributes, and if one of the standard converters will suffice, you can simply reference
that converter by using the component tag's converter attribute.
You can also nest an f:converter tag within the component tag and use either the
converter tag's converterId attribute or its binding attribute to reference the
converter.
The converterId attribute must reference the converter's ID. Here is an example that
uses one of the converter IDs listed in Table 11–1:
<h:inputText value="#{loginBean.age}">
<f:converter converterId="javax.faces.Integer" />
</h:inputText>
Instead of using the converterId attribute, the f:converter tag can use the binding
attribute. The binding attribute must resolve to a bean property that accepts and
returns an appropriate Converter instance.
You can also create custom converters and register them on components using the
f:converter tag. For details, see Creating and Using a Custom Converter.
11.1.2 Using DateTimeConverter
You can convert a component's data to a java.util.Date by nesting the
convertDateTime tag inside the component tag. The convertDateTime tag has several
attributes that allow you to specify the format and type of the data. Table 11–2 lists the
attributes.
Here is a simple example of a convertDateTime tag:
<h:outputText value="#{cashierBean.shipDate}">
<f:convertDateTime type="date" dateStyle="full" />
</h:outputText>
When binding the DateTimeConverter to a component, ensure that the managed bean
property to which the component is bound is of type java.util.Date. In the
preceding example, cashierBean.shipDate must be of type java.util.Date.
The example tag can display the following output:
Saturday, September 21, 2013
You can also display the same date and time by using the following tag in which the
date format is specified:
<h:outputText value="#{cashierBean.shipDate}">
<f:convertDateTime pattern="EEEEEEEE, MMM dd, yyyy" />
</h:outputText>
If you want to display the example date in Spanish, you can use the locale attribute:
Using Converters, Listeners, and Validators 11-3
Using the Standard Converters
<h:outputText value="#{cashierBean.shipDate}">
<f:convertDateTime dateStyle="full"
locale="es"
timeStyle="long" type="both" />
</h:outputText>
This tag would display the following output:
jueves 24 de octubre de 2013 15:07:04 GMT
Refer to the "Customizing Formats" lesson of the Java Tutorial at
http://docs.oracle.com/javase/tutorial/i18n/format/simpleDateFor
mat.html for more information on how to format the output using the pattern
attribute of the convertDateTime tag.
Table 11–2
Attributes for the f:convertDateTime Tag
Attribute
Type
Description
binding
DateTimeConverter
Used to bind a converter to a managed bean property.
dateStyle
String
Defines the format, as specified by java.text.DateFormat,
of a date or the date part of a date string. Applied only if
type is date or both and if pattern is not defined. Valid
values: default, short, medium, long, and full. If no value
is specified, default is used.
for
String
Used with composite components. Refers to one of the
objects within the composite component inside which this
tag is nested.
locale
String or Locale
Locale whose predefined styles for dates and times are
used during formatting or parsing. If not specified, the
Locale returned by FacesContext.getLocale will be used.
pattern
String
Custom formatting pattern that determines how the
date/time string should be formatted and parsed. If this
attribute is specified, dateStyle, timeStyle, and type
attributes are ignored.
timeStyle
String
Defines the format, as specified by java.text.DateFormat,
of a time or the time part of a date string. Applied only if
type is time and pattern is not defined. Valid values:
default, short, medium, long, and full. If no value is
specified, default is used.
timeZone
String or TimeZone
Time zone in which to interpret any time information in the
date string.
type
String
Specifies whether the string value will contain a date, a
time, or both. Valid values are date, time, or both. If no
value is specified, date is used.
11.1.3 Using NumberConverter
You can convert a component's data to a java.lang.Number by nesting the
convertNumber tag inside the component tag. The convertNumber tag has several
attributes that allow you to specify the format and type of the data. Table 11–3 lists the
attributes.
The following example uses a convertNumber tag to display the total prices of the
contents of a shopping cart:
<h:outputText value="#{cart.total}">
<f:convertNumber currencySymbol="$" type="currency"/>
</h:outputText>
11-4 The Java EE 7 Tutorial
Using the Standard Converters
When binding the NumberConverter to a component, ensure that the managed bean
property to which the component is bound is of a primitive type or has a type of
java.lang.Number. In the preceding example, cart.total is of type double.
Here is an example of a number that this tag can display:
$934
This result can also be displayed by using the following tag in which the currency
pattern is specified:
<h:outputText id="cartTotal" value="#{cart.total}">
<f:convertNumber pattern="$####" />
</h:outputText>
See the "Customizing Formats" lesson of the Java Tutorial at
http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat
.html for more information on how to format the output by using the pattern
attribute of the convertNumber tag.
Table 11–3
Attributes for the f:convertNumber Tag
Attribute
Type
Description
binding
NumberConverter
Used to bind a converter to a managed bean
property.
currencyCode
String
ISO 4217 currency code, used only when
formatting currencies.
currencySymbol
String
Currency symbol, applied only when formatting
currencies.
for
String
Used with composite components. Refers to one
of the objects within the composite component
inside which this tag is nested.
groupingUsed
Boolean
Specifies whether formatted output contains
grouping separators.
integerOnly
Boolean
Specifies whether only the integer part of the
value will be parsed.
locale
String or Locale
Locale whose number styles are used to format
or parse data.
maxFractionDigits
int
Maximum number of digits formatted in the
fractional part of the output.
maxIntegerDigits
int
Maximum number of digits formatted in the
integer part of the output.
minFractionDigits
int
Minimum number of digits formatted in the
fractional part of the output.
minIntegerDigits
int
Minimum number of digits formatted in the
integer part of the output.
pattern
String
Custom formatting pattern that determines how
the number string is formatted and parsed.
type
String
Specifies whether the string value is parsed and
formatted as a number, currency, or percentage.
If not specified, number is used.
Using Converters, Listeners, and Validators 11-5
Registering Listeners on Components
11.2 Registering Listeners on Components
An application developer can implement listeners as classes or as managed bean
methods. If a listener is a managed bean method, the page author references the
method from either the component's valueChangeListener attribute or its
actionListener attribute. If the listener is a class, the page author can reference the
listener from either an f:valueChangeListener tag or an f:actionListener tag and
nest the tag inside the component tag to register the listener on the component.
Referencing a Method That Handles an Action Event and Referencing a Method That
Handles a Value-Change Event explain how a page author uses the
valueChangeListener and actionListener attributes to reference managed bean
methods that handle events.
This section explains how to register a NameChanged value-change listener and a
BookChange action listener implementation on components. The Duke's Bookstore case
study includes both of these listeners.
11.2.1 Registering a Value-Change Listener on a Component
A page author can register a ValueChangeListener implementation on a component
that implements EditableValueHolder by nesting an f:valueChangeListener tag
within the component's tag on the page. The f:valueChangeListener tag supports the
attributes shown in Table 11–4, one of which must be used.
Table 11–4
Attributes for the f:valueChangeListener Tag
Attribute
Description
type
References the fully qualified class name of a ValueChangeListener
implementation. Can accept a literal or a value expression.
binding
References an object that implements ValueChangeListener. Can accept
only a value expression, which must point to a managed bean property
that accepts and returns a ValueChangeListener implementation.
The following example shows a value-change listener registered on a component:
<h:inputText id="name"
size="30"
value="#{cashierBean.name}"
required="true"
requiredMessage="#{bundle.ReqCustomerName}">
<f:valueChangeListener
type="javaeetutorial.dukesbookstore.listeners.NameChanged" />
</h:inputText>
In the example, the core tag type attribute specifies the custom NameChanged listener as
the ValueChangeListener implementation registered on the name component.
After this component tag is processed and local values have been validated, its
corresponding component instance will queue the ValueChangeEvent associated with
the specified ValueChangeListener to the component.
The binding attribute is used to bind a ValueChangeListener implementation to a
managed bean property. This attribute works in a similar way to the binding attribute
supported by the standard converter tags. See Binding Component Values and
Instances to Managed Bean Properties for more information.
11-6 The Java EE 7 Tutorial
Registering Listeners on Components
11.2.2 Registering an Action Listener on a Component
A page author can register an ActionListener implementation on a command
component by nesting an f:actionListener tag within the component's tag on the
page. Similarly to the f:valueChangeListener tag, the f:actionListener tag supports
both the type and binding attributes. One of these attributes must be used to reference
the action listener.
Here is an example of an h:commandLink tag that references an ActionListener
implementation:
<h:commandLink id="Duke" action="bookstore">
<f:actionListener
type="javaeetutorial.dukesbookstore.listeners.LinkBookChangeListener" />
<h:outputText value="#{bundle.Book201}"/>
</h:commandLink>
The type attribute of the f:actionListener tag specifies the fully qualified class name
of the ActionListener implementation. Similarly to the f:valueChangeListener tag,
the f:actionListener tag also supports the binding attribute. See Binding Converters,
Listeners, and Validators to Managed Bean Properties for more information about
binding listeners to managed bean properties.
In addition to the actionListener tag that allows you register a custom listener onto a
component, the core tag library includes the f:setPropertyActionListener tag. You
use this tag to register a special action listener onto the ActionSource instance
associated with a component. When the component is activated, the listener will store
the object referenced by the tag's value attribute into the object referenced by the tag's
target attribute.
The bookcatalog.xhtml page of the Duke's Bookstore application uses
f:setPropertyActionListener with two components: the h:commandLink component
used to link to the bookdetails.xhtml page and the h:commandButton component
used to add a book to the cart:
<h:dataTable id="books"
value="#{store.books}"
var="book"
headerClass="list-header"
styleClass="list-background"
rowClasses="list-row-even, list-row-odd"
border="1"
summary="#{bundle.BookCatalog}" >
...
<h:column>
<f:facet name="header">
<h:outputText value="#{bundle.ItemTitle}"/>
</f:facet>
<h:commandLink action="#{catalog.details}"
value="#{book.title}">
<f:setPropertyActionListener target="#{requestScope.book}"
value="#{book}"/>
</h:commandLink>
</h:column>
...
<h:column>
<f:facet name="header">
<h:outputText value="#{bundle.CartAdd}"/>
</f:facet>
<h:commandButton id="add"
action="#{catalog.add}"
Using Converters, Listeners, and Validators 11-7
Using the Standard Validators
value="#{bundle.CartAdd}">
<f:setPropertyActionListener target="#{requestScope.book}"
value="#{book}"/>
</h:commandButton>
</h:column>
The h:commandLink and h:commandButton tags are within an h:dataTable tag, which
iterates over the list of books. The var attribute refers to a single book in the list of
books.
The object referenced by the var attribute of an h:dataTable tag is in page scope.
However, in this case you need to put this object into request scope so that when the
user activates the commandLink component to go to bookdetails.xhtml or activates the
commandButton component to go to bookcatalog.xhtml, the book data is available to
those pages. Therefore, the f:setPropertyActionListener tag is used to set the
current book object into request scope when the commandLink or commandButton
component is activated.
In the preceding example, the f:setPropertyActionListener tag's value attribute
references the book object. The f:setPropertyActionListener tag's target attribute
references the value expression requestScope.book, which is where the book object
referenced by the value attribute is stored when the commandLink or the
commandButton component is activated.
11.3 Using the Standard Validators
JavaServer Faces technology provides a set of standard classes and associated tags that
page authors and application developers can use to validate a component's data.
Table 11–5 lists all the standard validator classes and the tags that allow you to use the
validators from the page.
Table 11–5
The Validator Classes
Validator Class
Tag
Function
BeanValidator
validateBean
Registers a bean validator for the
component.
DoubleRangeValidator
validateDoubleRange
Checks whether the local value of a
component is within a certain range. The
value must be floating-point or convertible
to floating-point.
LengthValidator
validateLength
Checks whether the length of a
component's local value is within a certain
range. The value must be a
java.lang.String.
LongRangeValidator
validateLongRange
Checks whether the local value of a
component is within a certain range. The
value must be any numeric type or String
that can be converted to a long.
RegexValidator
validateRegex
Checks whether the local value of a
component is a match against a regular
expression from the java.util.regex
package.
RequiredValidator
validateRequired
Ensures that the local value is not empty on
an EditableValueHolder component.
11-8 The Java EE 7 Tutorial
Using the Standard Validators
All of these validator classes implement the Validator interface. Component writers
and application developers can also implement this interface to define their own set of
constraints for a component's value.
Similar to the standard converters, each of these validators has one or more standard
error messages associated with it. If you have registered one of these validators onto a
component on your page and the validator is unable to validate the component's
value, the validator's error message will display on the page. For example, the error
message that displays when the component's value exceeds the maximum value
allowed by LongRangeValidator is as follows:
{1}: Validation Error: Value is greater than allowable maximum of "{0}"
In this case, the {1} substitution parameter is replaced by the component's label or id,
and the {0} substitution parameter is replaced with the maximum value allowed by
the validator.
See Displaying Error Messages with the h:message and h:messages Tags for
information on how to display validation error messages on the page when validation
fails.
Instead of using the standard validators, you can use Bean Validation to validate data.
If you specify bean validation constraints on your managed bean properties, the
constraints are automatically placed on the corresponding fields on your applications
web pages. See Chapter 21, "Introduction to Bean Validation" for more information.
You do not need to specify the validateBean tag to use Bean Validation, but the tag
allows you to use more advanced Bean Validation features. For example, you can use
the validationGroups attribute of the tag to specify constraint groups.
You can also create and register custom validators, although Bean Validation has made
this feature less useful. For details, see Creating and Using a Custom Validator.
11.3.1 Validating a Component's Value
To validate a component's value using a particular validator, you need to register that
validator on the component. You can do this in one of the following ways.
■
■
■
Nest the validator's corresponding tag (shown in Table 11–5) inside the
component's tag. Using Validator Tags explains how to use the
validateLongRange tag. You can use the other standard tags in the same way.
Refer to a method that performs the validation from the component tag's
validator attribute.
Nest a validator tag inside the component tag, and use either the validator tag's
validatorId attribute or its binding attribute to refer to the validator.
See Referencing a Method That Performs Validation for more information on using the
validator attribute.
The validatorId attribute works similarly to the converterId attribute of the
converter tag, as described in Converting a Component's Value.
Keep in mind that validation can be performed only on components that implement
EditableValueHolder, because these components accept values that can be validated.
11.3.2 Using Validator Tags
The following example shows how to use the f:validateLongRange validator tag on
an input component named quantity:
<h:inputText id="quantity" size="4" value="#{item.quantity}">
Using Converters, Listeners, and Validators 11-9
Referencing a Managed Bean Method
<f:validateLongRange minimum="1"/>
</h:inputText>
<h:message for="quantity"/>
This tag requires the user to enter a number that is at least 1. The validateLongRange
tag also has a maximum attribute, which sets a maximum value for the input.
The attributes of all the standard validator tags accept EL value expressions. This
means that the attributes can reference managed bean properties rather than specify
literal values. For example, the f:validateLongRange tag in the preceding example
can reference managed bean properties called minimum and maximum to get the
minimum and maximum values acceptable to the validator implementation, as shown
in this snippet from the guessnumber-jsf example:
<h:inputText id="userNo"
title="Type a number from 0 to 10:"
value="#{userNumberBean.userNumber}">
<f:validateLongRange minimum="#{userNumberBean.minimum}"
maximum="#{userNumberBean.maximum}"/>
</h:inputText>
The following f:validateRegex tag shows how you might ensure that a password is
from 4 to 10 characters long and contains at least one digit, at least one lowercase
letter, and at least one uppercase letter:
<f:validateRegex pattern="((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,10})"
for="passwordVal"/>
11.4 Referencing a Managed Bean Method
A component tag has a set of attributes for referencing managed bean methods that
can perform certain functions for the component associated with the tag. These
attributes are summarized in Table 11–6.
Table 11–6
Component Tag Attributes That Reference Managed Bean Methods
Attribute
Function
action
Refers to a managed bean method that performs navigation
processing for the component and returns a logical outcome String
actionListener
Refers to a managed bean method that handles action events
validator
Refers to a managed bean method that performs validation on the
component's value
valueChangeListener
Refers to a managed bean method that handles value-change events
Only components that implement ActionSource can use the action and
actionListener attributes. Only components that implement EditableValueHolder
can use the validator or valueChangeListener attributes.
The component tag refers to a managed bean method using a method expression as a
value of one of the attributes. The method referenced by an attribute must follow a
particular signature, which is defined by the tag attribute's definition in the
documentation at
http://docs.oracle.com/javaee/7/javaserverfaces/2.2/vdldocs/face
lets/. For example, the definition of the validator attribute of the inputText tag is
the following:
11-10 The Java EE 7 Tutorial
Referencing a Managed Bean Method
void validate(javax.faces.context.FacesContext,
javax.faces.component.UIComponent, java.lang.Object)
The following sections give examples of how to use the attributes.
11.4.1 Referencing a Method That Performs Navigation
If your page includes a component, such as a button or a link, that causes the
application to navigate to another page when the component is activated, the tag
corresponding to this component must include an action attribute. This attribute does
one of the following:
■
■
Specifies a logical outcome String that tells the application which page to access
next
References a managed bean method that performs some processing and returns a
logical outcome String
The following example shows how to reference a navigation method:
<h:commandButton value="#{bundle.Submit}"
action="#{cashierBean.submit}" />
See Writing a Method to Handle Navigation for information on how to write such a
method.
11.4.2 Referencing a Method That Handles an Action Event
If a component on your page generates an action event, and if that event is handled by
a managed bean method, you refer to the method by using the component's
actionListener attribute.
The following example shows how such a method could be referenced:
<h:commandLink id="Duke" action="bookstore"
actionListener="#{actionBean.chooseBookFromLink}">
The actionListener attribute of this component tag references the
chooseBookFromLink method using a method expression. The chooseBookFromLink
method handles the event when the user clicks the link rendered by this component.
See Writing a Method to Handle an Action Event for information on how to write such
a method.
11.4.3 Referencing a Method That Performs Validation
If the input of one of the components on your page is validated by a managed bean
method, refer to the method from the component's tag by using the validator
attribute.
The following simplified example from The guessnumber-cdi CDI Example shows
how to reference a method that performs validation on inputGuess, an input
component:
<h:inputText id="inputGuess"
value="#{userNumberBean.userNumber}"
required="true" size="3"
disabled="#{userNumberBean.number eq userNumberBean.userNumber ...}"
validator="#{userNumberBean.validateNumberRange}">
</h:inputText>
Using Converters, Listeners, and Validators
11-11
Referencing a Managed Bean Method
The managed bean method validateNumberRange verifies that the input value is
within the valid range, which changes each time another guess is made. See Writing a
Method to Perform Validation for information on how to write such a method.
11.4.4 Referencing a Method That Handles a Value-Change Event
If you want a component on your page to generate a value-change event and you want
that event to be handled by a managed bean method instead of a
ValueChangeListener implementation, you refer to the method by using the
component's valueChangeListener attribute:
<h:inputText id="name"
size="30"
value="#{cashierBean.name}"
required="true"
valueChangeListener="#{cashierBean.processValueChange}" />
</h:inputText>
The valueChangeListener attribute of this component tag references the
processValueChange method of CashierBean by using a method expression. The
processValueChange method handles the event of a user entering a name in the input
field rendered by this component.
Writing a Method to Handle a Value-Change Event describes how to implement a
method that handles a ValueChangeEvent.
11-12 The Java EE 7 Tutorial
12
Developing with JavaServer Faces
Technology
12
This chapter provides an overview of managed beans and explains how to write
methods and properties of managed beans that are used by a JavaServer Faces
application. This chapter also introduces the Bean Validation feature.
Chapter 10, "Using JavaServer Faces Technology in Web Pages" and Chapter 11, "Using
Converters, Listeners, and Validators" show how to add components to a page and
connect them to server-side objects by using component tags and core tags. These
chapters also show how to provide additional functionality to the components through
converters, listeners, and validators. Developing a JavaServer Faces application also
involves the task of programming the server-side objects: managed beans, converters,
event handlers, and validators.
The following topics are addressed here:
■
Managed Beans in JavaServer Faces Technology
■
Writing Bean Properties
■
Writing Managed Bean Methods
12.1 Managed Beans in JavaServer Faces Technology
A typical JavaServer Faces application includes one or more managed beans, each of
which can be associated with the components used in a particular page. This section
introduces the basic concepts of creating, configuring, and using managed beans in an
application.
12.1.1 Creating a Managed Bean
A managed bean is created with a constructor with no arguments, a set of properties,
and a set of methods that perform functions for a component. Each of the managed
bean properties can be bound to one of the following:
■
A component value
■
A component instance
■
A converter instance
■
A listener instance
■
A validator instance
The most common functions that managed bean methods perform include the
following:
Developing with JavaServer Faces Technology 12-1
Managed Beans in JavaServer Faces Technology
■
Validating a component's data
■
Handling an event fired by a component
■
Performing processing to determine the next page to which the application must
navigate
As with all JavaBeans components, a property consists of a private data field and a set
of accessor methods, as shown by this code:
private Integer userNumber = null;
...
public void setUserNumber(Integer user_number) {
userNumber = user_number;
}
public Integer getUserNumber() {
return userNumber;
}
When bound to a component's value, a bean property can be any of the basic primitive
and numeric types or any Java object type for which the application has access to an
appropriate converter. For example, a property can be of type java.util.Date if the
application has access to a converter that can convert the Date type to a String and
back again. See Writing Bean Properties for information on which types are accepted
by which component tags.
When a bean property is bound to a component instance, the property's type must be
the same as the component object. For example, if a
javax.faces.component.UISelectBoolean component is bound to the property, the
property must accept and return a UISelectBoolean object. Likewise, if the property is
bound to a converter, validator, or listener instance, the property must be of the
appropriate converter, validator, or listener type.
For more information on writing beans and their properties, see Writing Bean
Properties.
12.1.2 Using the EL to Reference Managed Beans
To bind component values and objects to managed bean properties or to reference
managed bean methods from component tags, page authors use the Expression
Language syntax. As explained in Overview of the EL, the following are some of the
features that the EL offers:
■
Deferred evaluation of expressions
■
The ability to use a value expression to both read and write data
■
Method expressions
Deferred evaluation of expressions is important because the JavaServer Faces lifecycle
is split into several phases in which component event handling, data conversion and
validation, and data propagation to external objects are all performed in an orderly
fashion. The implementation must be able to delay the evaluation of expressions until
the proper phase of the lifecycle has been reached. Therefore, the implementation's tag
attributes always use deferred-evaluation syntax, which is distinguished by the #{}
delimiter.
To store data in external objects, almost all JavaServer Faces tag attributes use lvalue
expressions, which are expressions that allow both getting and setting data on external
objects.
12-2 The Java EE 7 Tutorial
Writing Bean Properties
Finally, some component tag attributes accept method expressions that reference
methods that handle component events or validate or convert component data.
To illustrate a JavaServer Faces tag using the EL, the following tag references a method
that validates user input:
<h:inputText id="inputGuess"
value="#{userNumberBean.userNumber}"
required="true" size="3"
disabled="#{userNumberBean.number eq userNumberBean.userNumber ...}"
validator="#{userNumberBean.validateNumberRange}">
</h:inputText>
This tag binds the inputGuess component's value to the UserNumberBean.userNumber
managed bean property by using an lvalue expression. The tag uses a method
expression to refer to the UserNumberBean.validateNumberRange method, which
performs validation of the component's local value. The local value is whatever the
user types into the field corresponding to this tag. This method is invoked when the
expression is evaluated.
Nearly all JavaServer Faces tag attributes accept value expressions. In addition to
referencing bean properties, value expressions can reference lists, maps, arrays,
implicit objects, and resource bundles.
Another use of value expressions is to bind a component instance to a managed bean
property. A page author does this by referencing the property from the binding
attribute:
<h:outputLabel for="fanClub"
rendered="false"
binding="#{cashierBean.specialOfferText}">
value="#{bundle.DukeFanClub}"/>
</h:outputLabel>
In addition to using expressions with the standard component tags, you can configure
your custom component properties to accept expressions by creating
javax.el.ValueExpression or javax.el.MethodExpression instances for them.
For information on the EL, see Chapter 9, "Expression Language".
For information on referencing managed bean methods from component tags, see
Referencing a Managed Bean Method.
12.2 Writing Bean Properties
As explained in Managed Beans in JavaServer Faces Technology, a managed bean
property can be bound to one of the following items:
■
A component value
■
A component instance
■
A converter implementation
■
A listener implementation
■
A validator implementation
These properties follow the conventions of JavaBeans components (also called beans).
For more information on JavaBeans components, see the JavaBeans Tutorial at
http://docs.oracle.com/javase/tutorial/javabeans/index.html.
Developing with JavaServer Faces Technology 12-3
Writing Bean Properties
The component's tag binds the component's value to a managed bean property by
using its value attribute and binds the component's instance to a managed bean
property by using its binding attribute. Likewise, all the converter, listener, and
validator tags use their binding attributes to bind their associated implementations to
managed bean properties. See Binding Component Values and Instances to Managed
Bean Properties and Binding Converters, Listeners, and Validators to Managed Bean
Properties for more information.
To bind a component's value to a managed bean property, the type of the property
must match the type of the component's value to which it is bound. For example, if a
managed bean property is bound to a UISelectBoolean component's value, the
property should accept and return a boolean value or a Boolean wrapper Object
instance.
To bind a component instance to a managed bean property, the property must match
the type of component. For example, if a managed bean property is bound to a
UISelectBoolean instance, the property should accept and return a UISelectBoolean
value.
Similarly, to bind a converter, listener, or validator implementation to a managed bean
property, the property must accept and return the same type of converter, listener, or
validator object. For example, if you are using the convertDateTime tag to bind a
javax.faces.convert.DateTimeConverter to a property, that property must accept
and return a DateTimeConverter instance.
The rest of this section explains how to write properties that can be bound to
component values, to component instances for the component objects described in
Adding Components to a Page Using HTML Tag Library Tags, and to converter,
listener, and validator implementations.
12.2.1 Writing Properties Bound to Component Values
To write a managed bean property that is bound to a component's value, you must
match the property type to the component's value.
Table 12–1 lists the javax.faces.component classes and the acceptable types of their
values.
Table 12–1
Acceptable Types of Component Values
Component Class
Acceptable Types of Component Values
UIInput, UIOutput,
UISelectItem, UISelectOne
Any of the basic primitive and numeric types or any Java
programming language object type for which an appropriate
javax.faces.convert.Converter implementation is available
UIData
array of beans, List of beans, single bean, java.sql.ResultSet,
javax.servlet.jsp.jstl.sql.Result, javax.sql.RowSet
UISelectBoolean
boolean or Boolean
UISelectItems
java.lang.String, Collection, Array, Map
UISelectMany
array or List, although elements of the array or List can be
any of the standard types
When they bind components to properties by using the value attributes of the
component tags, page authors need to ensure that the corresponding properties match
the types of the components' values.
12-4 The Java EE 7 Tutorial
Writing Bean Properties
12.2.1.1 UIInput and UIOutput Properties
The UIInput and UIOutput component classes are represented by the component tags
that begin with h:input and h:output, respectively (for example, h:inputText and
h:outputText).
In the following example, an h:inputText tag binds the name component to the name
property of a managed bean called CashierBean.
<h:inputText id="name"
size="30"
value="#{cashierBean.name}"
...>
</h:inputText>
The following code snippet from the managed bean CashierBean shows the bean
property type bound by the preceding component tag:
protected String name = null;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
As described in Using the Standard Converters, to convert the value of an input or
output component you can either apply a converter or create the bean property bound
to the component with the matching type. Here is the example tag, from Using
DateTimeConverter, that displays the date on which items will be shipped.
<h:outputText value="#{cashierBean.shipDate}">
<f:convertDateTime type="date" dateStyle="full" />
</h:outputText>
The bean property represented by this tag must have a type of java.util.Date. The
following code snippet shows the shipDate property, from the managed bean
CashierBean, that is bound by the tag's value in the preceding example:
private Date shipDate;
public Date getShipDate() {
return this.shipDate;
}
public void setShipDate(Date shipDate) {
this.shipDate = shipDate;
}
12.2.1.2 UIData Properties
The UIData component class is represented by the h:dataTable component tag.
UIData components must be bound to one of the managed bean property types listed
in Table 12–1. Data components are discussed in Using Data-Bound Table
Components. Here is part of the start tag of dataTable from that section:
<h:dataTable id="items"
...
value="#{cart.items}"
...
var="item">
Developing with JavaServer Faces Technology 12-5
Writing Bean Properties
The value expression points to the items property of a shopping cart bean named
cart. The cart bean maintains a map of ShoppingCartItem beans.
The getItems method from the cart bean populates a List with ShoppingCartItem
instances that are saved in the items map when the customer adds books to the cart, as
shown in the following code segment:
public synchronized List<ShoppingCartItem> getItems() {
List<ShoppingCartItem> results = new ArrayList<ShoppingCartItem>();
results.addAll(this.items.values());
return results;
}
All the components contained in the UIData component are bound to the properties of
the cart bean that is bound to the entire UIData component. For example, here is the
h:outputText tag that displays the book title in the table:
<h:commandLink action="#{showcart.details}">
<h:outputText value="#{item.item.title}"/>
</h:commandLink>
The title is actually a link to the bookdetails.xhtml page. The h:outputText tag uses
the value expression #{item.item.title} to bind its UIOutput component to the
title property of the Book entity. The first item in the expression is the
ShoppingCartItem instance that the h:dataTable tag is referencing while rendering
the current row. The second item in expression refers to the item property of
ShoppingCartItem, which returns an Object (in this case, a Book). The title part of
the expression refers to the title property of Book. The value of the UIOutput
component corresponding to this tag is bound to the title property of the Book entity:
private String title;
...
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
12.2.1.3 UISelectBoolean Properties
The UISelectBoolean component class is represented by the component tag
h:selectBooleanCheckbox.
Managed bean properties that hold a UISelectBoolean component's data must be of
boolean or Boolean type. The example selectBooleanCheckbox tag from the section
Displaying Components for Selecting One Value binds a component to a property. The
following example shows a tag that binds a component value to a boolean property:
<h:selectBooleanCheckbox title="#{bundle.receiveEmails}"
value="#{custFormBean.receiveEmails}">
</h:selectBooleanCheckbox>
<h:outputText value="#{bundle.receiveEmails}">
Here is an example property that can be bound to the component represented by the
example tag:
private boolean receiveEmails = false;
...
public void setReceiveEmails(boolean receiveEmails) {
12-6 The Java EE 7 Tutorial
Writing Bean Properties
this.receiveEmails = receiveEmails;
}
public boolean getReceiveEmails() {
return receiveEmails;
}
12.2.1.4 UISelectMany Properties
The UISelectMany component class is represented by the component tags that begin
with h:selectMany (for example, h:selectManyCheckbox and h:selectManyListbox).
Because a UISelectMany component allows a user to select one or more items from a
list of items, this component must map to a bean property of type List or array. This
bean property represents the set of currently selected items from the list of available
items.
The following example of the selectManyCheckbox tag comes from Displaying
Components for Selecting Multiple Values:
<h:selectManyCheckbox id="newslettercheckbox"
layout="pageDirection"
value="#{cashierBean.newsletters}">
<f:selectItems value="#{cashierBean.newsletterItems}"/>
</h:selectManyCheckbox>
Here is the bean property that maps to the value of the selectManyCheckbox tag from
the preceding example:
private String[] newsletters;
public void setNewsletters(String[] newsletters) {
this.newsletters = newsletters;
}
public String[] getNewsletters() {
return this.newsletters;
}
The UISelectItem and UISelectItems components are used to represent all the values
in a UISelectMany component. See UISelectItem Properties and UISelectItems
Properties for information on writing the bean properties for the UISelectItem and
UISelectItems components.
12.2.1.5 UISelectOne Properties
The UISelectOne component class is represented by the component tags that begin
with h:selectOne (for example, h:selectOneRadio and h:selectOneListbox).
UISelectOne properties accept the same types as UIInput and UIOutput properties,
because a UISelectOne component represents the single selected item from a set of
items. This item can be any of the primitive types and anything else for which you can
apply a converter.
Here is an example of the h:selectOneMenu tag from Displaying a Menu Using the
h:selectOneMenu Tag:
<h:selectOneMenu id="shippingOption"
required="true"
value="#{cashierBean.shippingOption}">
<f:selectItem itemValue="2"
itemLabel="#{bundle.QuickShip}"/>
<f:selectItem itemValue="5"
itemLabel="#{bundle.NormalShip}"/>
Developing with JavaServer Faces Technology 12-7
Writing Bean Properties
<f:selectItem itemValue="7"
itemLabel="#{bundle.SaverShip}"/>
</h:selectOneMenu>
Here is the bean property corresponding to this tag:
private String shippingOption = "2";
public void setShippingOption(String shippingOption) {
this.shippingOption = shippingOption;
}
public String getShippingOption() {
return this.shippingOption;
}
Note that shippingOption represents the currently selected item from the list of items
in the UISelectOne component.
The UISelectItem and UISelectItems components are used to represent all the values
in a UISelectOne component. This is explained in Displaying a Menu Using the
h:selectOneMenu Tag.
For information on how to write the managed bean properties for the UISelectItem
and UISelectItems components, see UISelectItem Properties and UISelectItems
Properties.
12.2.1.6 UISelectItem Properties
A UISelectItem component represents a single value in a set of values in a
UISelectMany or a UISelectOne component. A UISelectItem component must be
bound to a managed bean property of type javax.faces.model.SelectItem. A
SelectItem object is composed of an Object representing the value along with two
Strings representing the label and the description of the UISelectItem object.
The example selectOneMenu tag from UISelectOne Properties contains selectItem
tags that set the values of the list of items in the page. Here is an example of a bean
property that can set the values for this list in the bean:
SelectItem itemOne = null;
SelectItem getItemOne(){
return itemOne;
}
void setItemOne(SelectItem item) {
itemOne = item;
}
12.2.1.7 UISelectItems Properties
UISelectItems components are children of UISelectMany and UISelectOne
components. Each UISelectItems component is composed of a set of either
UISelectItem instances or any collection of objects, such as an array, a list, or even
POJOs.
The following code snippet from CashierBean shows how to write the properties for
selectItems tags containing SelectItem instances.
private
private
new
new
new
String[] newsletters;
static final SelectItem[] newsletterItems = {
SelectItem("Duke's Quarterly"),
SelectItem("Innovator's Almanac"),
SelectItem("Duke's Diet and Exercise Journal"),
12-8 The Java EE 7 Tutorial
Writing Bean Properties
new SelectItem("Random Ramblings")
};
...
public void setNewsletters(String[] newsletters) {
this.newsletters = newsletters;
}
public String[] getNewsletters() {
return this.newsletters;
}
public SelectItem[] getNewsletterItems() {
return newsletterItems;
}
Here, the newsletters property represents the SelectItems object, whereas the
newsletterItems property represents a static array of SelectItem objects. The
SelectItem class has several constructors; in this example, the first argument is an
Object representing the value of the item, whereas the second argument is a String
representing the label that appears in the UISelectMany component on the page.
12.2.2 Writing Properties Bound to Component Instances
A property bound to a component instance returns and accepts a component instance
rather than a component value. The following components bind a component instance
to a managed bean property:
<h:selectBooleanCheckbox id="fanClub"
rendered="false"
binding="#{cashierBean.specialOffer}" />
<h:outputLabel for="fanClub"
rendered="false"
binding="#{cashierBean.specialOfferText}"
value="#{bundle.DukeFanClub}" />
</h:outputLabel>
The selectBooleanCheckbox tag renders a check box and binds the fanClub
UISelectBoolean component to the specialOffer property of CashierBean. The
outputLabel tag binds the value of the value attribute, which represents the check
box's label, to the specialOfferText property of CashierBean. If the user orders more
than $100 worth of books and clicks the Submit button, the submit method of
CashierBean sets both components' rendered properties to true, causing the check
box and label to display when the page is re-rendered.
Because the components corresponding to the example tags are bound to the managed
bean properties, these properties must match the components' types. This means that
the specialOfferText property must be of type UIOutput, and the specialOffer
property must be of type UISelectBoolean:
UIOutput specialOfferText = null;
UISelectBoolean specialOffer = null;
public UIOutput getSpecialOfferText() {
return this.specialOfferText;
}
public void setSpecialOfferText(UIOutput specialOfferText) {
this.specialOfferText = specialOfferText;
}
public UISelectBoolean getSpecialOffer() {
Developing with JavaServer Faces Technology 12-9
Writing Managed Bean Methods
return this.specialOffer;
}
public void setSpecialOffer(UISelectBoolean specialOffer) {
this.specialOffer = specialOffer;
}
For more general information on component binding, see Managed Beans in
JavaServer Faces Technology.
For information on how to reference a managed bean method that performs
navigation when a button is clicked, see Referencing a Method That Performs
Navigation.
For more information on writing managed bean methods that handle navigation, see
Writing a Method to Handle Navigation.
12.2.3 Writing Properties Bound to Converters, Listeners, or Validators
All the standard converter, listener, and validator tags included with JavaServer Faces
technology support binding attributes that allow you to bind converter, listener, or
validator implementations to managed bean properties.
The following example shows a standard convertDateTime tag using a value
expression with its binding attribute to bind the
javax.faces.convert.DateTimeConverter instance to the convertDate property of
LoginBean:
<h:inputText value="#{loginBean.birthDate}">
<f:convertDateTime binding="#{loginBean.convertDate}" />
</h:inputText>
The convertDate property must therefore accept and return a DateTimeConverter
object, as shown here:
private DateTimeConverter convertDate;
public DateTimeConverter getConvertDate() {
...
return convertDate;
}
public void setConvertDate(DateTimeConverter convertDate) {
convertDate.setPattern("EEEEEEEE, MMM dd, yyyy");
this.convertDate = convertDate;
}
Because the converter is bound to a managed bean property, the managed bean
property can modify the attributes of the converter or add new functionality to it. In
the case of the preceding example, the property sets the date pattern that the converter
uses to parse the user's input into a Date object.
The managed bean properties that are bound to validator or listener implementations
are written in the same way and have the same general purpose.
12.3 Writing Managed Bean Methods
Methods of a managed bean can perform several application-specific functions for
components on the page. These functions include
■
Performing processing associated with navigation
■
Handling action events
12-10 The Java EE 7 Tutorial
Writing Managed Bean Methods
■
Performing validation on the component's value
■
Handling value-change events
By using a managed bean to perform these functions, you eliminate the need to
implement the javax.faces.validator.Validator interface to handle the validation
or one of the listener interfaces to handle events. Also, by using a managed bean
instead of a Validator implementation to perform validation, you eliminate the need
to create a custom tag for the Validator implementation.
In general, it is good practice to include these methods in the same managed bean that
defines the properties for the components referencing these methods. The reason for
doing so is that the methods might need to access the component's data to determine
how to handle the event or to perform the validation associated with the component.
The following sections explain how to write various types of managed bean methods.
12.3.1 Writing a Method to Handle Navigation
An action method, a managed bean method that handles navigation processing, must
be a public method that takes no parameters and returns an Object, which is the
logical outcome that the navigation system uses to determine the page to display next.
This method is referenced using the component tag's action attribute.
The following action method is from the managed bean CashierBean, which is
invoked when a user clicks the Submit button on the page. If the user has ordered
more than $100 worth of books, this method sets the rendered properties of the
fanClub and specialOffer components to true, causing them to be displayed on the
page the next time that page is rendered.
After setting the components' rendered properties to true, this method returns the
logical outcome null. This causes the JavaServer Faces implementation to re-render
the page without creating a new view of the page, retaining the customer's input. If
this method were to return purchase, which is the logical outcome to use to advance to
a payment page, the page would re-render without retaining the customer's input. In
this case, you want to re-render the page without clearing the data.
If the user does not purchase more than $100 worth of books or if the thankYou
component has already been rendered, the method returns bookreceipt. The
JavaServer Faces implementation loads the bookreceipt.xhtml page after this method
returns:
public String submit() {
...
if ((cart().getTotal()> 100.00) && !specialOffer.isRendered()) {
specialOfferText.setRendered(true);
specialOffer.setRendered(true);
return null;
} else if (specialOffer.isRendered() && !thankYou.isRendered()) {
thankYou.setRendered(true);
return null;
} else {
...
cart.clear();
return ("bookreceipt");
}
}
Typically, an action method will return a String outcome, as shown in the preceding
example. Alternatively, you can define an Enum class that encapsulates all possible
Developing with JavaServer Faces Technology
12-11
Writing Managed Bean Methods
outcome strings and then make an action method return an enum constant, which
represents a particular String outcome defined by the Enum class.
The following example uses an Enum class to encapsulate all logical outcomes:
public enum Navigation {
main, accountHist, accountList, atm, atmAck, transferFunds,
transferAck, error
}
When it returns an outcome, an action method uses the dot notation to reference the
outcome from the Enum class:
public Object submit(){
...
return Navigation.accountHist;
}
The section Referencing a Method That Performs Navigation explains how a
component tag references this method. The section Writing Properties Bound to
Component Instances explains how to write the bean properties to which the
components are bound.
12.3.2 Writing a Method to Handle an Action Event
A managed bean method that handles an action event must be a public method that
accepts an action event and returns void. This method is referenced using the
component tag's actionListener attribute. Only components that implement
javax.faces.component.ActionSource can refer to this method.
In the following example, a method from a managed bean named ActionBean
processes the event of a user clicking one of the links on the page:
public void chooseBookFromLink(ActionEvent event) {
String current = event.getComponent().getId();
FacesContext context = FacesContext.getCurrentInstance();
String bookId = books.get(current);
context.getExternalContext().getSessionMap().put("bookId", bookId);
}
This method gets the component that generated the event from the event object; then it
gets the component's ID, which is a code for the book. The method matches the code
against a HashMap object that contains the book codes and corresponding book ID
values. Finally, the method sets the book ID by using the selected value from the
HashMap object.
Referencing a Method That Handles an Action Event explains how a component tag
references this method.
12.3.3 Writing a Method to Perform Validation
Instead of implementing the javax.faces.validator.Validator interface to perform
validation for a component, you can include a method in a managed bean to take care
of validating input for the component. A managed bean method that performs
validation must accept a javax.faces.context.FacesContext, the component whose
data must be validated, and the data to be validated, just as the validate method of
the Validator interface does. A component refers to the managed bean method by
using its validator attribute. Only values of UIInput components or values of
components that extend UIInput can be validated.
12-12 The Java EE 7 Tutorial
Writing Managed Bean Methods
Here is an example of a managed bean method that validates user input, from The
guessnumber-cdi CDI Example:
public void validateNumberRange(FacesContext context,
UIComponent toValidate,
Object value) {
if (remainingGuesses <= 0) {
((UIInput) toValidate).setValid(false);
FacesMessage message = new FacesMessage("No guesses left!");
context.addMessage(toValidate.getClientId(context), message);
return;
}
int input = (Integer) value;
if (input < minimum || input> maximum) {
((UIInput) toValidate).setValid(false);
FacesMessage message = new FacesMessage("Invalid guess");
context.addMessage(toValidate.getClientId(context), message);
}
}
The validateNumberRange method performs two different validations.
■
■
If the user has run out of guesses, the method sets the valid property of the
UIInput component to false. Then it queues a message onto the FacesContext
instance, associating the message with the component ID, and returns.
If the user has some remaining guesses, the method then retrieves the local value
of the component. If the input value is outside the allowable range, the method
again sets the valid property of the UIInput component to false, queues a
different message on the FacesContext instance, and returns.
See Referencing a Method That Performs Validation for information on how a
component tag references this method.
12.3.4 Writing a Method to Handle a Value-Change Event
A managed bean that handles a value-change event must use a public method that
accepts a value-change event and returns void. This method is referenced using the
component's valueChangeListener attribute. This section explains how to write a
managed bean method to replace the javax.faces.event.ValueChangeListener
implementation.
The following example tag comes from Registering a Value-Change Listener on a
Component, where the h:inputText tag with the id of name has a
ValueChangeListener instance registered on it. This ValueChangeListener instance
handles the event of entering a value in the field corresponding to the component.
When the user enters a value, a value-change event is generated, and the
processValueChange(ValueChangeEvent) method of the ValueChangeListener class is
invoked:
<h:inputText id="name"
size="30"
value="#{cashierBean.name}"
required="true"
requiredMessage="#{bundle.ReqCustomerName}">
<f:valueChangeListener
type="javaeetutorial.dukesbookstore.listeners.NameChanged" />
</h:inputText>
Developing with JavaServer Faces Technology
12-13
Writing Managed Bean Methods
Instead of implementing ValueChangeListener, you can write a managed bean
method to handle this event. To do this, you move the
processValueChange(ValueChangeEvent) method from the ValueChangeListener
class, called NameChanged, to your managed bean.
Here is the managed bean method that processes the event of entering a value in the
name field on the page:
public void processValueChange(ValueChangeEvent event)
throws AbortProcessingException {
if (null != event.getNewValue()) {
FacesContext.getCurrentInstance().getExternalContext().
getSessionMap().put("name", event.getNewValue());
}
}
To make this method handle the ValueChangeEvent generated by an input component,
reference this method from the component tag's valueChangeListener attribute. See
Referencing a Method That Handles a Value-Change Event for more information.
12-14 The Java EE 7 Tutorial
13
Using Ajax with JavaServer Faces
Technology
13
Ajax is an acronym for Asynchronous JavaScript and XML, a group of web
technologies that enable creation of dynamic and highly responsive web applications.
Using Ajax, web applications can retrieve content from the server without interfering
with the display on the client. In the Java EE 7 platform, JavaServer Faces technology
provides built-in support for Ajax.
Early web applications were created mostly as static web pages. When a static web
page is updated by a client, the entire page has to reload to reflect the update. In effect,
every update needs a page reload to reflect the change. Repetitive page reloads can
result in excessive network access and can impact application performance.
Technologies such as Ajax were created to overcome these deficiencies.
This chapter describes using Ajax functionality in JavaServer Faces web applications.
The following topics are addressed here:
■
Overview of Ajax
■
Using Ajax Functionality with JavaServer Faces Technology
■
Using Ajax with Facelets
■
Sending an Ajax Request
■
Monitoring Events on the Client
■
Handling Errors
■
Receiving an Ajax Response
■
Ajax Request Lifecycle
■
Grouping of Components
■
Loading JavaScript as a Resource
■
The ajaxguessnumber Example Application
■
Further Information about Ajax in JavaServer Faces Technology
13.1 Overview of Ajax
Ajax refers to JavaScript and XML, technologies that are widely used for creating
dynamic and asynchronous web content. While Ajax is not limited to JavaScript and
XML technologies, more often than not they are used together by web applications.
The focus of this tutorial is on using JavaScript based Ajax functionality in JavaServer
Faces web applications.
Using Ajax with JavaServer Faces Technology 13-1
Using Ajax Functionality with JavaServer Faces Technology
JavaScript is a dynamic scripting language for web applications. It allows users to add
enhanced functionality to user interfaces and allows web pages to interact with clients
asynchronously. JavaScript runs mainly on the client side (as in a browser) and thereby
reduces server access by clients.
When a JavaScript function sends an asynchronous request from the client to the
server, the server sends back a response that is used to update the page's Document
Object Model (DOM). This response is often in the format of an XML document. The
term Ajax refers to this interaction between the client and server.
The server response need not be in XML only; it can also be in other formats, such as
JSON (see Introduction to JSON and http://www.json.org/). This tutorial does
not focus on the response formats.
Ajax enables asynchronous and partial updating of web applications. Such
functionality allows for highly responsive web pages that are rendered in near real
time. Ajax-based web applications can access server and process information and can
also retrieve data without interfering with the display and rendering of the current
web page on a client (such as a browser).
Some of the advantages of using Ajax are as follows:
■
Form data validation in real time, eliminating the need to submit the form for
verification
■
Enhanced functionality for web pages, such as user name and password prompts
■
Partial update of the web content, avoiding complete page reloads
13.2 Using Ajax Functionality with JavaServer Faces Technology
Ajax functionality can be added to a JavaServer Faces application in one of the
following ways:
■
Adding the required JavaScript code to an application
■
Using the built-in Ajax resource library
In earlier releases of the Java EE platform, JavaServer Faces applications provided Ajax
functionality by adding the necessary JavaScript to the web page. In the Java EE 7
platform, standard Ajax support is provided by a built-in JavaScript resource library.
With the support of this JavaScript resource library, JavaServer Faces standard UI
components, such as buttons, labels, or text fields, can be enabled for Ajax
functionality. You can also load this resource library and use its methods directly from
within the managed bean code. The next sections of the tutorial describe the use of the
built-in Ajax resource library.
In addition, because the JavaServer Faces technology component model can be
extended, custom components can be created with Ajax functionality.
The tutorial examples include an Ajax version of the guessnumber application,
ajaxguessnumber. See The ajaxguessnumber Example Application for more
information.
The Ajax specific f:ajax tag and its attributes are explained in the next sections.
13.3 Using Ajax with Facelets
As mentioned in the previous section, JavaServer Faces technology supports Ajax by
using a built-in JavaScript resource library that is provided as part of the JavaServer
13-2 The Java EE 7 Tutorial
Using Ajax with Facelets
Faces core libraries. This built-in Ajax resource can be used in JavaServer Faces web
applications in one of the following ways.
■
■
By using the f:ajax tag along with another standard component in a Facelets
application. This method adds Ajax functionality to any UI component without
additional coding and configuration.
By using the JavaScript API method jsf.ajax.request() directly within the
Facelets application. This method provides direct access to Ajax methods and
allows customized control of component behavior.
13.3.1 Using the f:ajax Tag
The f:ajax tag is a JavaServer Faces core tag that provides Ajax functionality to any
regular UI component when used in conjunction with that component. In the
following example, Ajax behavior is added to an input component by including the
f:ajax core tag:
<h:inputText value="#{bean.message}">
<f:ajax />
</h:inputText>
In this example, although Ajax is enabled, the other attributes of the f:ajax tag are not
defined. If an event is not defined, the default action for the component is performed.
For the inputText component, when no event attribute is specified, the default event
is valueChange. Table 13–1 lists the attributes of the f:ajax tag and their default
actions.
Table 13–1
Attributes of the f:ajax Tag
Name
Type
Description
disabled
javax.el.ValueExpression
that evaluates to a Boolean
A Boolean value that identifies the tag status. A
value of true indicates that the Ajax behavior
should not be rendered. A value of false
indicates that the Ajax behavior should be
rendered. The default value is false.
event
javax.el.ValueExpression
that evaluates to a String
A String that identifies the type of event to
which the Ajax action will apply. If specified, it
must be one of the events supported by the
component. If not specified, the default event
(the event that triggers the Ajax request) is
determined for the component. The default
event is action for
javax.faces.component.ActionSource
components and valueChange for
javax.faces.component.EditableValueHolder
components.
execute
javax.el.ValueExpression
that evaluates to an Object
A Collection that identifies a list of
components to be executed on the server. If a
literal is specified, it must be a space-delimited
String of component identifiers and/or one of
the keywords. If a ValueExpression is specified,
it must refer to a property that returns a
Collection of String objects. If not specified,
the default value is @this.
Using Ajax with JavaServer Faces Technology 13-3
Sending an Ajax Request
Table 13–1 (Cont.) Attributes of the f:ajax Tag
Name
Type
Description
immediate
javax.el.ValueExpression
that evaluates to a Boolean
A Boolean value that indicates whether inputs
are to be processed early in the lifecycle. If true,
behavior events generated from this behavior
are broadcast during the Apply Request Values
phase. Otherwise, the events will be broadcast
during the Invoke Application phase.
listener
javax.el.MethodExpression
The name of the listener method that is called
when a
javax.faces.event.AjaxBehaviorEvent has
been broadcast for the listener.
onevent
javax.el.ValueExpression
that evaluates to a String
The name of the JavaScript function that
handles UI events.
onerror
javax.el.ValueExpression
that evaluates to a String
The name of the JavaScript function that
handles errors.
render
javax.el.ValueExpression
that evaluates to an Object
A Collection that identifies a list of
components to be rendered on the client. If a
literal is specified, it must be a space-delimited
String of component identifiers and/or one of
the keywords. If a ValueExpression is specified,
it must refer to a property that returns a
Collection of String objects. If not specified,
the default value is @none.
The keywords listed in Table 13–2 can be used with the execute and render attributes
of the f:ajax tag.
Table 13–2
Execute and Render Keywords
Keyword
Description
@all
All component identifiers
@form
The form that encloses the component
@none
No component identifiers
@this
The element that triggered the request
Note that when you use the f:ajax tag in a Facelets page, the JavaScript resource
library is loaded implicitly. This resource library can also be loaded explicitly as
described in Loading JavaScript as a Resource.
13.4 Sending an Ajax Request
To activate Ajax functionality, the web application must create an Ajax request and
send it to the server. The server then processes the request.
The application uses the attributes of the f:ajax tag listed in Table 13–1 to create the
Ajax request. The following sections explain the process of creating and sending an
Ajax request using some of these attributes.
Note: Behind the scenes, the jsf.ajax.request() method of the
JavaScript resource library collects the data provided by the f:ajax
tag and posts the request to the JavaServer Faces lifecycle.
13-4 The Java EE 7 Tutorial
Sending an Ajax Request
13.4.1 Using the event Attribute
The event attribute defines the event that triggers the Ajax action. Some of the possible
values for this attribute are click, keyup, mouseover, focus, and blur.
If not specified, a default event based on the parent component will be applied. The
default event is action for javax.faces.component.ActionSource components, such
as a commandButton, and valueChange for
javax.faces.component.EditableValueHolder components, such as inputText. In
the following example, an Ajax tag is associated with the button component, and the
event that triggers the Ajax action is a mouse click:
<h:commandButton id="submit" value="Submit">
<f:ajax event="click" />
</h:commandButton>
<h:outputText id="result" value="#{userNumberBean.response}" />
You may have noticed that the listed events are very similar
to JavaScript events. In fact, they are based on JavaScript events,
but do not have the on prefix.
Note:
For a command button, the default event is click, so you do not actually need to
specify event="click" to obtain the desired behavior.
13.4.2 Using the execute Attribute
The execute attribute defines the component or components to be executed on the
server. The component is identified by its id attribute. You can specify more than one
executable component. If more than one component is to be executed, specify a
space-delimited list of components.
When a component is executed, it participates in all phases of the request-processing
lifecycle except the Render Response phase.
The execute attribute value can also be a keyword, such as @all, @none, @this, or
@form. The default value is @this, which refers to the component within which the
f:ajax tag is nested.
The following code specifies that the h:inputText component with the id value of
userNo should be executed when the button is clicked:
<h:inputText id="userNo"
title="Type a number from 0 to 10:"
value="#{userNumberBean.userNumber}">
...
</h:inputText>
<h:commandButton id="submit" value="Submit">
<f:ajax event="click" execute="userNo" />
</h:commandButton>
13.4.3 Using the immediate Attribute
The immediate attribute indicates whether user inputs are to be processed early in the
application lifecycle or later. If the attribute is set to true, events generated from this
component are broadcast during the Apply Request Values phase. Otherwise, the
events will be broadcast during the Invoke Application phase.
If not defined, the default value of this attribute is false.
Using Ajax with JavaServer Faces Technology 13-5
Monitoring Events on the Client
13.4.4 Using the listener Attribute
The listener attribute refers to a method expression that is executed on the server
side in response to an Ajax action on the client. The listener's
javax.faces.event.AjaxBehaviorListener.processAjaxBehavior method is called
once during the Invoke Application phase of the lifecycle. In the following code from
the reservation example application (see The reservation Example Application), a
listener attribute is defined by an f:ajax tag, which refers to a method from the
bean:
<f:ajax event="change" render="total"
listener="#{reservationBean.calculateTotal}"/>
Whenever either the price or the number of tickets ordered changes, the
calculateTotal method of ReservationBean recalculates the total cost of the tickets
and displays it in the output component named total.
13.5 Monitoring Events on the Client
To monitor ongoing Ajax requests, use the onevent attribute of the f:ajax tag. The
value of this attribute is the name of a JavaScript function. JavaServer Faces calls the
onevent function at each stage of the processing of an Ajax request: begin, complete,
and success.
When calling the JavaScript function assigned to the onevent property, JavaServer
Faces passes a data object to it. The data object contains the properties listed in
Table 13–3.
Table 13–3
Properties of the onevent Data Object
Property
Description
responseXML
The response to the Ajax call in XML format
responseText
The response to the Ajax call in text format
responseCode
The response to the Ajax call in numeric code
source
The source of the current Ajax event: the DOM element
status
The status of the current Ajax call: begin, complete, or success
type
The type of the Ajax call: event
By using the status property of the data object, you can identify the current status of
the Ajax request and monitor its progress. In the following example,
monitormyajaxevent is a JavaScript function that monitors the Ajax request sent by the
event:
<f:ajax event="click" render="statusmessage" onevent="monitormyajaxevent"/>
13.6 Handling Errors
JavaServer Faces handles Ajax errors through use of the onerror attribute of the
f:ajax tag. The value of this attribute is the name of a JavaScript function.
When there is an error in processing a Ajax request, JavaServer Faces calls the defined
onerror JavaScript function and passes a data object to it. The data object contains all
the properties available for the onevent attribute and, in addition, the following
properties:
■
description
13-6 The Java EE 7 Tutorial
Ajax Request Lifecycle
■
errorName
■
errorMessage
The type is error. The status property of the data object contains one of the valid
error values listed in Table 13–4.
Table 13–4
Valid Error Values for the Data Object status Property
Values
Description
emptyResponse
No Ajax response from server.
httpError
One of the valid HTTP errors: request.status==null or
request.status==undefined or request.status<200 or
request.status>=300.
malformedXML
The Ajax response is not well formed.
serverError
The Ajax response contains an error element.
In the following example, any errors that occurred in processing the Ajax request are
handled by the handlemyajaxerror JavaScript function:
<f:ajax event="click" render="errormessage" onerror="handlemyajaxerror"/>
13.7 Receiving an Ajax Response
After the application sends an Ajax request, it is processed on the server side, and a
response is sent back to the client. As described earlier, Ajax allows for partial
updating of web pages. To enable such partial updating, JavaServer Faces technology
allows for partial processing of the view. The handling of the response is defined by
the render attribute of the f:ajax tag.
Similar to the execute attribute, the render attribute defines which sections of the
page will be updated. The value of a render attribute can be one or more component
id values, one of the keywords @this, @all, @none, or @form, or an EL expression. In
the following example, the render attribute identifies an output component to be
displayed when the button component is clicked (the default event for a command
button):
<h:commandButton id="submit" value="Submit">
<f:ajax execute="userNo" render="result" />
</h:commandButton>
<h:outputText id="result" value="#{userNumberBean.response}" />
Note: Behind the scenes, once again the jsf.ajax.request()
method handles the response. It registers a response-handling
callback when the original request is created. When the response is
sent back to the client, the callback is invoked. This callback
automatically updates the client-side DOM to reflect the rendered
response.
13.8 Ajax Request Lifecycle
An Ajax request varies from other typical JavaServer Faces requests, and its processing
is also handled differently by the JavaServer Faces lifecycle.
As described in Partial Processing and Partial Rendering, when an Ajax request is
received, the state associated with that request is captured by the
Using Ajax with JavaServer Faces Technology 13-7
Grouping of Components
javax.faces.context.PartialViewContext. This object provides access to
information such as which components are targeted for processing/rendering. The
processPartial method of PartialViewContext uses this information to perform
partial component tree processing and rendering.
The execute attribute of the f:ajax tag identifies which segments of the server-side
component tree should be processed. Because components can be uniquely identified
in the JavaServer Faces component tree, it is easy to identify and process a single
component, a few components, or a whole tree. This is made possible by the
visitTree method of the UIComponent class. The identified components then run
through the JavaServer Faces request lifecycle phases.
Similar to the execute attribute, the render attribute identifies which segments of the
JavaServer Faces component tree need to be rendered during the render response
phase.
During the render response phase, the render attribute is examined. The identified
components are found and asked to render themselves and their children. The
components are then packaged up and sent back to the client as a response.
13.9 Grouping of Components
The previous sections describe how to associate a single UI component with Ajax
functionality. You can also associate Ajax with more than one component at a time by
grouping them together on a page. The following example shows how a number of
components can be grouped by using the f:ajax tag:
<f:ajax>
<h:form>
<h:inputText id="input1" value="#{user.name}"/>
<h:commandButton id="Submit"/>
</h:form>
</f:ajax>
In the example, neither component is associated with any Ajax event or render
attributes yet. Therefore, no action will take place in case of user input. You can
associate the above components with an event and a render attribute as follows:
<f:ajax event="click" render="@all">
<h:form>
<h:inputText id="input1" value="#{user.name}"/>
<h:commandButton id="Submit"/>
</h:form>
</f:ajax>
In the updated example, when the user clicks either component, the updated results
will be displayed for all components. You can further fine-tune the Ajax action by
adding specific events to each of the components, in which case Ajax functionality
becomes cumulative. Consider the following example:
<f:ajax event="click" render="@all">
...
<h:commandButton id="Submit">
<f:ajax event="mouseover"/>
</h:commandButton>
...
</f:ajax>
Now the button component will fire an Ajax action in case of a mouseover event as
well as a mouse-click event.
13-8 The Java EE 7 Tutorial
Loading JavaScript as a Resource
13.10 Loading JavaScript as a Resource
The JavaScript resource file bundled with JavaServer Faces technology is named
jsf.js and is available in the javax.faces library. This resource library supports Ajax
functionality in JavaServer Faces applications.
If you use the f:ajax tag on a page, the jsf.js resource is automatically delivered to
the client. It is not necessary to use the h:outputScript tag to specify this resource.
You may want to use the h:outputScript tag to specify other JavaScript libraries.
In order to use a JavaScript resource directly with a UIComponent, you must explicitly
load the resource in either of the following ways:
■
■
By using the h:outputScript tag directly in a Facelets page
By using the javax.faces.application.ResourceDependency annotation on a
UIComponent Java class
13.10.1 Using JavaScript API in a Facelets Application
To use the bundled JavaScript resource API directly in a web application, such as a
Facelets page, you need to first identify the default JavaScript resource for the page
with the help of the h:outputScript tag. For example, consider the following section
of a Facelets page:
<h:form>
<h:outputScript name="jsf.js" library="javax.faces" target="head"/>
</h:form>
Specifying the target as head causes the script resource to be rendered within the head
element on the HTML page.
In the next step, identify the component to which you would like to attach the Ajax
functionality. Add the Ajax functionality to the component by using the JavaScript
API. For example, consider the following:
<h:form>
<h:outputScript name="jsf.js" library="javax.faces" target="head">
<h:inputText id="inputname" value="#{userBean.name}"/>
<h:outputText id="outputname" value="#{userBean.name}"/>
<h:commandButton id="submit" value="Submit"
onclick="jsf.ajax.request(this, event,
{execute:'inputname',render:'outputname'});
return false;" />
</h:form>
The jsf.ajax.request method takes up to three parameters that specify source, event,
and options. The source parameter identifies the DOM element that triggered the Ajax
request, typically this. The optional event parameter identifies the DOM event that
triggered this request. The optional options parameter contains a set of name/value
pairs from Table 13–5.
Table 13–5
Possible Values for the Options Parameter
Name
Value
execute
A space-delimited list of client identifiers or one of the keywords listed in
Table 13–2. The identifiers reference the components that will be processed during
the Execute phase of the lifecycle.
Using Ajax with JavaServer Faces Technology 13-9
The ajaxguessnumber Example Application
Table 13–5 (Cont.) Possible Values for the Options Parameter
Name
Value
render
A space-delimited list of client identifiers or one of the keywords listed in
Table 13–2. The identifiers reference the components that will be processed during
the render phase of the lifecycle.
onevent
A String that is the name of the JavaScript function to call when an event occurs.
onerror
A String that is the name of the JavaScript function to call when an error occurs.
params
An object that may include additional parameters to include in the request.
If no identifier is specified, the default assumed keyword for the execute attribute is
@this, and for the render attribute it is @none.
You can also place the JavaScript method in a file and include it as a resource.
13.10.2 Using the @ResourceDependency Annotation in a Bean Class
Use the javax.faces.application.ResourceDependency annotation to cause the bean
class to load the default jsf.js library.
To load the Ajax resource from the server side, use the jsf.ajax.request method
within the bean class. This method is usually used when creating a custom component
or a custom renderer for a component.
The following example shows how the resource is loaded in a bean class:
@ResourceDependency(name="jsf.js" library="javax.faces" target="head")
13.11 The ajaxguessnumber Example Application
To demonstrate the advantages of using Ajax, revisit the guessnumber example from
Chapter 8, "Introduction to Facelets". If you modify this example to use Ajax, the
response need not be displayed on the response.xhtml page. Instead, an
asynchronous call is made to the bean on the server side, and the response is displayed
on the originating page by executing just the input component rather than by form
submission.
The source code for this application is in the
tut-install/examples/web/jsf/ajaxguessnumber/ directory.
13.11.1 The ajaxguessnumber Source Files
The changes to the guessnumber application occur in two source files.
13.11.1.1 The ajaxgreeting.xhtml Facelets Page
The Facelets page for ajaxguessnumber, ajaxgreeting.xhtml, is almost the same as
the greeting.xhtml page for the guessnumber application:
<h:head>
<h:outputStylesheet library="css" name="default.css"/>
<title>Ajax Guess Number Facelets Application</title>
</h:head>
<h:body>
<h:form id="AjaxGuess">
<h:graphicImage value="#{resource['images:wave.med.gif']}"
alt="Duke waving his hand"/>
<h2>
13-10 The Java EE 7 Tutorial
The ajaxguessnumber Example Application
Hi, my name is Duke. I am thinking of a number from
#{dukesNumberBean.minimum} to #{dukesNumberBean.maximum}.
Can you guess it?
</h2>
<p>
<h:inputText id="userNo"
title="Enter a number from 0 to 10:"
value="#{userNumberBean.userNumber}">
<f:validateLongRange minimum="#{dukesNumberBean.minimum}"
maximum="#{dukesNumberBean.maximum}"/>
</h:inputText>
<h:commandButton id="submit" value="Submit">
<f:ajax execute="userNo" render="outputGroup" />
</h:commandButton>
</p>
<p>
<h:panelGroup layout="block" id="outputGroup">
<h:outputText id="result" style="color:blue"
value="#{userNumberBean.response}"
rendered="#{!facesContext.validationFailed}"/>
<h:message id="errors1"
showSummary="true"
showDetail="false"
style="color: #d20005;
font-family: 'New Century Schoolbook', serif;
font-style: oblique;
text-decoration: overline"
for="userNo"/>
</h:panelGroup>
</p>
</h:form>
</h:body>
The most important change is in the h:commandButton tag. The action attribute is
removed from the tag, and an f:ajax tag is added.
The f:ajax tag specifies that when the button is clicked the h:inputText component
with the id value userNo is executed. The components within the outputGroup panel
group are then rendered. If a validation error occurs, the managed bean is not
executed, and the validation error message is displayed in the message pane.
Otherwise, the result of the guess is rendered in the result component.
13.11.1.2 The UserNumberBean Backing Bean
A small change is also made in the UserNumberBean code so that the output component
does not display any message for the default (null) value of the property response.
Here is the modified bean code:
public String getResponse() {
if ((userNumber != null)
&& (userNumber.compareTo(dukesNumberBean.getRandomInt()) == 0)) {
return "Yay! You got it!";
}
if (userNumber == null) {
return null;
} else {
return "Sorry, " + userNumber + " is incorrect.";
}
}
Using Ajax with JavaServer Faces Technology
13-11
The ajaxguessnumber Example Application
13.11.1.3 The DukesNumberBean CDI Managed Bean
The DukesNumberBean session-scoped CDI managed bean stores the range of guessable
numbers and the randomly chosen number from that range. It is injected into
UserNumberBean with the CDI @Inject annotation so that the value of the random
number can be compared to the number the user submitted:
@Inject
DukesNumberBean dukesNumberBean;
You will learn more about CDI in Chapter 23, "Introduction to Contexts and
Dependency Injection for Java EE".
13.11.2 Running the ajaxguessnumber Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
ajaxguessnumber application.
13.11.2.1 To Build, Package, and Deploy the ajaxguessnumber Example Using
NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsf
4.
Select the ajaxguessnumber folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the ajaxguessnumber project and select Build.
This command builds and deploys the project.
13.11.2.2 To Build, Package, and Deploy the ajaxguessnumber Example Using
Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/jsf/ajaxguessnumber/
3.
Enter the following command:
mvn install
This command builds and packages the application into a WAR file,
ajaxguessnumber.war, located in the target directory. It then deploys the
application.
13.11.2.3 To Run the ajaxguessnumber Example
1.
In a web browser, enter the following URL:
http://localhost:8080/ajaxguessnumber
2.
Enter a value in the field and click Submit.
13-12 The Java EE 7 Tutorial
Further Information about Ajax in JavaServer Faces Technology
If the value is in the range of 0 to 10, a message states whether the guess is correct
or incorrect. If the value is outside that range or if the value is not a number, an
error message appears in red.
13.12 Further Information about Ajax in JavaServer Faces Technology
For more information on Ajax in JavaServer Faces Technology, see
■
JavaServer Faces project website:
https://javaserverfaces.java.net/
■
JavaServer Faces JavaScript Library APIs:
http://docs.oracle.com/javaee/7/javaserverfaces/2.2/jsdocs/sy
mbols/jsf.ajax.html
Using Ajax with JavaServer Faces Technology
13-13
Further Information about Ajax in JavaServer Faces Technology
13-14 The Java EE 7 Tutorial
14
Composite Components: Advanced Topics
and an Example
14
This chapter describes the advanced features of composite components in JavaServer
Faces technology.
A composite component is a special type of JavaServer Faces template that acts as a
component. If you are new to composite components, see Composite Components
before you proceed with this chapter.
The following topics are addressed here:
■
Attributes of a Composite Component
■
Invoking a Managed Bean
■
Validating Composite Component Values
■
The compositecomponentexample Example Application
14.1 Attributes of a Composite Component
You define an attribute of a composite component by using the composite:attribute
tag. Table 14–1 lists the commonly used attributes of this tag.
Table 14–1
Commonly Used Attributes of the composite:attribute Tag
Attribute
Description
name
Specifies the name of the composite component attribute to be used in
the using page. Alternatively, the name attribute can specify standard
event handlers such as action, actionListener, and managed bean.
default
Specifies the default value of the composite component attribute.
required
Specifies whether it is mandatory to provide a value for the attribute.
method-signature
Specifies a subclass of java.lang.Object as the type of the composite
component's attribute. The method-signature element declares that
the composite component attribute is a method expression. The type
attribute and the method-signature attribute are mutually exclusive.
If you specify both, method-signature is ignored. The default type of
an attribute is java.lang.Object.
Note: Method expressions are similar to value expressions, but rather
than supporting the dynamic retrieval and setting of properties,
method expressions support the invocation of a method of an
arbitrary object, passing a specified set of parameters and returning
the result from the called method (if any).
Composite Components: Advanced Topics and an Example
14-1
Invoking a Managed Bean
Table 14–1 (Cont.) Commonly Used Attributes of the composite:attribute Tag
Attribute
Description
type
Specifies a fully qualified class name as the type of the attribute. The
type attribute and the method-signature attribute are mutually
exclusive. If you specify both, method-signature is ignored. The
default type of an attribute is java.lang.Object.
The following code snippet defines a composite component attribute and assigns it a
default value:
<composite:attribute name="username" default="admin"/>
The following code snippet uses the method-signature element:
<composite:attribute name="myaction"
method-signature="java.lang.String action()"/>
The following code snippet uses the type element:
<composite:attribute name="dateofjoining" type="java.util.Date"/>
14.2 Invoking a Managed Bean
To enable a composite component to handle server-side data, you can invoke a
managed bean in one of the following ways.
■
Pass the reference of the managed bean to the composite component.
■
Directly use the properties of the managed bean.
The example application described in The compositecomponentexample Example
Application shows how to use a managed bean with a composite component by
passing the reference of the managed bean to the component.
14.3 Validating Composite Component Values
JavaServer Faces provides the following tags for validating values of input
components. These tags can be used with the composite:valueHolder or the
composite:editableValueHolder tag.
Table 14–2 lists commonly used validator tags. See Using the Standard Validators for
details and a complete list.
Table 14–2
Validator Tags
Tag Name
Description
f:validateBean
Delegates the validation of the local value to the Bean Validation
API.
f:validateRegex
Uses the pattern attribute to validate the wrapping component. The
entire pattern is matched against the String value of the component.
If it matches, it is valid.
f:validateRequired
Enforces the presence of a value. Has the same effect as setting the
required element of a composite component's attribute to true.
14-2 The Java EE 7 Tutorial
The compositecomponentexample Example Application
14.4 The compositecomponentexample Example Application
The compositecomponentexample application creates a composite component that
accepts a name (or any other string). The component interacts with a managed bean
that calculates whether the letters in the name, if converted to numeric values, add up
to a prime number. The component displays the sum of the letter values and reports
whether it is or is not prime.
The compositecomponentexample application has a composite component file, a using
page, and a managed bean.
The source code for this application is in the
tut-install/examples/web/jsf/compositecomponentexample/ directory.
14.4.1 The Composite Component File
The composite component file is an XHTML file,
/web/resources/ezcomp/PrimePanel.xhtml. It has a composite:interface section
that declares the labels for the name and a command button. It also declares a
managed bean, which defines properties for the name.
<composite:interface>
<composite:attribute name="namePrompt"
default="Name, word, or phrase: "/>
<composite:attribute name="calcButtonText" default="Calculate"/>
<composite:attribute name="calcAction"
method-signature="java.lang.String action()"/>
<composite:attribute name="primeBean"/>
<composite:editableValueHolder name="nameVal" targets="form:name"/>
</composite:interface>
The composite component implementation accepts the input value for the name
property of the managed bean. The h:outputStylesheet tag specifies the stylesheet as
a relocatable resource. The implementation then specifies the format of the output,
using properties of the managed bean, as well as the format of error messages. The
sum value is rendered only after it has been calculated, and the report of whether the
sum is prime or not is rendered only if the input value is validated.
<composite:implementation>
<h:form id="form">
<h:outputStylesheet library="css" name="default.css"
target="head"/>
<h:panelGrid columns="2" role="presentation">
<h:outputLabel for="name"
value="#{cc.attrs.namePrompt}"/>
<h:inputText id="name"
size="45"
value="#{cc.attrs.primeBean.name}"
required="true"/>
</h:panelGrid>
<p>
<h:commandButton id="calcButton"
value="#{cc.attrs.calcButtonText}"
action="#{cc.attrs.calcAction}">
<f:ajax execute="name" render="outputGroup"/>
</h:commandButton>
</p>
<h:panelGroup id="outputGroup" layout="block">
<p>
Composite Components: Advanced Topics and an Example
14-3
The compositecomponentexample Example Application
<h:outputText id="result" style="color:blue"
rendered="#{cc.attrs.primeBean.totalSum gt 0}"
value="Sum is #{cc.attrs.primeBean.totalSum}" />
</p>
<p>
<h:outputText id="response" style="color:blue"
value="#{cc.attrs.primeBean.response}"
rendered="#{!facesContext.validationFailed}"/>
<h:message id="errors1"
showSummary="true"
showDetail="false"
style="color: #d20005;
font-family: 'New Century Schoolbook', serif;
font-style: oblique;
text-decoration: overline"
for="name"/>
</p>
</h:panelGroup>
</h:form>
</composite:implementation>
14.4.2 The Using Page
The using page in this example application, web/index.xhtml, is an XHTML file that
invokes the PrimePanel.xhtml composite component file along with the managed
bean. It validates the user's input.
<div id="compositecomponent">
<ez:PrimePanel primeBean="#{primeBean}"
calcAction="#{primeBean.calculate}">
</ez:PrimePanel>
</div>
14.4.3 The Managed Bean
The managed bean, PrimeBean.java, defines a method called calculate, which
performs the calculations on the input string and sets properties accordingly. The bean
first creates an array of prime numbers. It calculates the sum of the letters in the string,
with 'a' equal to 1 and 'z' equal to 26, and determines whether the value can be
found in the array of primes. An uppercase letter in the input string has the same
value as its lowercase equivalent.
The bean specifies the minimum and maximum size of the name string, which is
enforced by the Bean Validation @Size constraint. The bean uses the @Model
annotation, a shortcut for @Named and @RequestScoped, as described in Step 7 of To
View the hello1 Web Module Using NetBeans IDE.
@Model
public class PrimeBean implements Serializable {
...
@Size(min=1, max=45)
private String name;
...
public String calculate() {
...
}
}
14-4 The Java EE 7 Tutorial
The compositecomponentexample Example Application
14.4.4 Running the compositecomponentexample Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
compositecomponentexample example.
14.4.4.1 To Build, Package, and Deploy the compositecomponentexample Example
Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsf
4.
Select the compositecomponentexample folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the compositecomponentexample project and select
Build.
This command builds and deploys the application.
14.4.4.2 To Build, Package, and Deploy the compositecomponentexample Example
Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/jsf/compositecomponentexample/
3.
Enter the following command to build and deploy the application:
mvn install
14.4.4.3 To Run the compositecomponentexample Example
1.
In a web browser, enter the following URL:
http://localhost:8080/compositecomponentexample
2.
On the page that appears, enter a string in the Name, word, or phrase field, then
click Calculate.
The page reports the sum of the letters and whether the sum is prime. A validation
error is reported if no value is entered or if the string contains more than 45
characters.
Composite Components: Advanced Topics and an Example
14-5
The compositecomponentexample Example Application
14-6 The Java EE 7 Tutorial
15
Creating Custom UI Components and Other
Custom Objects
15
JavaServer Faces technology offers a basic set of standard, reusable UI components
that enable quick and easy construction of user interfaces for web applications. These
components mostly map one-to-one to the elements in HTML 4. But often an
application requires a component that has additional functionality or requires a
completely new component. JavaServer Faces technology allows extension of standard
components to enhance their functionality or to create custom components. A rich
ecosystem of third-party component libraries is built on this extension capability, but it
is beyond the scope of this tutorial to examine them. A web search for "JSF Component
Libraries" is a good starting point to learn more about this important aspect of using
JavaServer Faces technology.
In addition to extending the functionality of standard components, a component
writer might want to give a page author the ability to change the appearance of the
component on the page or to alter listener behavior. Alternatively, the component
writer might want to render a component to a different kind of client device type, such
as a smartphone or a tablet instead of a desktop computer. Enabled by the flexible
JavaServer Faces architecture, a component writer can separate the definition of the
component behavior from its appearance by delegating the rendering of the
component to a separate renderer. In this way, a component writer can define the
behavior of a custom component once but create multiple renderers, each of which
defines a different way to render the component to a particular kind of client device.
A javax.faces.component.UIComponent is a Java class that is responsible for
representing a self-contained piece of the user interface during the request-processing
lifecycle. It is intended to represent the meaning of the component; the visual
representation of the component is the responsibility of the
javax.faces.render.Renderer. There can be multiple instances of the same
UIComponent class in any given JavaServer Faces view, just as there can be multiple
instances of any Java class in any given Java program.
JavaServer Faces technology provides the ability to create custom components by
extending the UIComponent class, the base class for all standard UI components. A
custom component can be used anywhere an ordinary component can be used, such as
within a composite component. A UIComponent is identified by two names:
component-family specifies the general purpose of the component (input or output,
for instance), and component-type indicates the specific purpose of a component, such
as a text input field or a command button.
A Renderer is a helper to the UIComponent that deals with how that specific
UIComponent class should appear in a specific kind of client device. Renderers are
identified by two names: render-kit-id and renderer-type. A render kit is just a
bucket into which a particular group of renderers is placed, and the render-kit-id
Creating Custom UI Components and Other Custom Objects 15-1
Determining Whether You Need a Custom Component or Renderer
identifies the group. Most JavaServer Faces component libraries provide their own
render kits.
A javax.faces.view.facelets.Tag object is a helper to the UIComponent and
Renderer that allows the page author to include an instance of a UIComponent in a
JavaServer Faces view. A tag represents a specific combination of component-type and
renderer-type.
See Component, Renderer, and Tag Combinations for information on how
components, renderers, and tags interact.
This chapter uses the image map component from the Duke's Bookstore case study
example to explain how you can create simple custom components, custom renderers,
and associated custom tags, and take care of all the other details associated with using
the components and renderers in an application. See Chapter 57, "Duke's Bookstore
Case Study Example" for more information about this example.
The chapter also describes how to create other custom objects: custom converters,
custom listeners, and custom validators. It also describes how to bind component
values and instances to data objects and how to bind custom objects to managed bean
properties.
The following topics are addressed here:
■
Determining Whether You Need a Custom Component or Renderer
■
Understanding the Image Map Example
■
Steps for Creating a Custom Component
■
Creating Custom Component Classes
■
Delegating Rendering to a Renderer
■
Implementing an Event Listener
■
Handling Events for Custom Components
■
Defining the Custom Component Tag in a Tag Library Descriptor
■
Using a Custom Component
■
Creating and Using a Custom Converter
■
Creating and Using a Custom Validator
■
Binding Component Values and Instances to Managed Bean Properties
■
Binding Converters, Listeners, and Validators to Managed Bean Properties
15.1 Determining Whether You Need a Custom Component or Renderer
The JavaServer Faces implementation supports a very basic set of components and
associated renderers. This section helps you to decide whether you can use standard
components and renderers in your application or need a custom component or custom
renderer.
15.1.1 When to Use a Custom Component
A component class defines the state and behavior of a UI component. This behavior
includes converting the value of a component to the appropriate markup, queuing
events on components, performing validation, and any other behavior related to how
the component interacts with the browser and the request-processing lifecycle.
15-2 The Java EE 7 Tutorial
Determining Whether You Need a Custom Component or Renderer
You need to create a custom component in the following situations.
■
■
■
■
You need to add new behavior to a standard component, such as generating an
additional type of event (for example, notifying another part of the page that
something changed in this component as a result of user interaction).
You need to take a different action in the request processing of the value of a
component from what is available in any of the existing standard components.
You want to take advantage of an HTML capability offered by your target browser,
but none of the standard JavaServer Faces components take advantage of the
capability in the way you want, if at all. The current release does not contain
standard components for complex HTML components, such as frames; however,
because of the extensibility of the component architecture, you can use JavaServer
Faces technology to create components like these. The Duke's Bookstore case study
creates custom components that correspond to the HTML map and area tags.
You need to render to a non-HTML client that requires extra components not
supported by HTML. Eventually, the standard HTML render kit will provide
support for all standard HTML components. However, if you are rendering to a
different client, such as a phone, you might need to create custom components to
represent the controls uniquely supported by the client. For example, some
component architectures for wireless clients include support for tickers and
progress bars, which are not available on an HTML client. In this case, you might
also need a custom renderer along with the component, or you might need only a
custom renderer.
You do not need to create a custom component in the following cases.
■
■
■
■
■
You need to aggregate components to create a new component that has its own
unique behavior. In this situation, you can use a composite component to combine
existing standard components. For more information on composite components,
see Composite Components and Chapter 14, "Composite Components: Advanced
Topics and an Example".
You simply need to manipulate data on the component or add application-specific
functionality to it. In this situation, you should create a managed bean for this
purpose and bind it to the standard component rather than create a custom
component. See Managed Beans in JavaServer Faces Technology for more
information on managed beans.
You need to convert a component's data to a type not supported by its renderer.
See Using the Standard Converters for more information about converting a
component's data.
You need to perform validation on the component data. Standard validators and
custom validators can be added to a component by using the validator tags from
the page. See Using the Standard Validators and Creating and Using a Custom
Validator for more information about validating a component's data.
You need to register event listeners on components. You can either register event
listeners on components using the f:valueChangeListener and f:actionListener
tags, or you can point at an event-processing method on a managed bean using the
component's actionListener or valueChangeListener attributes. See
Implementing an Event Listener and Writing Managed Bean Methods for more
information.
Creating Custom UI Components and Other Custom Objects 15-3
Determining Whether You Need a Custom Component or Renderer
15.1.2 When to Use a Custom Renderer
A renderer, which generates the markup to display a component on a web page,
allows you to separate the semantics of a component from its appearance. By keeping
this separation, you can support different kinds of client devices with the same kind of
authoring experience. You can think of a renderer as a "client adapter." It produces
output suitable for consumption and display by the client and accepts input from the
client when the user interacts with that component.
If you are creating a custom component, you need to ensure, among other things, that
your component class performs these operations that are central to rendering the
component:
■
■
Decoding: Converting the incoming request parameters to the local value of the
component
Encoding: Converting the current local value of the component into the
corresponding markup that represents it in the response
The JavaServer Faces specification supports two programming models for handling
encoding and decoding.
■
■
Direct implementation: The component class itself implements the decoding and
encoding.
Delegated implementation: The component class delegates the implementation of
encoding and decoding to a separate renderer.
By delegating the operations to the renderer, you have the option of associating your
custom component with different renderers so that you can render the component on
different clients. If you don't plan to render a particular component on different clients,
it may be simpler to let the component class handle the rendering. However, a
separate renderer enables you to preserve the separation of semantics from
appearance. The Duke's Bookstore application separates the renderers from the
components, although it renders only to HTML 4 web browsers.
If you aren't sure whether you will need the flexibility offered by separate renderers
but you want to use the simpler direct-implementation approach, you can actually use
both models. Your component class can include some default rendering code, but it
can delegate rendering to a renderer if there is one.
15.1.3 Component, Renderer, and Tag Combinations
When you create a custom component, you can create a custom renderer to go with it.
To associate the component with the renderer and to reference the component from the
page, you will also need a custom tag.
Although you need to write the custom component and renderer, there is no need to
write code for a custom tag (called a tag handler). If you specify the component and
renderer combination, Facelets creates the tag handler automatically.
In rare situations, you might use a custom renderer with a standard component rather
than a custom component. Or you might use a custom tag without a renderer or a
component. This section gives examples of these situations and summarizes what is
required for a custom component, renderer, and tag.
You would use a custom renderer without a custom component if you wanted to add
some client-side validation on a standard component. You would implement the
validation code with a client-side scripting language, such as JavaScript, and then
render the JavaScript with the custom renderer. In this situation, you need a custom
15-4 The Java EE 7 Tutorial
Understanding the Image Map Example
tag to go with the renderer so that its tag handler can register the renderer on the
standard component.
Custom components as well as custom renderers need custom tags associated with
them. However, you can have a custom tag without a custom renderer or custom
component. For example, suppose that you need to create a custom validator that
requires extra attributes on the validator tag. In this case, the custom tag corresponds
to a custom validator and not to a custom component or custom renderer. In any case,
you still need to associate the custom tag with a server-side object.
Table 15–1 summarizes what you must or can associate with a custom component,
custom renderer, or custom tag.
Table 15–1
Tags
Requirements for Custom Components, Custom Renderers, and Custom
Custom Item
Must Have
Can Have
Custom
component
Custom tag
Custom renderer or standard
renderer
Custom renderer
Custom tag
Custom component or standard
component
Custom
JavaServer Faces
tag
Some server-side object, like a
component, a custom renderer, or
custom validator
Custom component or standard
component associated with a custom
renderer
15.2 Understanding the Image Map Example
Duke's Bookstore includes a custom image map component on the index.xhtml page.
This image map displays a selection of six book titles. When the user clicks one of the
book titles in the image map, the application goes to a page that displays the title of
the selected book as well as information about a featured book. The page allows the
user to add either book (or none) to the shopping cart.
15.2.1 Why Use JavaServer Faces Technology to Implement an Image Map?
JavaServer Faces technology is an ideal framework to use for implementing this kind
of image map because it can perform the work that must be done on the server
without requiring you to create a server-side image map.
In general, client-side image maps are preferred over server-side image maps for
several reasons. One reason is that the client-side image map allows the browser to
provide immediate feedback when a user positions the mouse over a hotspot. Another
reason is that client-side image maps perform better because they don't require
round-trips to the server. However, in some situations, your image map might need to
access the server to retrieve data or to change the appearance of nonform controls,
tasks that a client-side image map cannot do.
Because the image map custom component uses JavaServer Faces technology, it has
the best of both styles of image maps: It can handle the parts of the application that
need to be performed on the server while allowing the other parts of the application to
be performed on the client side.
15.2.2 Understanding the Rendered HTML
Here is an abbreviated version of the form part of the HTML page that the application
needs to render:
<form id="j_idt13" name="j_idt13" method="post"
Creating Custom UI Components and Other Custom Objects 15-5
Understanding the Image Map Example
action="/dukesbookstore/index.xhtml" ...>
...
<img id="j_idt13:mapImage"
src="/dukesbookstore/javax.faces.resource/book_all.jpg?ln=images"
alt="Choose a Book from our Catalog"
usemap="#bookMap" />
...
<map name="bookMap">
<area alt="Duke"
coords="67,23,212,268"
shape="rect"
onmouseout="document.forms[0]['j_idt13:mapImage'].src='resources/images/book_all.jpg'"
onmouseover="document.forms[0]['j_idt13:mapImage'].src='resources/images/book_201.jpg'"
onclick="document.forms[0]['bookMap_current'].value='Duke'; document.forms[0].submit()"
/>
...
<input type="hidden" name="bookMap_current">
</map>
...
</form>
The img tag associates an image (book_all.jpg) with the image map referenced in the
usemap attribute value.
The map tag specifies the image map and contains a set of area tags.
Each area tag specifies a region of the image map. The onmouseover, onmouseout, and
onclick attributes define which JavaScript code is executed when these events occur.
When the user moves the mouse over a region, the onmouseover function associated
with the region displays the map with that region highlighted. When the user moves
the mouse out of a region, the onmouseout function redisplays the original image. If the
user clicks on a region, the onclick function sets the value of the input tag to the ID of
the selected area and submits the page.
The input tag represents a hidden control that stores the value of the currently
selected area between client-server exchanges so that the server-side component
classes can retrieve the value.
The server-side objects retrieve the value of bookMap_current and set the locale in the
javax.faces.context.FacesContext instance according to the region that was
selected.
15.2.3 Understanding the Facelets Page
Here is an abbreviated form of the Facelets page that the image map component uses
to generate the HTML page shown in the preceding section. It uses custom
bookstore:map and bookstore:area tags to represent the custom components:
<h:form>
...
<h:graphicImage id="mapImage"
name="book_all.jpg"
library="images"
alt="#{bundle.ChooseBook}"
usemap="#bookMap" />
<bookstore:map id="bookMap"
current="map1"
immediate="true"
action="bookstore">
<f:actionListener
type="dukesbookstore.listeners.MapBookChangeListener" />
15-6 The Java EE 7 Tutorial
Understanding the Image Map Example
<bookstore:area id="map1" value="#{Book201}"
onmouseover="resources/images/book_201.jpg"
onmouseout="resources/images/book_all.jpg"
targetImage="mapImage" />
<bookstore:area id="map2" value="#{Book202}"
onmouseover="resources/images/book_202.jpg"
onmouseout="resources/images/book_all.jpg"
targetImage="mapImage"/>
...
</bookstore:map>
...
</h:form>
The alt attribute of the h:graphicImage tag maps to the localized string "Choose a
Book from our Catalog".
The f:actionListener tag within the bookstore:map tag points to a listener class for
an action event. The processAction method of the listener places the book ID for the
selected map area into the session map. The way this event is handled is explained
more in Handling Events for Custom Components.
The action attribute of the bookstore:map tag specifies a logical outcome String,
"bookstore", which by implicit navigation rules sends the application to the page
bookstore.xhtml. For more information on navigation, see Configuring Navigation
Rules.
The immediate attribute of the bookstore:map tag is set to true, which indicates that
the default javax.faces.event.ActionListener implementation should execute
during the Apply Request Values phase of the request-processing lifecycle, instead of
waiting for the Invoke Application phase. Because the request resulting from clicking
the map does not require any validation, data conversion, or server-side object
updates, it makes sense to skip directly to the Invoke Application phase.
The current attribute of the bookstore:map tag is set to the default area, which is map1
(the book My Early Years: Growing Up on Star7, by Duke).
Notice that the bookstore:area tags do not contain any of the JavaScript, coordinate,
or shape data that is displayed on the HTML page. The JavaScript is generated by the
dukesbookstore.renderers.AreaRenderer class. The onmouseover and onmouseout
attribute values indicate the image to be loaded when these events occur. How the
JavaScript is generated is explained more in Performing Encoding.
The coordinate, shape, and alternate text data are obtained through the value
attribute, whose value refers to an attribute in application scope. The value of this
attribute is a bean, which stores the coords, shape, and alt data. How these beans are
stored in the application scope is explained more in the next section.
15.2.4 Configuring Model Data
In a JavaServer Faces application, data such as the coordinates of a hotspot of an image
map is retrieved from the value attribute through a bean. However, the shape and
coordinates of a hotspot should be defined together because the coordinates are
interpreted differently depending on what shape the hotspot is. Because a
component's value can be bound only to one property, the value attribute cannot refer
to both the shape and the coordinates.
To solve this problem, the application encapsulates all of this information in a set of
ImageArea objects. These objects are initialized into application scope by the managed
bean creation facility (see Section 16.4.1, "Using the managed-bean Element"). Here is
Creating Custom UI Components and Other Custom Objects 15-7
Understanding the Image Map Example
part of the managed bean declaration for the ImageArea bean corresponding to the
South America hotspot:
<managed-bean eager="true">
...
<managed-bean-name>Book201</managed-bean-name>
<managed-bean-class>
javaeetutorial.dukesbookstore.model.ImageArea
</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<managed-property>
...
<property-name>shape</property-name>
<value>rect</value>
</managed-property>
<managed-property>
...
<property-name>alt</property-name>
<value>Duke</value>
</managed-property>
<managed-property>
...
<property-name>coords</property-name>
<value>67,23,212,268</value>
</managed-property>
</managed-bean>
For more information on initializing managed beans with the managed bean creation
facility, see the section Application Configuration Resource File.
The value attributes of the bookstore:area tags refer to the beans in the application
scope, as shown in this bookstore:area tag from index.xhtml:
<bookstore:area id="map1" value="#{Book201}"
onmouseover="resources/images/book_201.jpg"
onmouseout="resources/images/book_all.jpg"
targetImage="mapImage" />
To reference the ImageArea model object bean values from the component class, you
implement a getValue method in the component class. This method calls
super.getValue. The superclass of
tut-install/examples/case-studies/dukes-bookstore/src/java/dukesbookstore/com
ponents/AreaComponent.java, UIOutput, has a getValue method that does the work
of finding the ImageArea object associated with AreaComponent. The AreaRenderer
class, which needs to render the alt, shape, and coords values from the ImageArea
object, calls the getValue method of AreaComponent to retrieve the ImageArea object.
ImageArea iarea = (ImageArea) area.getValue();
ImageArea is a simple bean, so you can access the shape, coordinates, and alternative
text values by calling the appropriate accessor methods of ImageArea. Creating the
Renderer Class explains how to do this in the AreaRenderer class.
15.2.5 Summary of the Image Map Application Classes
Table 15–2 summarizes all the classes needed to implement the image map
component.
15-8 The Java EE 7 Tutorial
Creating Custom Component Classes
Table 15–2
Image Map Classes
Class
Function
AreaSelectedEvent
The javax.faces.event.ActionEvent indicating that an AreaComponent
from the MapComponent has been selected.
AreaComponent
The class that defines AreaComponent, which corresponds to the
bookstore:area custom tag.
MapComponent
The class that defines MapComponent, which corresponds to the
bookstore:map custom tag.
AreaRenderer
This javax.faces.render.Renderer performs the delegated rendering for
AreaComponent.
ImageArea
The bean that stores the shape and coordinates of the hotspots.
MapBookChangeListener
The action listener for the MapComponent.
The Duke's Bookstore source directory, called bookstore-dir, is
tut-install/examples/case-studies/dukes-bookstore/src/java/dukesbookstore/.
The event and listener classes are located in bookstore-dir/listeners/. The component
classes are located in bookstore-dir/components/. The renderer classes are located in
bookstore-dir/renderers/. ImageArea is located in bookstore-dir/model/.
15.3 Steps for Creating a Custom Component
You can apply the following steps while developing your own custom component.
1.
2.
Create a custom component class that does the following:
a.
Overrides the getFamily method to return the component family, which is
used to look up renderers that can render the component
b.
Includes the rendering code or delegates it to a renderer (explained in Step 2)
c.
Enables component attributes to accept expressions
d.
Queues an event on the component if the component generates events
e.
Saves and restores the component state
Delegate rendering to a renderer if your component does not handle the
rendering. To do this:
a.
Create a custom renderer class by extending javax.faces.render.Renderer.
b.
Register the renderer to a render kit.
3.
Register the component.
4.
Create an event handler if your component generates events.
5.
Create a tag library descriptor (TLD) that defines the custom tag.
See Registering a Custom Component and Registering a Custom Renderer with a
Render Kit for information on registering the custom component and the renderer. The
section Using a Custom Component discusses how to use the custom component in a
JavaServer Faces page.
15.4 Creating Custom Component Classes
As explained in When to Use a Custom Component, a component class defines the
state and behavior of a UI component. The state information includes the component's
Creating Custom UI Components and Other Custom Objects 15-9
Creating Custom Component Classes
type, identifier, and local value. The behavior defined by the component class includes
the following:
■
Decoding (converting the request parameter to the component's local value)
■
Encoding (converting the local value into the corresponding markup)
■
Saving the state of the component
■
Updating the bean value with the local value
■
Processing validation on the local value
■
Queueing events
The javax.faces.component.UIComponentBase class defines the default behavior of a
component class. All the classes representing the standard components extend from
UIComponentBase. These classes add their own behavior definitions, as your custom
component class will do.
Your custom component class must either extend UIComponentBase directly or extend
a class representing one of the standard components. These classes are located in the
javax.faces.component package, and their names begin with UI.
If your custom component serves the same purpose as a standard component, you
should extend that standard component rather than directly extend UIComponentBase.
For example, suppose you want to create an editable menu component. It makes sense
to have this component extend UISelectOne rather than UIComponentBase because you
can reuse the behavior already defined in UISelectOne. The only new functionality
you need to define is to make the menu editable.
Whether you decide to have your component extend UIComponentBase or a standard
component, you might also want your component to implement one or more of these
behavioral interfaces defined in the javax.faces.component package:
■
■
■
■
■
■
ActionSource: Indicates that the component can fire a
javax.faces.event.ActionEvent
ActionSource2: Extends ActionSource and allows component properties
referencing methods that handle action events to use method expressions as
defined by the EL
EditableValueHolder: Extends ValueHolder and specifies additional features for
editable components, such as validation and emitting value-change events
NamingContainer: Mandates that each component rooted at this component has a
unique ID
StateHolder: Denotes that a component has state that must be saved between
requests
ValueHolder: Indicates that the component maintains a local value as well as the
option of accessing data in the model tier
If your component extends UIComponentBase, it automatically implements only
StateHolder. Because all components directly or indirectly extend UIComponentBase,
they all implement StateHolder. Any component that implements StateHolder also
implements the StateHelper interface, which extends StateHolder and defines a
Map-like contract that makes it easy for components to save and restore a partial view
state.
If your component extends one of the other standard components, it might also
implement other behavioral interfaces in addition to StateHolder. If your component
extends UICommand, it automatically implements ActionSource2. If your component
15-10 The Java EE 7 Tutorial
Creating Custom Component Classes
extends UIOutput or one of the component classes that extend UIOutput, it
automatically implements ValueHolder. If your component extends UIInput, it
automatically implements EditableValueHolder and ValueHolder. See the JavaServer
Faces API documentation to find out what the other component classes implement.
You can also make your component explicitly implement a behavioral interface that it
doesn't already by virtue of extending a particular standard component. For example,
if you have a component that extends UIInput and you want it to fire action events,
you must make it explicitly implement ActionSource2 because a UIInput component
doesn't automatically implement this interface.
The Duke's Bookstore image map example has two component classes: AreaComponent
and MapComponent. The MapComponent class extends UICommand and therefore
implements ActionSource2, which means it can fire action events when a user clicks
on the map. The AreaComponent class extends the standard component UIOutput. The
@FacesComponent annotation registers the components with the JavaServer Faces
implementation:
@FacesComponent("DemoMap")
public class MapComponent extends UICommand {...}
@FacesComponent("DemoArea")
public class AreaComponent extends UIOutput {...}
The MapComponent class represents the component corresponding to the
bookstore:map tag:
<bookstore:map id="bookMap"
current="map1"
immediate="true"
action="bookstore">
...
</bookstore:map>
The AreaComponent class represents the component corresponding to the
bookstore:area tag:
<bookstore:area id="map1" value="#{Book201}"
onmouseover="resources/images/book_201.jpg"
onmouseout="resources/images/book_all.jpg"
targetImage="mapImage"/>
MapComponent has one or more AreaComponent instances as children. Its behavior
consists of the following actions:
■
Retrieving the value of the currently selected area
■
Defining the properties corresponding to the component's values
■
Generating an event when the user clicks on the image map
■
Queuing the event
■
Saving its state
■
Rendering the HTML map tag and the HTML input tag
MapComponent delegates the rendering of the HTML map and input tags to the
MapRenderer class.
AreaComponent is bound to a bean that stores the shape and coordinates of the region
of the image map. You will see how all this data is accessed through the value
expression in Creating the Renderer Class. The behavior of AreaComponent consists of
Creating Custom UI Components and Other Custom Objects
15-11
Creating Custom Component Classes
the following:
■
Retrieving the shape and coordinate data from the bean
■
Setting the value of the hidden tag to the id of this component
■
Rendering the area tag, including the JavaScript for the onmouseover, onmouseout,
and onclick functions
Although these tasks are actually performed by AreaRenderer, AreaComponent must
delegate the tasks to AreaRenderer. See Delegating Rendering to a Renderer for more
information.
The rest of this section describes the tasks that MapComponent performs as well as the
encoding and decoding that it delegates to MapRenderer. Handling Events for Custom
Components details how MapComponent handles events.
15.4.1 Specifying the Component Family
If your custom component class delegates rendering, it needs to override the
getFamily method of UIComponent to return the identifier of a component family,
which is used to refer to a component or set of components that can be rendered by a
renderer or set of renderers. The component family is used along with the renderer
type to look up renderers that can render the component:
public String getFamily() {
return ("Map");
}
The component family identifier, Map, must match that defined by the
component-family elements included in the component and renderer configurations in
the application configuration resource file. Registering a Custom Renderer with a
Render Kit explains how to define the component family in the renderer configuration.
Registering a Custom Component explains how to define the component family in the
component configuration.
15.4.2 Performing Encoding
During the Render Response phase, the JavaServer Faces implementation processes
the encoding methods of all components and their associated renderers in the view.
The encoding methods convert the current local value of the component into the
corresponding markup that represents it in the response.
The UIComponentBase class defines a set of methods for rendering markup:
encodeBegin, encodeChildren, and encodeEnd. If the component has child
components, you might need to use more than one of these methods to render the
component; otherwise, all rendering should be done in encodeEnd. Alternatively, you
can use the encodeALL method, which encompasses all the methods.
Because MapComponent is a parent component of AreaComponent, the area tags must be
rendered after the beginning map tag and before the ending map tag. To accomplish this,
the MapRenderer class renders the beginning map tag in encodeBegin and the rest of the
map tag in encodeEnd.
The JavaServer Faces implementation automatically invokes the encodeEnd method of
AreaComponent's renderer after it invokes MapRenderer's encodeBegin method and
before it invokes MapRenderer's encodeEnd method. If a component needs to perform
the rendering for its children, it does this in the encodeChildren method.
Here are the encodeBegin and encodeEnd methods of MapRenderer:
15-12 The Java EE 7 Tutorial
Creating Custom Component Classes
@Override
public void encodeBegin(FacesContext context, UIComponent component)
throws IOException {
if ((context == null)|| (component == null)) {
throw new NullPointerException();
}
MapComponent map = (MapComponent) component;
ResponseWriter writer = context.getResponseWriter();
writer.startElement("map", map);
writer.writeAttribute("name", map.getId(), "id");
}
@Override
public void encodeEnd(FacesContext context, UIComponent component)
throws IOException {
if ((context == null) || (component == null)){
throw new NullPointerException();
}
MapComponent map = (MapComponent) component;
ResponseWriter writer = context.getResponseWriter();
writer.startElement("input", map);
writer.writeAttribute("type", "hidden", null);
writer.writeAttribute("name", getName(context,map), "clientId");
writer.endElement("input");
writer.endElement("map");
}
Notice that encodeBegin renders only the beginning map tag. The encodeEnd method
renders the input tag and the ending map tag.
The encoding methods accept a UIComponent argument and a
javax.faces.context.FacesContext argument. The FacesContext instance contains
all the information associated with the current request. The UIComponent argument is
the component that needs to be rendered.
The rest of the method renders the markup to the
javax.faces.context.ResponseWriter instance, which writes out the markup to the
current response. This basically involves passing the HTML tag names and attribute
names to the ResponseWriter instance as strings, retrieving the values of the
component attributes, and passing these values to the ResponseWriter instance.
The startElement method takes a String (the name of the tag) and the component to
which the tag corresponds (in this case, map). (Passing this information to the
ResponseWriter instance helps design-time tools know which portions of the
generated markup are related to which components.)
After calling startElement, you can call writeAttribute to render the tag's attributes.
The writeAttribute method takes the name of the attribute, its value, and the name of
a property or attribute of the containing component corresponding to the attribute.
The last parameter can be null, and it won't be rendered.
The name attribute value of the map tag is retrieved using the getId method of
UIComponent, which returns the component's unique identifier. The name attribute
value of the input tag is retrieved using the getName(FacesContext, UIComponent)
method of MapRenderer.
If you want your component to perform its own rendering but delegate to a renderer if
there is one, include the following lines in the encoding method to check whether there
is a renderer associated with this component:
if (getRendererType() != null) {
Creating Custom UI Components and Other Custom Objects
15-13
Creating Custom Component Classes
super.encodeEnd(context);
return;
}
If there is a renderer available, this method invokes the superclass's encodeEnd
method, which does the work of finding the renderer. The MapComponent class
delegates all rendering to MapRenderer, so it does not need to check for available
renderers.
In some custom component classes that extend standard components, you might need
to implement other methods in addition to encodeEnd. For example, if you need to
retrieve the component's value from the request parameters, you must also implement
the decode method.
15.4.3 Performing Decoding
During the Apply Request Values phase, the JavaServer Faces implementation
processes the decode methods of all components in the tree. The decode method
extracts a component's local value from incoming request parameters and uses a
javax.faces.convert.Converter implementation to convert the value to a type that is
acceptable to the component class.
A custom component class or its renderer must implement the decode method only if
it must retrieve the local value or if it needs to queue events. The component queues
the event by calling queueEvent.
Here is the decode method of MapRenderer:
@Override
public void decode(FacesContext context, UIComponent component) {
if ((context == null) || (component == null)) {
throw new NullPointerException();
}
MapComponent map = (MapComponent) component;
String key = getName(context, map);
String value = (String) context.getExternalContext().
getRequestParameterMap().get(key);
if (value != null)
map.setCurrent(value);
}
}
The decode method first gets the name of the hidden input field by calling
getName(FacesContext, UIComponent). It then uses that name as the key to the
request parameter map to retrieve the current value of the input field. This value
represents the currently selected area. Finally, it sets the value of the MapComponent
class's current attribute to the value of the input field.
15.4.4 Enabling Component Properties to Accept Expressions
Nearly all the attributes of the standard JavaServer Faces tags can accept expressions,
whether they are value expressions or method expressions. It is recommended that
you also enable your component attributes to accept expressions because it gives you
much more flexibility when you write Facelets pages.
To enable the attributes to accept expressions, the component class must implement
getter and setter methods for the component properties. These methods can use the
facilities offered by the StateHelper interface to store and retrieve not only the values
for these properties but also the state of the components across multiple requests.
15-14 The Java EE 7 Tutorial
Creating Custom Component Classes
Because MapComponent extends UICommand, the UICommand class already does the work
of getting the ValueExpression and MethodExpression instances associated with each
of the attributes that it supports. Similarly, the UIOutput class that AreaComponent
extends already obtains the ValueExpression instances for its supported attributes.
For both components, the simple getter and setter methods store and retrieve the key
values and state for the attributes, as shown in this code fragment from
AreaComponent:
enum PropertyKeys {
alt, coords, shape, targetImage;
}
public String getAlt() {
return (String) getStateHelper().eval(PropertyKeys.alt, null);
}
public void setAlt(String alt) {
getStateHelper().put(PropertyKeys.alt, alt);
}
...
However, if you have a custom component class that extends UIComponentBase, you
will need to implement the methods that get the ValueExpression and
MethodExpression instances associated with those attributes that are enabled to accept
expressions. For example, you could include a method that gets the ValueExpression
instance for the immediate attribute:
public boolean isImmediate() {
if (this.immediateSet) {
return (this.immediate);
}
ValueExpression ve = getValueExpression("immediate");
if (ve != null) {
Boolean value = (Boolean) ve.getValue(
getFacesContext().getELContext());
return (value.booleanValue());
} else {
return (this.immediate);
}
}
The properties corresponding to the component attributes that accept method
expressions must accept and return a MethodExpression object. For example, if
MapComponent extended UIComponentBase instead of UICommand, it would need to
provide an action property that returns and accepts a MethodExpression object:
public MethodExpression getAction() {
return (this.action);
}
public void setAction(MethodExpression action) {
this.action = action;
}
15.4.5 Saving and Restoring State
As described in Enabling Component Properties to Accept Expressions, use of the
StateHelper interface facilities allows you to save the component's state at the same
time you set and retrieve property values. The StateHelper implementation allows
partial state saving; it saves only the changes in the state since the initial request, not
the entire state, because the full state can be restored during the Restore View phase.
Creating Custom UI Components and Other Custom Objects
15-15
Delegating Rendering to a Renderer
Component classes that implement StateHolder may prefer to implement the
saveState(FacesContext) and restoreState(FacesContext, Object) methods to
help the JavaServer Faces implementation save and restore the state of components
across multiple requests.
To save a set of values, you can implement the saveState(FacesContext) method.
This method is called during the Render Response phase, during which the state of the
response is saved for processing on subsequent requests. Here is a hypothetical
method from MapComponent, which has only one attribute, current:
@Override
public Object saveState(FacesContext context) {
Object values[] = new Object[2];
values[0] = super.saveState(context);
values[1] = current;
return (values);
}
This method initializes an array, which will hold the saved state. It next saves all of the
state associated with the component.
A component that implements StateHolder may also provide an implementation for
restoreState(FacesContext, Object), which restores the state of the component to
that saved with the saveState(FacesContext) method. The
restoreState(FacesContext, Object) method is called during the Restore View
phase, during which the JavaServer Faces implementation checks whether there is any
state that was saved during the last Render Response phase and needs to be restored
in preparation for the next postback.
Here is a hypothetical restoreState(FacesContext, Object) method from
MapComponent:
public void restoreState(FacesContext context, Object state) {
Object values[] = (Object[]) state;
super.restoreState(context, values[0]);
current = (String) values[1];
}
This method takes a FacesContext and an Object instance, representing the array that
is holding the state for the component. This method sets the component's properties to
the values saved in the Object array.
Whether or not you implement these methods in your component class, you can use
the javax.faces.STATE_SAVING_METHOD context parameter to specify in the
deployment descriptor where you want the state to be saved: either client or server.
If state is saved on the client, the state of the entire view is rendered to a hidden field
on the page. By default, the state is saved on the server.
The web applications in the Duke's Forest case study save their view state on the
client.
Saving state on the client uses more bandwidth as well as more client resources,
whereas saving it on the server uses more server resources. You may also want to save
state on the client if you expect your users to disable cookies.
15.5 Delegating Rendering to a Renderer
Both MapComponent and AreaComponent delegate all of their rendering to a separate
renderer. The section Performing Encoding explains how MapRenderer performs the
encoding for MapComponent. This section explains in detail the process of delegating
15-16 The Java EE 7 Tutorial
Delegating Rendering to a Renderer
rendering to a renderer using AreaRenderer, which performs the rendering for
AreaComponent.
To delegate rendering, you perform these tasks.
■
■
■
Create the Renderer class.
Register the renderer with a render kit by using the @FacesRenderer annotation
(or by using the application configuration resource file, as explained in Registering
a Custom Renderer with a Render Kit).
Identify the renderer type in the FacesRenderer annotation.
15.5.1 Creating the Renderer Class
When delegating rendering to a renderer, you can delegate all encoding and decoding
to the renderer, or you can choose to do part of it in the component class. The
AreaComponent class delegates encoding to the AreaRenderer class.
The renderer class begins with a @FacesRenderer annotation:
@FacesRenderer(componentFamily = "Area", rendererType = "DemoArea")
public class AreaRenderer extends Renderer {
The @FacesRenderer annotation registers the renderer class with the JavaServer Faces
implementation as a renderer class. The annotation identifies the component family as
well as the renderer type.
To perform the rendering for AreaComponent, AreaRenderer must implement an
encodeEnd method. The encodeEnd method of AreaRenderer retrieves the shape,
coordinates, and alternative text values stored in the ImageArea bean that is bound to
AreaComponent. Suppose that the area tag currently being rendered has a value
attribute value of "book203". The following line from encodeEnd gets the value of the
attribute "book203" from the FacesContext instance:
ImageArea ia = (ImageArea)area.getValue();
The attribute value is the ImageArea bean instance, which contains the shape, coords,
and alt values associated with the book203 AreaComponent instance. Configuring
Model Data describes how the application stores these values.
After retrieving the ImageArea object, the method renders the values for shape, coords,
and alt by simply calling the associated accessor methods and passing the returned
values to the ResponseWriter instance, as shown by these lines of code, which write
out the shape and coordinates:
writer.startElement("area", area);
writer.writeAttribute("alt", iarea.getAlt(), "alt");
writer.writeAttribute("coords", iarea.getCoords(), "coords");
writer.writeAttribute("shape", iarea.getShape(), "shape");
The encodeEnd method also renders the JavaScript for the onmouseout, onmouseover,
and onclick attributes. The Facelets page needs to provide only the path to the images
that are to be loaded during an onmouseover or onmouseout action:
<bookstore:area id="map3" value="#{Book203}"
onmouseover="resources/images/book_203.jpg"
onmouseout="resources/images/book_all.jpg"
targetImage="mapImage"/>
The AreaRenderer class takes care of generating the JavaScript for these actions, as
shown in the following code from encodeEnd. The JavaScript that AreaRenderer
Creating Custom UI Components and Other Custom Objects
15-17
Implementing an Event Listener
generates for the onclick action sets the value of the hidden field to the value of the
current area's component ID and submits the page.
sb = new StringBuffer("document.forms[0]['").append(targetImageId).
append("'].src='");
sb.append(
getURI(context,
(String) area.getAttributes().get("onmouseout")));
sb.append("'");
writer.writeAttribute("onmouseout", sb.toString(), "onmouseout");
sb = new StringBuffer("document.forms[0]['").append(targetImageId).
append("'].src='");
sb.append(
getURI(context,
(String) area.getAttributes().get("onmouseover")));
sb.append("'");
writer.writeAttribute("onmouseover", sb.toString(), "onmouseover");
sb = new StringBuffer("document.forms[0]['");
sb.append(getName(context, area));
sb.append("'].value='");
sb.append(iarea.getAlt());
sb.append("'; document.forms[0].submit()");
writer.writeAttribute("onclick", sb.toString(), "value");
writer.endElement("area");
By submitting the page, this code causes the JavaServer Faces lifecycle to return back
to the Restore View phase. This phase saves any state information, including the value
of the hidden field, so that a new request component tree is constructed. This value is
retrieved by the decode method of the MapComponent class. This decode method is
called by the JavaServer Faces implementation during the Apply Request Values
phase, which follows the Restore View phase.
In addition to the encodeEnd method, AreaRenderer contains an empty constructor.
This is used to create an instance of AreaRenderer so that it can be added to the render
kit.
The @FacesRenderer annotation registers the renderer class with the JavaServer Faces
implementation as a renderer class. The annotation identifies the component family as
well as the renderer type.
15.5.2 Identifying the Renderer Type
During the Render Response phase, the JavaServer Faces implementation calls the
getRendererType method of the component's tag handler to determine which renderer
to invoke, if there is one.
You identify the type associated with the renderer in the rendererType element of the
@FacesRenderer annotation for AreaRenderer as well as in the renderer-type element
of the tag library descriptor.
15.6 Implementing an Event Listener
The JavaServer Faces technology supports action events and value-change events for
components.
Action events occur when the user activates a component that implements
javax.faces.component.ActionSource. These events are represented by the class
javax.faces.event.ActionEvent.
15-18 The Java EE 7 Tutorial
Implementing an Event Listener
Value-change events occur when the user changes the value of a component that
implements javax.faces.component.EditableValueHolder. These events are
represented by the class javax.faces.event.ValueChangeEvent.
One way to handle events is to implement the appropriate listener classes. Listener
classes that handle the action events in an application must implement the interface
javax.faces.event.ActionListener. Similarly, listeners that handle the value-change
events must implement the interface javax.faces.event.ValueChangeListener.
This section explains how to implement the two listener classes.
To handle events generated by custom components, you must implement an event
listener and an event handler and manually queue the event on the component. See
Handling Events for Custom Components for more information.
Note: You do not need to create an ActionListener
implementation to handle an event that results solely in navigating
to a page and does not perform any other application-specific
processing. See Writing a Method to Handle Navigation for
information on how to manage page navigation.
15.6.1 Implementing Value-Change Listeners
A javax.faces.event.ValueChangeListener implementation must include a
processValueChange(ValueChangeEvent) method. This method processes the
specified value-change event and is invoked by the JavaServer Faces implementation
when the value-change event occurs. The ValueChangeEvent instance stores the old
and the new values of the component that fired the event.
In the Duke's Bookstore case study, the NameChanged listener implementation is
registered on the name UIInput component on the bookcashier.xhtml page. This
listener stores into session scope the name the user entered in the field corresponding
to the name component.
The bookreceipt.xhtml subsequently retrieves the name from the session scope:
<h:outputFormat title="thanks"
value="#{bundle.ThankYouParam}">
<f:param value="#{sessionScope.name}"/>
</h:outputFormat>
When the bookreceipt.xhtml page is loaded, it displays the name inside the message:
"Thank you, {0}, for purchasing your books from us."
Here is part of the NameChanged listener implementation:
public class NameChanged extends Object implements ValueChangeListener {
@Override
public void processValueChange(ValueChangeEvent event)
throws AbortProcessingException {
if (null != event.getNewValue()) {
FacesContext.getCurrentInstance().getExternalContext().
getSessionMap().put("name", event.getNewValue());
}
}
}
Creating Custom UI Components and Other Custom Objects
15-19
Handling Events for Custom Components
When the user enters the name in the field, a value-change event is generated, and the
processValueChange(ValueChangeEvent) method of the NameChanged listener
implementation is invoked. This method first gets the ID of the component that fired
the event from the ValueChangeEvent object, and it puts the value, along with an
attribute name, into the session map of the FacesContext instance.
Registering a Value-Change Listener on a Component explains how to register this
listener onto a component.
15.6.2 Implementing Action Listeners
A javax.faces.event.ActionListener implementation must include a
processAction(ActionEvent) method. The processAction(ActionEvent) method
processes the specified action event. The JavaServer Faces implementation invokes the
processAction(ActionEvent) method when the ActionEvent occurs.
The Duke's Bookstore case study uses two ActionListener implementations,
LinkBookChangeListener and MapBookChangeListener. See Handling Events for
Custom Components for details on MapBookChangeListener.
Registering an Action Listener on a Component explains how to register this listener
onto a component.
15.7 Handling Events for Custom Components
As explained in Implementing an Event Listener, events are automatically queued on
standard components that fire events. A custom component, on the other hand, must
manually queue events from its decode method if it fires events.
Performing Decoding explains how to queue an event on MapComponent using its
decode method. This section explains how to write the class that represents the event
of clicking on the map and how to write the method that processes this event.
As explained in Understanding the Facelets Page, the actionListener attribute of the
bookstore:map tag points to the MapBookChangeListener class. The listener class's
processAction method processes the event of clicking the image map. Here is the
processAction method:
@Override
public void processAction(ActionEvent actionEvent)
throws AbortProcessingException {
AreaSelectedEvent event = (AreaSelectedEvent) actionEvent;
String current = event.getMapComponent().getCurrent();
FacesContext context = FacesContext.getCurrentInstance();
String bookId = books.get(current);
context.getExternalContext().getSessionMap().put("bookId", bookId);
}
When the JavaServer Faces implementation calls this method, it passes in an
ActionEvent object that represents the event generated by clicking on the image map.
Next, it casts it to an AreaSelectedEvent object (see
tut-install/examples/case-studies/dukes-bookstore/src/java/dukesbookstore/lis
teners/AreaSelectedEvent.java). Then this method gets the MapComponent
associated with the event. Next, it gets the value of the MapComponent object's current
attribute, which indicates the currently selected area. The method then uses the value
of the current attribute to get the book's ID value from a HashMap object, which is
constructed elsewhere in the MapBookChangeListener class. Finally, the method places
the ID obtained from the HashMap object into the session map for the application.
15-20 The Java EE 7 Tutorial
Defining the Custom Component Tag in a Tag Library Descriptor
In addition to the method that processes the event, you need the event class itself. This
class is very simple to write; you have it extend ActionEvent and provide a
constructor that takes the component on which the event is queued and a method that
returns the component. Here is the AreaSelectedEvent class used with the image map:
public class AreaSelectedEvent extends ActionEvent {
public AreaSelectedEvent(MapComponent map) {
super(map);
}
public MapComponent getMapComponent() {
return ((MapComponent) getComponent());
}
}
As explained in the section Creating Custom Component Classes, in order for
MapComponent to fire events in the first place, it must implement ActionSource.
Because MapComponent extends UICommand, it also implements ActionSource.
15.8 Defining the Custom Component Tag in a Tag Library Descriptor
To use a custom tag, you declare it in a Tag Library Descriptor (TLD). The TLD file
defines how the custom tag is used in a JavaServer Faces page. The web container uses
the TLD to validate the tag. The set of tags that are part of the HTML render kit are
defined in the HTML_BASIC TLD, available at
http://docs.oracle.com/javaee/7/javaserverfaces/2.2/renderkitdoc
s/.
The TLD file name must end with taglib.xml. In the Duke's Bookstore case study, the
custom tags area and map are defined in the file web/WEB-INF/bookstore.taglib.xml.
All tag definitions must be nested inside the facelet-taglib element in the TLD. Each
tag is defined by a tag element. Here are the tag definitions for the area and map
components:
<facelet-taglib xmlns="http://xmlns.jcp.org/xml/ns/javaee"
...>
<namespace>http://dukesbookstore</namespace>
<tag>
<tag-name>area</tag-name>
<component>
<component-type>DemoArea</component-type>
<renderer-type>DemoArea</renderer-type>
</component>
</tag>
<tag>
<tag-name>map</tag-name>
<component>
<component-type>DemoMap</component-type>
<renderer-type>DemoMap</renderer-type>
</component>
</tag>
</facelet-taglib>
The component-type element specifies the name defined in the @FacesComponent
annotation, and the renderer-type element specifies the rendererType defined in the
@FacesRenderer annotation.
The facelet-taglib element must also include a namespace element, which defines
the namespace to be specified in pages that use the custom component. See Using a
Custom Component for information on specifying the namespace in pages.
Creating Custom UI Components and Other Custom Objects
15-21
Using a Custom Component
The TLD file is located in the WEB-INF directory. In addition, an entry is included in the
web deployment descriptor (web.xml) to identify the custom tag library descriptor file,
as follows:
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/bookstore.taglib.xml</param-value>
</context-param>
15.9 Using a Custom Component
To use a custom component in a page, you add the custom tag associated with the
component to the page.
As explained in Defining the Custom Component Tag in a Tag Library Descriptor, you
must ensure that the TLD that defines any custom tags is packaged in the application
if you intend to use the tags in your pages. TLD files are stored in the WEB-INF/
directory or subdirectory of the WAR file or in the META-INF/ directory or subdirectory
of a tag library packaged in a JAR file.
You also need to include a namespace declaration in the page so that the page has
access to the tags. The custom tags for the Duke's Bookstore case study are defined in
bookstore.taglib.xml. The ui:composition tag on the index.xhtml page declares the
namespace defined in the tag library:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:bookstore="http://dukesbookstore"
template="./bookstoreTemplate.xhtml">
Finally, to use a custom component in a page, you add the component's tag to the
page.
The Duke's Bookstore case study includes a custom image map component on the
index.xhtml page. This component allows you to select a book by clicking on a region
of the image map:
...
<h:graphicImage id="mapImage"
name="book_all.jpg"
library="images
alt="#{bundle.chooseLocale}"
usemap="#bookMap" />
<bookstore:map id="bookMap"
current="map1"
immediate="true"
action="bookstore">
<f:actionListener
type="javaeetutorial.dukesbookstore.listeners.MapBookChangeListener" />
<bookstore:area id="map1" value="#{Book201}"
onmouseover="resources/images/book_201.jpg"
onmouseout="resources/images/book_all.jpg"
targetImage="mapImage" />
...
<bookstore:area id="map6" value="#{Book207}"
onmouseover="resources/images/book_207.jpg"
onmouseout="resources/images//book_all.jpg"
targetImage="mapImage" />
</bookstore:map>
15-22 The Java EE 7 Tutorial
Creating and Using a Custom Converter
The standard h:graphicImage tag associates an image (book_all.jpg) with an image
map that is referenced in the usemap attribute value.
The custom bookstore:map tag that represents the custom component, MapComponent,
specifies the image map and contains a set of bookstore:area tags. Each custom
bookstore:area tag represents a custom AreaComponent and specifies a region of the
image map.
On the page, the onmouseover and onmouseout attributes specify the image that is
displayed when the user performs the actions described by the attributes. The custom
renderer also renders an onclick attribute.
In the rendered HTML page, the onmouseover, onmouseout, and onclick attributes
define which JavaScript code is executed when these events occur. When the user
moves the mouse over a region, the onmouseover function associated with the region
displays the map with that region highlighted. When the user moves the mouse out of
a region, the onmouseout function redisplays the original image. When the user clicks a
region, the onclick function sets the value of a hidden input tag to the ID of the
selected area and submits the page.
When the custom renderer renders these attributes in HTML, it also renders the
JavaScript code. The custom renderer also renders the entire onclick attribute rather
than letting the page author set it.
The custom renderer that renders the HTML map tag also renders a hidden input
component that holds the current area. The server-side objects retrieve the value of the
hidden input field and set the locale in the FacesContext instance according to which
region was selected.
15.10 Creating and Using a Custom Converter
A JavaServer Faces converter class converts strings to objects and objects to strings as
required. Several standard converters are provided by JavaServer Faces for this
purpose. See Using the Standard Converters for more information on these included
converters.
As explained in Conversion Model, if the standard converters included with
JavaServer Faces cannot perform the data conversion that you need, you can create a
custom converter to perform this specialized conversion. This implementation, at a
minimum, must define how to convert data both ways between the two views of the
data described in Conversion Model.
All custom converters must implement the javax.faces.convert.Converter
interface. This section explains how to implement this interface to perform a custom
data conversion.
The Duke's Bookstore case study uses a custom Converter implementation, located in
tut-install/examples/case-studies/dukes-bookstore/src/java/dukesbookstore/con
verters/CreditCardConverter.java, to convert the data entered in the Credit Card
Number field on the bookcashier.xhtml page. It strips blanks and hyphens from the
text string and formats it so that a blank space separates every four characters.
Another common use case for a custom converter is in a list for a nonstandard object
type. In the Duke's Tutoring case study, the Student and Guardian entities require a
custom converter so that they can be converted to and from a UISelectItems input
component.
Creating Custom UI Components and Other Custom Objects
15-23
Creating and Using a Custom Converter
15.10.1 Creating a Custom Converter
The CreditCardConverter custom converter class is created as follows:
@FacesConverter("ccno")
public class CreditCardConverter implements Converter {
...
}
The @FacesConverter annotation registers the custom converter class as a converter
with the name of ccno with the JavaServer Faces implementation. Alternatively, you
can register the converter with entries in the application configuration resource file, as
shown in Registering a Custom Converter.
To define how the data is converted from the presentation view to the model view, the
Converter implementation must implement the getAsObject(FacesContext,
UIComponent, String) method from the Converter interface. Here is the
implementation of this method from CreditCardConverter:
@Override
public Object getAsObject(FacesContext context,
UIComponent component, String newValue)
throws ConverterException {
if (newValue.isEmpty()) {
return null;
}
// Since this is only a String to String conversion,
// this conversion does not throw ConverterException.
String convertedValue = newValue.trim();
if ( (convertedValue.contains("-")) || (convertedValue.contains(" "))) {
char[] input = convertedValue.toCharArray();
StringBuilder builder = new StringBuilder(input.length);
for (int i = 0; i < input.length; ++i) {
if ((input[i] == '-') || (input[i] == ' ')) {
} else {
builder.append(input[i]);
}
}
convertedValue = builder.toString();
}
return convertedValue;
}
During the Apply Request Values phase, when the components' decode methods are
processed, the JavaServer Faces implementation looks up the component's local value
in the request and calls the getAsObject method. When calling this method, the
JavaServer Faces implementation passes in the current FacesContext instance, the
component whose data needs conversion, and the local value as a String. The method
then writes the local value to a character array, trims the hyphens and blanks, adds the
rest of the characters to a String, and returns the String.
To define how the data is converted from the model view to the presentation view, the
Converter implementation must implement the getAsString(FacesContext,
UIComponent, Object) method from the Converter interface. Here is an
implementation of this method:
@Override
public String getAsString(FacesContext context,
UIComponent component, Object value)
15-24 The Java EE 7 Tutorial
Creating and Using a Custom Converter
throws ConverterException {
String inputVal = null;
if ( value == null ) {
return "";
}
// value must be of a type that can be cast to a String.
try {
inputVal = (String)value;
} catch (ClassCastException ce) {
FacesMessage errMsg = new FacesMessage(CONVERSION_ERROR_MESSAGE_ID);
FacesContext.getCurrentInstance().addMessage(null, errMsg);
throw new ConverterException(errMsg.getSummary());
}
// insert spaces after every four characters for better
// readability if they are not already present.
char[] input = inputVal.toCharArray();
StringBuilder builder = new StringBuilder(input.length + 3);
for (int i = 0; i < input.length; ++i) {
if ((i % 4) == 0 && (i != 0)) {
if ({input[i] != ' ') || (input[i] != '-')){
builder.append(" ");
// if there are any "-"'s convert them to blanks.
} else if (input[i] == '-') {
builder.append(" ");
}
}
builder.append(input[i]);
}
String convertedValue = builder.toString();
return convertedValue;
}
During the Render Response phase, in which the components' encode methods are
called, the JavaServer Faces implementation calls the getAsString method in order to
generate the appropriate output. When the JavaServer Faces implementation calls this
method, it passes in the current FacesContext, the UIComponent whose value needs to
be converted, and the bean value to be converted. Because this converter does a
String-to-String conversion, this method can cast the bean value to a String.
If the value cannot be converted to a String, the method throws an exception, passing
an error message from the resource bundle that is registered with the application.
Registering Application Messages explains how to register custom error messages
with the application.
If the value can be converted to a String, the method reads the String to a character
array and loops through the array, adding a space after every four characters.
You can also create a custom converter with a @FacesConverter annotation that
specifies the forClass attribute, as shown in the following example from the Duke's
Tutoring case study:
@FacesConverter(forClass=Guardian.class, value="guardian")
public class GuardianConverter extends EntityConverter implements Converter { ...
The forClass attribute registers the converter as the default converter for the Guardian
class. Therefore, whenever that class is specified by a value attribute of an input
component, the converter is invoked automatically.
A converter class can be a separate Java POJO class, as in the Duke's Bookstore case
study. If it needs to access objects defined in a managed bean class, however, it can be a
Creating Custom UI Components and Other Custom Objects
15-25
Creating and Using a Custom Converter
subclass of a JavaServer Faces managed bean, as in the address-book persistence
example, in which the converters use an enterprise bean that is injected into the
managed bean class.
15.10.2 Using a Custom Converter
To apply the data conversion performed by a custom converter to a particular
component's value, you must do one of the following.
■
■
Reference the converter from the component tag's converter attribute.
Nest an f:converter tag inside the component's tag and reference the custom
converter from one of the f:converter tag's attributes.
If you are using the component tag's converter attribute, this attribute must reference
the Converter implementation's identifier or the fully-qualified class name of the
converter. Creating and Using a Custom Converter explains how to implement a
custom converter.
The identifier for the credit card converter class is ccno, the value specified in the
@FacesConverter annotation:
@FacesConverter("ccno")
public class CreditCardConverter implements Converter {
...
Therefore, the CreditCardConverter instance can be registered on the ccno component
as shown in the following example:
<h:inputText id="ccno"
size="19"
converter="ccno"
value="#{cashierBean.creditCardNumber}"
required="true"
requiredMessage="#{bundle.ReqCreditCard}">
...
</h:inputText>
By setting the converter attribute of a component's tag to the converter's identifier or
its class name, you cause that component's local value to be automatically converted
according to the rules specified in the Converter implementation.
Instead of referencing the converter from the component tag's converter attribute, you
can reference the converter from an f:converter tag nested inside the component's
tag. To reference the custom converter using the f:converter tag, you do one of the
following.
■
Set the f:converter tag's converterId attribute to the Converter
implementation's identifier defined in the @FacesConverter annotation or in the
application configuration resource file. This method is shown in
bookcashier.xhtml:
<h:inputText id="ccno"
size="19"
value="#{cashierBean.creditCardNumber}"
required="true"
requiredMessage="#{bundle.ReqCreditCard}">
<f:converter converterId="ccno"/>
<f:validateRegex
pattern="\d{16}|\d{4} \d{4} \d{4} \d{4}|\d{4}-\d{4}-\d{4}-\d{4}"/>
</h:inputText>
15-26 The Java EE 7 Tutorial
Creating and Using a Custom Validator
■
Bind the Converter implementation to a managed bean property using the
f:converter tag's binding attribute, as described in Binding Converters, Listeners,
and Validators to Managed Bean Properties.
The JavaServer Faces implementation calls the converter's getAsObject method to
strip spaces and hyphens from the input value. The getAsString method is called
when the bookcashier.xhtml page is redisplayed; this happens if the user orders more
than $100 worth of books.
In the Duke's Tutoring case study, each converter is registered as the converter for a
particular class. The converter is automatically invoked whenever that class is
specified by a value attribute of an input component. In the following example, the
itemValue attribute (highlighted in bold) calls the converter for the Guardian class:
<h:selectManyListbox id="selectGuardiansMenu"
title="#{bundle['action.add.guardian']}"
value="#{guardianManager.selectedGuardians}"
size="5"
converter="guardian">
<f:selectItems value="#{guardianManager.allGuardians}"
var="selectedGuardian"
itemLabel="#{selectedGuardian.name}"
itemValue="#{selectedGuardian}" />
</h:selectManyListbox>
15.11 Creating and Using a Custom Validator
If the standard validators or Bean Validation don't perform the validation checking
you need, you can create a custom validator to validate user input. As explained in
Validation Model, there are two ways to implement validation code.
■
■
Implement a managed bean method that performs the validation.
Provide an implementation of the javax.faces.validator.Validator interface to
perform the validation.
Writing a Method to Perform Validation explains how to implement a managed bean
method to perform validation. The rest of this section explains how to implement the
Validator interface.
If you choose to implement the Validator interface and you want to allow the page
author to configure the validator's attributes from the page, you also must specify a
custom tag for registering the validator on a component.
If you prefer to configure the attributes in the Validator implementation, you can
forgo specifying a custom tag and instead let the page author register the validator on
a component using the f:validator tag, as described in Using a Custom Validator.
You can also create a managed bean property that accepts and returns the Validator
implementation you create, as described in Writing Properties Bound to Converters,
Listeners, or Validators. You can use the f:validator tag's binding attribute to bind
the Validator implementation to the managed bean property.
Usually, you will want to display an error message when data fails validation. You
need to store these error messages in a resource bundle.
After creating the resource bundle, you have two ways to make the messages available
to the application. You can queue the error messages onto the FacesContext
programmatically, or you can register the error messages in the application
configuration resource file, as explained in Registering Application Messages.
Creating Custom UI Components and Other Custom Objects
15-27
Creating and Using a Custom Validator
For example, an e-commerce application might use a general-purpose custom
validator called FormatValidator.java to validate input data against a format pattern
that is specified in the custom validator tag. This validator would be used with a
Credit Card Number field on a Facelets page. Here is the custom validator tag:
<mystore:formatValidator
formatPatterns="9999999999999999|9999 9999 9999 9999|9999-9999-9999-9999"/>
According to this validator, the data entered in the field must be one of the following:
■
A 16-digit number with no spaces
■
A 16-digit number with a space between every four digits
■
A 16-digit number with hyphens between every four digits
The f:validateRegex tag makes a custom validator unnecessary in this situation.
However, the rest of this section describes how this validator would be implemented
and how to specify a custom tag so that the page author could register the validator on
a component.
15.11.1 Implementing the Validator Interface
A Validator implementation must contain a constructor, a set of accessor methods for
any attributes on the tag, and a validate method, which overrides the validate
method of the Validator interface.
The hypothetical FormatValidator class also defines accessor methods for setting the
formatPatterns attribute, which specifies the acceptable format patterns for input into
the fields. The setter method calls the parseFormatPatterns method, which separates
the components of the pattern string into a string array, formatPatternsList.
public String getFormatPatterns() {
return (this.formatPatterns);
}
public void setFormatPatterns(String formatPatterns) {
this.formatPatterns = formatPatterns;
parseFormatPatterns();
}
In addition to defining accessor methods for the attributes, the class overrides the
validate method of the Validator interface. This method validates the input and also
accesses the custom error messages to be displayed when the String is invalid.
The validate method performs the actual validation of the data. It takes the
FacesContext instance, the component whose data needs to be validated, and the
value that needs to be validated. A validator can validate only data of a component
that implements javax.faces.component.EditableValueHolder.
Here is an implementation of the validate method:
@FacesValidator
public class FormatValidator implements Validator, StateHolder {
...
public void validate(FacesContext context, UIComponent component,
Object toValidate) {
boolean valid = false;
String value = null;
if ((context == null) || (component == null)) {
throw new NullPointerException();
}
15-28 The Java EE 7 Tutorial
Creating and Using a Custom Validator
if (!(component instanceof UIInput)) {
return;
}
if ( null == formatPatternsList || null == toValidate) {
return;
}
value = toValidate.toString();
// validate the value against the list of valid patterns.
Iterator patternIt = formatPatternsList.iterator();
while (patternIt.hasNext()) {
valid = isFormatValid(
((String)patternIt.next()), value);
if (valid) {
break;
}
}
if ( !valid ) {
FacesMessage errMsg =
new FacesMessage(FORMAT_INVALID_MESSAGE_ID);
FacesContext.getCurrentInstance().addMessage(null, errMsg);
throw new ValidatorException(errMsg);
}
}
}
The @FacesValidator annotation registers the FormatValidator class as a validator
with the JavaServer Faces implementation. The validate method gets the local value
of the component and converts it to a String. It then iterates over the
formatPatternsList list, which is the list of acceptable patterns that was parsed from
the formatPatterns attribute of the custom validator tag.
While iterating over the list, this method checks the pattern of the component's local
value against the patterns in the list. If the pattern of the local value does not match
any pattern in the list, this method generates an error message. It then creates a
javax.faces.application.FacesMessage and queues it on the FacesContext for
display, using a String that represents the key in the Properties file:
public static final String FORMAT_INVALID_MESSAGE_ID =
"FormatInvalid";
}
Finally, the method passes the message to the constructor of
javax.faces.validator.ValidatorException.
When the error message is displayed, the format pattern will be substituted for the {0}
in the error message, which, in English, is as follows:
Input must match one of the following patterns: {0}
You may wish to save and restore state for your validator, although state saving is not
usually necessary. To do so, you will need to implement the StateHolder interface as
well as the Validator interface. To implement StateHolder, you would need to
implement its four methods: saveState(FacesContext),
restoreState(FacesContext, Object), isTransient, and setTransient(boolean).
See Saving and Restoring State for more information.
15.11.2 Specifying a Custom Tag
If you implemented a Validator interface rather than implementing a managed bean
method that performs the validation, you need to do one of the following.
Creating Custom UI Components and Other Custom Objects
15-29
Creating and Using a Custom Validator
■
■
Allow the page author to specify the Validator implementation to use with the
f:validator tag. In this case, the Validator implementation must define its own
properties. Using a Custom Validator explains how to use the f:validator tag.
Specify a custom tag that provides attributes for configuring the properties of the
validator from the page.
To create a custom tag, you need to add the tag to the tag library descriptor for the
application, bookstore.taglib.xml:
<tag>
<tag-name>validator</tag-name>
<validator>
<validator-id>formatValidator</validator-id>
<validator-class>
dukesbookstore.validators.FormatValidator
</validator-class>
</validator>
</tag>
The tag-name element defines the name of the tag as it must be used in a Facelets
page. The validator-id element identifies the custom validator. The validator-class
element wires the custom tag to its implementation class.
Using a Custom Validator explains how to use the custom validator tag on the page.
15.11.3 Using a Custom Validator
To register a custom validator on a component, you must do one of the following.
■
■
Nest the validator's custom tag inside the tag of the component whose value you
want to be validated.
Nest the standard f:validator tag within the tag of the component and reference
the custom Validator implementation from the f:validator tag.
Here is a hypothetical custom formatValidator tag for the Credit Card Number field,
nested within the h:inputText tag:
<h:inputText id="ccno" size="19"
...
required="true">
<mystore:formatValidator
formatPatterns="9999999999999999|9999 9999 9999 9999|9999-9999-9999-9999"/>
</h:inputText>
<h:message styleClass="validationMessage" for="ccno"/>
This tag validates the input of the ccno field against the patterns defined by the page
author in the formatPatterns attribute.
You can use the same custom validator for any similar component by simply nesting
the custom validator tag within the component tag.
If the application developer who created the custom validator prefers to configure the
attributes in the Validator implementation rather than allow the page author to
configure the attributes from the page, the developer will not create a custom tag for
use with the validator.
In this case, the page author must nest the f:validator tag inside the tag of the
component whose data needs to be validated. Then the page author needs to do one of
the following.
15-30 The Java EE 7 Tutorial
Binding Component Values and Instances to Managed Bean Properties
■
■
Set the f:validator tag's validatorId attribute to the ID of the validator that is
defined in the application configuration resource file.
Bind the custom Validator implementation to a managed bean property using the
f:validator tag's binding attribute, as described in Binding Converters, Listeners,
and Validators to Managed Bean Properties.
The following tag registers a hypothetical validator on a component using an
f:validator tag and references the ID of the validator:
<h:inputText id="name" value="#{CustomerBean.name}"
size="10" ...>
<f:validator validatorId="customValidator" />
...
</h:inputText>
15.12 Binding Component Values and Instances to Managed Bean
Properties
A component tag can wire its data to a managed bean by one of the following
methods:
■
Binding its component's value to a bean property
■
Binding its component's instance to a bean property
To bind a component's value to a managed bean property, a component tag's value
attribute uses an EL value expression. To bind a component instance to a bean
property, a component tag's binding attribute uses a value expression.
When a component instance is bound to a managed bean property, the property holds
the component's local value. Conversely, when a component's value is bound to a
managed bean property, the property holds the value stored in the managed bean.
This value is updated with the local value during the Update Model Values phase of
the lifecycle. There are advantages to both of these methods.
Binding a component instance to a bean property has the following advantages.
■
■
The managed bean can programmatically modify component attributes.
The managed bean can instantiate components rather than let the page author do
so.
Binding a component's value to a bean property has the following advantages.
■
■
■
The page author has more control over the component attributes.
The managed bean has no dependencies on the JavaServer Faces API (such as the
component classes), allowing for greater separation of the presentation layer from
the model layer.
The JavaServer Faces implementation can perform conversions on the data based
on the type of the bean property without the developer needing to apply a
converter.
In most situations, you will bind a component's value rather than its instance to a bean
property. You'll need to use a component binding only when you need to change one
of the component's attributes dynamically. For example, if an application renders a
component only under certain conditions, it can set the component's rendered
property accordingly by accessing the property to which the component is bound.
Creating Custom UI Components and Other Custom Objects
15-31
Binding Component Values and Instances to Managed Bean Properties
When referencing the property using the component tag's value attribute, you need to
use the proper syntax. For example, suppose a managed bean called MyBean has this
int property:
protected int currentOption = null;
public int getCurrentOption(){...}
public void setCurrentOption(int option){...}
The value attribute that references this property must have this value-binding
expression:
#{myBean.currentOption}
In addition to binding a component's value to a bean property, the value attribute can
specify a literal value or can map the component's data to any primitive (such as int),
structure (such as an array), or collection (such as a list), independent of a JavaBeans
component. Table 15–3 lists some example value-binding expressions that you can use
with the value attribute.
Table 15–3
Examples of Value-Binding Expressions
Value
Expression
A Boolean
cart.numberOfItems> 0
A property initialized from a context initialization initParam.quantity
parameter
A bean property
cashierBean.name
A value in an array
books[3]
A value in a collection
books["fiction"]
A property of an object in an array of objects
books[3].price
The next two sections explain how to use the value attribute to bind a component's
value to a bean property or other data objects and how to use the binding attribute to
bind a component instance to a bean property.
15.12.1 Binding a Component Value to a Property
To bind a component's value to a managed bean property, you specify the name of the
bean and the property using the value attribute.
This means that the first part of the EL value expression must match the name of the
managed bean up to the first period (.) and the part of the value expression after the
period must match the property of the managed bean.
For example, in the Duke's Bookstore case study, the h:dataTable tag in
bookcatalog.xhtml sets the value of the component to the value of the books property
of the BookstoreBean backing bean, whose name is store:
<h:dataTable id="books"
value="#{store.books}"
var="book"
headerClass="list-header"
styleClass="list-background"
rowClasses="list-row-even, list-row-odd"
border="1"
summary="#{bundle.BookCatalog}">
15-32 The Java EE 7 Tutorial
Binding Component Values and Instances to Managed Bean Properties
The value is obtained by calling the backing bean's getBooks method, which in turn
calls the BookRequestBean session bean's getBooks method.
If you use the application configuration resource file to configure managed beans
instead of defining them in managed bean classes, the name of the bean in the value
expression must match the managed-bean-name element of the managed bean
declaration up to the first period (.) in the expression. Similarly, the part of the value
expression after the period must match the name specified in the corresponding
property-name element in the application configuration resource file.
For example, consider this managed bean configuration, which configures the
ImageArea bean corresponding to the top-left book in the image map on the
index.html page of the Duke's Bookstore case study:
<managed-bean eager="true">
...
<managed-bean-name>Book201</managed-bean-name>
<managed-bean-class>dukesbookstore.model.ImageArea</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<managed-property>
...
<property-name>shape</property-name>
<value>rect</value>
</managed-property>
<managed-property>
...
<property-name>alt</property-name>
<value>Duke</value>
</managed-property>
...
This example configures a bean called Book201, which has several properties, one of
which is called shape.
Although the bookstore:area tags on the index.xhtml page do not bind to an
ImageArea property (they bind to the bean itself), you could refer to the property using
a value expression from the value attribute of the component's tag:
<h:outputText value="#{Book201.shape}" />
See Configuring Managed Beans for information on how to configure beans in the
application configuration resource file.
15.12.2 Binding a Component Value to an Implicit Object
One external data source that a value attribute can refer to is an implicit object.
The bookreceipt.xhtml page of the Duke's Bookstore case study has a reference to an
implicit object:
<h:outputFormat title="thanks"
value="#{bundle.ThankYouParam}">
<f:param value="#{sessionScope.name}"/>
</h:outputFormat>
This tag gets the name of the customer from the session scope and inserts it into the
parameterized message at the key ThankYouParam from the resource bundle. For
example, if the name of the customer is Gwen Canigetit, this tag will render:
Thank you, Gwen Canigetit, for purchasing your books from us.
Creating Custom UI Components and Other Custom Objects
15-33
Binding Component Values and Instances to Managed Bean Properties
Retrieving values from other implicit objects is done in a similar way to the example
shown in this section. Table 15–4 lists the implicit objects to which a value attribute can
refer. All of the implicit objects, except for the scope objects, are read-only and
therefore should not be used as values for a UIInput component.
Table 15–4
Implicit Objects
Implicit Object
What It Is
applicationScope
A Map of the application scope attribute values, keyed by attribute name
cookie
A Map of the cookie values for the current request, keyed by cookie name
facesContext
The FacesContext instance for the current request
header
A Map of HTTP header values for the current request, keyed by header
name
headerValues
A Map of String arrays containing all the header values for HTTP headers
in the current request, keyed by header name
initParam
A Map of the context initialization parameters for this web application
param
A Map of the request parameters for this request, keyed by parameter
name
paramValues
A Map of String arrays containing all the parameter values for request
parameters in the current request, keyed by parameter name
requestScope
A Map of the request attributes for this request, keyed by attribute name
sessionScope
A Map of the session attributes for this request, keyed by attribute name
view
The root UIComponent in the current component tree stored in the
FacesRequest for this request
15.12.3 Binding a Component Instance to a Bean Property
A component instance can be bound to a bean property using a value expression with
the binding attribute of the component's tag. You usually bind a component instance
rather than its value to a bean property if the bean must dynamically change the
component's attributes.
Here are two tags from the bookcashier.xhtml page that bind components to bean
properties:
<h:selectBooleanCheckbox id="fanClub"
rendered="false"
binding="#{cashierBean.specialOffer}" />
<h:outputLabel for="fanClub"
rendered="false"
binding="#{cashierBean.specialOfferText}"
value="#{bundle.DukeFanClub}"/>
</h:outputLabel>
The h:selectBooleanCheckbox tag renders a check box and binds the fanClub
UISelectBoolean component to the specialOffer property of the cashier bean. The
h:outputLabel tag binds the component representing the check box's label to the
specialOfferText property of the cashier bean. If the application's locale is English,
the h:outputLabel tag renders
I'd like to join the Duke Fan Club, free with my purchase of over $100
The rendered attributes of both tags are set to false to prevent the check box and its
label from being rendered. If the customer makes a large order and clicks the Submit
15-34 The Java EE 7 Tutorial
Binding Converters, Listeners, and Validators to Managed Bean Properties
button, the submit method of CashierBean sets both components' rendered properties
to true, causing the check box and its label to be rendered.
These tags use component bindings rather than value bindings because the managed
bean must dynamically set the values of the components' rendered properties.
If the tags were to use value bindings instead of component bindings, the managed
bean would not have direct access to the components and would therefore require
additional code to access the components from the FacesContext instance to change
the components' rendered properties.
Writing Properties Bound to Component Instances explains how to write the bean
properties bound to the example components.
15.13 Binding Converters, Listeners, and Validators to Managed Bean
Properties
As described in Adding Components to a Page Using HTML Tag Library Tags, a page
author can bind converter, listener, and validator implementations to managed bean
properties using the binding attributes of the tags that are used to register the
implementations on components.
This technique has similar advantages to binding component instances to managed
bean properties, as described in Binding Component Values and Instances to Managed
Bean Properties. In particular, binding a converter, listener, or validator
implementation to a managed bean property yields the following benefits.
■
■
The managed bean can instantiate the implementation instead of allowing the
page author to do so.
The managed bean can programmatically modify the attributes of the
implementation. In the case of a custom implementation, the only other way to
modify the attributes outside of the implementation class would be to create a
custom tag for it and require the page author to set the attribute values from the
page.
Whether you are binding a converter, listener, or validator to a managed bean
property, the process is the same for any of the implementations.
■
■
■
Nest the converter, listener, or validator tag within an appropriate component tag.
Make sure that the managed bean has a property that accepts and returns the
converter, listener, or validator implementation class that you want to bind to the
property.
Reference the managed bean property using a value expression from the binding
attribute of the converter, listener, or validator tag.
For example, say that you want to bind the standard DateTime converter to a managed
bean property because you want to set the formatting pattern of the user's input in the
managed bean rather than on the Facelets page. First, the page registers the converter
onto the component by nesting the f:convertDateTime tag within the component tag.
Then, the page references the property with the binding attribute of the
f:convertDateTime tag:
<h:inputText value="#{loginBean.birthDate}">
<f:convertDateTime binding="#{loginBean.convertDate}" />
</h:inputText>
The convertDate property would look something like this:
Creating Custom UI Components and Other Custom Objects
15-35
Binding Converters, Listeners, and Validators to Managed Bean Properties
private DateTimeConverter convertDate;
public DateTimeConverter getConvertDate() {
...
return convertDate;
}
public void setConvertDate(DateTimeConverter convertDate) {
convertDate.setPattern("EEEEEEEE, MMM dd, yyyy");
this.convertDate = convertDate;
}
See Writing Properties Bound to Converters, Listeners, or Validators for more
information on writing managed bean properties for converter, listener, and validator
implementations.
15-36 The Java EE 7 Tutorial
16
Configuring JavaServer Faces Applications
16
The process of building and deploying simple JavaServer Faces applications is
described in earlier chapters of this tutorial, including Chapter 6, "Getting Started with
Web Applications," Chapter 8, "Introduction to Facelets," Chapter 13, "Using Ajax with
JavaServer Faces Technology," and Chapter 14, "Composite Components: Advanced
Topics and an Example." When you create large and complex applications, however,
various additional configuration tasks are required. These tasks include the following:
■
■
■
■
Registering managed beans with the application so that all parts of the application
have access to them
Configuring managed beans and model beans so that they are instantiated with
the proper values when a page makes reference to them
Defining navigation rules for each of the pages in the application so that the
application has a smooth page flow, if nondefault navigation is needed
Packaging the application to include all the pages, resources, and other files so that
the application can be deployed on any compliant container
The following topics are addressed here:
■
Using Annotations to Configure Managed Beans
■
Application Configuration Resource File
■
Using Faces Flows
■
Configuring Managed Beans
■
Registering Application Messages
■
Using Default Validators
■
Registering a Custom Validator
■
Registering a Custom Converter
■
Configuring Navigation Rules
■
Registering a Custom Renderer with a Render Kit
■
Registering a Custom Component
■
Basic Requirements of a JavaServer Faces Application
16.1 Using Annotations to Configure Managed Beans
JavaServer Faces support for bean annotations is introduced in Chapter 7, "JavaServer
Faces Technology". Bean annotations can be used for configuring JavaServer Faces
applications.
Configuring JavaServer Faces Applications 16-1
Using Annotations to Configure Managed Beans
The @Named (javax.inject.Named) annotation in a class, along with a scope
annotation, automatically registers that class as a resource with the JavaServer Faces
implementation. A bean that uses these annotations is a CDI managed bean.
The following shows the use of the @Named and @SessionScoped annotations in a class:
@Named("cart")
@SessionScoped
public class ShoppingCart ... { ... }
The above code snippet shows a bean that is managed by the JavaServer Faces
implementation and is available for the length of the session.
You can annotate beans with any of the scopes listed in the next section, Using
Managed Bean Scopes.
All classes will be scanned for annotations at startup unless the faces-config element
in the faces-config.xml file has the metadata-complete attribute set to true.
Annotations are also available for other artifacts, such as components, converters,
validators, and renderers, to be used in place of application configuration resource file
entries. These are discussed, along with registration of custom listeners, custom
validators, and custom converters, in Chapter 15, "Creating Custom UI Components
and Other Custom Objects".
16.1.1 Using Managed Bean Scopes
You can use annotations to define the scope in which the bean will be stored. You can
specify one of the following scopes for a bean class.
■
■
■
■
■
Application (javax.enterprise.context.ApplicationScoped): Application scope
persists across all users' interactions with a web application.
Session (javax.enterprise.context.SessionScoped): Session scope persists
across multiple HTTP requests in a web application.
Flow (javax.faces.flows.FlowScoped): Flow scope persists during a user's
interaction with a specific flow of a web application. See Using Faces Flows for
more information.
Request (javax.enterprise.context.RequestScoped): Request scope persists
during a single HTTP request in a web application.
Dependent (javax.enterprise.context.Dependent): Indicates that the bean
depends on some other bean.
You may want to use @Dependent when a managed bean references another managed
bean. The second bean should not be in a scope (@Dependent) if it is supposed to be
created only when it is referenced. If you define a bean as @Dependent, the bean is
instantiated anew each time it is referenced, so it does not get saved in any scope.
If your managed bean is referenced by the binding attribute of a component tag, you
should define the bean with a request scope. If you placed the bean in session or
application scope instead, the bean would need to take precautions to ensure thread
safety, because javax.faces.component.UIComponent instances each depend on
running inside of a single thread.
If you are configuring a bean that allows attributes to be associated with the view, you
can use the view scope. The attributes persist until the user has navigated to the next
view.
16-2 The Java EE 7 Tutorial
Application Configuration Resource File
16.2 Application Configuration Resource File
JavaServer Faces technology provides a portable configuration format (as an XML
document) for configuring application resources. One or more XML documents, called
application configuration resource files, may use this format to register and configure
objects and resources and to define navigation rules for applications. An application
configuration resource file is usually named faces-config.xml.
You need an application configuration resource file in the following cases:
■
■
To specify configuration elements for your application that are not available
through managed bean annotations, such as localized messages and navigation
rules
To override managed bean annotations when the application is deployed
The application configuration resource file must be valid against the XML schema
located at http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_
2.xsd.
In addition, each file must include the following information, in the following order:
■
The XML version number, usually with an encoding attribute:
<?xml version="1.0" encoding='UTF-8'?>
■
A faces-config tag enclosing all the other declarations:
<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
...
</faces-config>
You can have more than one application configuration resource file for an application.
The JavaServer Faces implementation finds the configuration file or files by looking for
the following.
■
■
■
A resource named /META-INF/faces-config.xml in any of the JAR files in the web
application's /WEB-INF/lib/ directory and in parent class loaders. If a resource
with this name exists, it is loaded as a configuration resource. This method is
practical for a packaged library containing some components and renderers. In
addition, any file with a name that ends in faces-config.xml is also considered a
configuration resource and is loaded as such.
A context initialization parameter, javax.faces.application.CONFIG_FILES, in
your web deployment descriptor file that specifies one or more (comma-delimited)
paths to multiple configuration files for your web application. This method is most
often used for enterprise-scale applications that delegate to separate groups the
responsibility for maintaining the file for each portion of a big application.
A resource named faces-config.xml in the /WEB-INF/ directory of your
application. Simple web applications make their configuration files available in
this way.
To access the resources registered with the application, an application developer can
use an instance of the javax.faces.application.Application class, which is
automatically created for each application. The Application instance acts as a
centralized factory for resources that are defined in the XML file.
Configuring JavaServer Faces Applications 16-3
Application Configuration Resource File
When an application starts up, the JavaServer Faces implementation creates a single
instance of the Application class and configures it with the information you provided
in the application configuration resource file.
16.2.1 Configuring Eager Application-Scoped Managed Beans
JavaServer Faces managed beans (either specified in the faces-config.xml file or
annotated with javax.faces.bean.ManagedBean) are lazily instantiated. That is, that
they are instantiated when a request is made from the application.
To force an application-scoped bean to be instantiated and placed in the application
scope as soon as the application is started and before any request is made, the eager
attribute of the managed bean should be set to true, as shown in the following
examples.
The faces-config.xml file declaration is as follows:
<managed-bean eager="true">
The annotation is as follows:
@ManagedBean(eager=true)
@ApplicationScoped
16.2.2 Ordering of Application Configuration Resource Files
Because JavaServer Faces technology allows the use of multiple application
configuration resource files stored in different locations, the order in which they are
loaded by the implementation becomes important in certain situations (for example,
when using application-level objects). This order can be defined through an ordering
element and its subelements in the application configuration resource file itself. The
ordering of application configuration resource files can be absolute or relative.
Absolute ordering is defined by an absolute-ordering element in the file. With
absolute ordering, the user specifies the order in which application configuration
resource files will be loaded. The following example shows an entry for absolute
ordering.
File my-faces-config.xml contains the following elements:
<faces-config>
<name>myJSF</name>
<absolute-ordering>
<name>A</name>
<name>B</name>
<name>C</name>
</absolute-ordering>
</faces-config>
In this example, A, B, and C are different application configuration resource files and
are to be loaded in the listed order.
If there is an absolute-ordering element in the file, only the files listed by the
subelement name are processed. To process any other application configuration
resource files, an others subelement is required. In the absence of the others
subelement, all other unlisted files will be ignored at load time.
Relative ordering is defined by an ordering element and its subelements before and
after. With relative ordering, the order in which application configuration resource
files will be loaded is calculated by considering ordering entries from the different
files. The following example shows some of these considerations. In the following
16-4 The Java EE 7 Tutorial
Using Faces Flows
example, config-A, config-B, and config-C are different application configuration
resource files.
File config-A contains the following elements:
<faces-config>
<name>config-A</name>
<ordering>
<before>
<name>config-B</name>
</before>
</ordering>
</faces-config>
File config-B (not shown here) does not contain any ordering elements.
File config-C contains the following elements:
<faces-config>
<name>config-C</name>
<ordering>
<after>
<name>config-B</name>
</after>
</ordering>
</faces-config>
Based on the before subelement entry, file config-A will be loaded before the
config-B file. Based on the after subelement entry, file config-C will be loaded after
the config-B file.
In addition, a subelement others can also be nested within the before and after
subelements. If the others element is present, the specified file may receive highest or
lowest preference among both listed and unlisted configuration files.
If an ordering element is not present in an application configuration file, then that file
will be loaded after all the files that contain ordering elements.
16.3 Using Faces Flows
The Faces Flows feature of JavaServer Faces technology allows you to create a set of
pages with a scope, FlowScoped, that is greater than request scope but less than session
scope. For example, you might want to create a series of pages for the checkout process
in an online store. You could create a set of self-contained pages that could be
transferred from one store to another as needed.
Faces Flows are somewhat analogous to subroutines in procedural programming, in
the following ways.
■
■
■
Like a subroutine, a flow has a well defined entry point, list of parameters, and
return value. However, unlike a subroutine, a flow can return multiple values.
Like a subroutine, a flow has a scope, allowing information to be available only
during the invocation of the flow. Such information is not available outside the
scope of the flow and does not consume any resources once the flow returns.
Like a subroutine, a flow may call other flows before returning. The invocation of
flows is maintained in a call stack: a new flow causes a push onto the stack, and a
return causes a pop.
Configuring JavaServer Faces Applications 16-5
Using Faces Flows
An application can have any number of flows. Each flow includes a set of pages and,
usually, one or more managed beans scoped to that flow. Each flow has a starting
point, called a start node, and an exit point, called a return node.
The data in a flow is scoped to that flow alone, but you can pass data from one flow to
another by specifying parameters and calling the other flow.
Flows can be nested, so that if you call one flow from another and then exit the second
flow, you return to the calling flow rather than to the second flow's return node.
You can configure a flow programmatically, by creating a class annotated
@FlowDefinition, or you can configure a flow by using a configuration file. The
configuration file can be limited to one flow, or you can use the faces-config.xml file
to put all the flows in one place, if you have many flows in an application. The
programmatic configuration places the code closer to the rest of the flow code and
enables you to modularize the flows.
Figure 16–1 shows two flows and illustrates how they interact.
Figure 16–1 Two Faces Flows and Their Interactions
Flow A
flow-a
- param1FromFlowB
- param2FromFlowB
taskFlow
Return1
Flow_a_Bean
Start
flow-a
next_a1
next_a2
callB
- param1FromFlowA
- param2FromFlowA
Flow B
flow-b
- param1FromFlowA
- param2FromFlowA
taskFlow
Return1
Flow_b_Bean
Start
flow-b
next_b1
next_b2
callA
- param1FromFlowB
- param2FromFlowB
In this figure, Flow A has a start node named flow-a and two additional pages, next_
a1 and next_a2. From next_a2, a user can either exit the flow using the defined return
node, taskFlowReturn1, or call Flow B, passing two parameters. Flow A also defines
two inbound parameters that it can accept from Flow B. Flow B is identical to Flow A
except for the names of the flow and files. Each flow also has an associated managed
bean; the beans are Flow_a_Bean and Flow_b_Bean.
16-6 The Java EE 7 Tutorial
Using Faces Flows
16.3.1 Packaging Flows in an Application
Typically, you package flows in a web application using a directory structure that
modularizes the flows. In the src/main/webapp directory of a Maven project, for
example, you would place the Facelets files that are outside the flow at the top level as
usual. Then the webapp files for each flow would be in a separate directory, and the
Java files would be under src/main/java. For example, the files for the application
shown in Figure 16–1 might look like this:
src/main/webapp/
index.xhtml
return.xhtml
WEB_INF/
beans.xml
web.xml
flow-a/
flow-a.xhtml
next_a1.xhtml
next_a2.xhtml
flow-b/
flow-b-flow.xml
next_b1.xhtml
next_b2.xhtml
src/main/java/javaeetutorial/flowexample
FlowA.java
Flow_a_Bean.java
Flow_b_Bean.java
In this example, flow-a is defined programmatically in FlowA.java, while flow-b is
defined by the configuration file flow-b-flow.xml.
16.3.2 The Simplest Possible Flow: The simple-flow Example Application
The simple-flow example application demonstrates the most basic building blocks of
a Faces Flows application and illustrates some of the conventions that make it easy to
get started with iterative development using flows. You may want to start with a
simple example like this one and build upon it.
This example provides an implicit flow definition by including an empty
configuration file. A configuration file that has content, or a class annotated
@FlowDefinition, provides an explicit flow definition.
The source code for this application is in the
tut-install/examples/web/jsf/simple-flow/ directory.
The file layout of the simple-flow example looks like this:
src/main/webapp
index.xhtml
simple-flow-return.xhtml
WEB_INF/
web.xml
simple-flow
simple-flow-flow.xml
simple-flow.xhtml
simple-flow-page2.xhtml
The simple-flow example has an empty configuration file, which is by convention
named flow-name-flow.xml. The flow does not require any configuration for the
following reasons.
Configuring JavaServer Faces Applications 16-7
Using Faces Flows
■
■
The flow does not call another flow, nor does it pass parameters to another flow.
The flow uses default names for the first page of the flow, flow-name.xhtml, and
the return page, flow-name-return.xhtml.
This example has only four Facelets pages.
■
index.xhtml, the start page, which contains almost nothing but a button that
navigates to the first page of the flow:
<p><h:commandButton value="Enter Flow" action="simple-flow"/></p>
■
simple-flow.xhtml and simple-flow-page2.xhtml, the two pages of the flow
itself. In the absence of an explicit flow definition, the page whose name is the
same as the name of the flow is assumed to be the start node of the flow. In this
case, the flow is named simple-flow, so the page named simple-flow.xhtml is
assumed to be the start node of the flow. The start node is the node navigated to
upon entry into the flow. It can be thought of as the home page of the flow.
The simple-flow.xhtml page asks you to enter a flow-scoped value and provides
a button that navigates to the next page of the flow:
<p>Value: <h:inputText id="input" value="#{flowScope.value}" /></p>
<p><h:commandButton value="Next" action="simple-flow-page2" /></p>
The second page, which can have any name, displays the flow-scoped value and
provides a button that navigates to the return page:
<p>Value: #{flowScope.value}</p>
<p><h:commandButton value="Return" action="simple-flow-return" /></p>
■
simple-flow-return.xhtml, the return page. The return page, which by
convention is named flow-name-return.xhtml, must be located outside of the flow.
This page displays the flow-scoped value, to show that it has no value outside of
the flow, and provides a link that navigates to the index.xhtml page:
<p>Value (should be empty):
"<h:outputText id="output" value="#{flowScope.value}" />"</p>
<p><h:link outcome="index" value="Back to Start" /></p>
The Facelets pages use only flow-scoped data, so the example does not need a
managed bean.
16.3.2.1 To Build, Package, and Deploy the simple-flow Example Using NetBeans
IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsf
4.
Select the simple-flow folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the simple-flow project and select Build.
16-8 The Java EE 7 Tutorial
Using Faces Flows
This command builds and packages the application into a WAR file,
simple-flow.war, that is located in the target directory. It then deploys the
application to the server.
16.3.2.2 To Build, Package, and Deploy the simple-flow Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/jsf/simple-flow/
3.
Enter the following command:
mvn install
This command builds and packages the application into a WAR file,
simple-flow.war, that is located in the target directory. It then deploys the
application to the server.
16.3.2.3 To Run the simple-flow Example
1.
Enter the following URL in your web browser:
http://localhost:8080/simple-flow
2.
On the index.xhtml page, click Enter Flow.
3.
On the first page of the flow, enter any string in the Value field, then click Next.
4.
On the second page of the flow, you can see the value you entered. Click Return.
5.
On the return page, an empty pair of quotation marks encloses the inaccessible
value. Click Back to Start to return to the index.xhtml page.
16.3.3 The checkout-module Example Application
The checkout-module example application is considerably more complex than
simple-flow. It shows how you might use the Faces Flows feature to implement a
checkout module for an online store.
Like the hypothetical example in Figure 16–1, the example application contains two
flows, each of which can call the other. Both flows have explicit flow definitions. One
flow, checkoutFlow, is specified programmatically. The other flow, joinFlow, is
specified in a configuration file.
The source code for this application is in the
tut-install/examples/web/jsf/checkout-module/ directory.
For the checkout-module application, the directory structure is as follows (there is also
a src/main/webapp/resources directory with a stylesheet and an image):
src/main/webapp/
index.xhtml
exithome.xhtml
WEB_INF/
beans.xml
web.xml
checkoutFlow/
checkoutFlow.xhtml
checkoutFlow2.xhtml
checkoutFlow3.xhtml
Configuring JavaServer Faces Applications 16-9
Using Faces Flows
checkoutFlow4.xhtml
joinFlow/
joinFlow-flow.xml
joinFlow.xhtml
joinFlow2.xhtml
src/main/java/javaeetutorial/checkoutmodule
CheckoutBean.java
CheckoutFlow.java
CheckoutFlowBean.java
JoinFlowBean.java
For the example, index.xhtml is the beginning page for the application as well as the
return node for the checkout flow. The exithome.xhtml page is the return node for the
join flow.
The configuration file joinFlow-flow.xml defines the join flow, and the source file
CheckoutFlow.java defines the checkout flow.
The checkout flow contains four Facelets pages, whereas the join flow contains two.
The managed beans scoped to each flow are CheckoutFlowBean.java and
JoinFlowBean.java, whereas CheckoutBean.java is the backing bean for the
index.html page.
16.3.3.1 The Facelets Pages for the checkout-module Example
The starting page for the example, index.xhtml, summarizes the contents of a
hypothetical shopping cart. It allows the user to click either of two buttons to enter one
of the two flows:
<p><h:commandButton value="Check Out" action="checkoutFlow"/></p>
...
<p><h:commandButton value="Join" action="joinFlow"/></p>
This page is also the return node for the checkout flow.
The Facelets page exithome.xhtml is the return node for the join flow. This page has a
button that allows you to return to the index.xhtml page.
The four Facelets pages within the checkout flow, starting with checkoutFlow.xhtml
and ending with checkoutFlow4.xhtml, allow you to proceed to the next page or, in
some cases, to return from the flow. The checkoutFlow.xhtml page allows you to
access parameters passed from the join flow through the flow scope. These appear as
empty quotation marks if you have not called the checkout flow from the join flow.
<p>If you called this flow from the Join flow, you can see these parameters:
"<h:outputText value="#{flowScope.param1Value}"/>" and
"<h:outputText value="#{flowScope.param2Value}"/>"
</p>
Only checkoutFlow2.xhtml has a button to return to the previous page, but moving
between pages is generally permitted within flows. Here are the buttons for
checkoutFlow2.xhtml:
<p><h:commandButton value="Continue" action="checkoutFlow3"/></p>
<p><h:commandButton value="Go Back" action="checkoutFlow"/></p>
<p><h:commandButton value="Exit Flow" action="returnFromCheckoutFlow"/></p>
The action returnFromCheckoutFlow is defined in the configuration source code file,
CheckoutFlow.java.
16-10 The Java EE 7 Tutorial
Using Faces Flows
The final page of the checkout flow, checkoutFlow4.xhtml, contains a button that calls
the join flow:
<p><h:commandButton value="Join" action="calljoin"/></p>
<p><h:commandButton value="Exit Flow" action="returnFromCheckoutFlow"/></p>
The calljoin action is also defined in the configuration source code file,
CheckoutFlow.java. This action enters the join flow, passing two parameters from the
checkout flow.
The two pages in the join flow, joinFlow.xhtml and joinFlow2.xhtml, are similar to
those in the checkout flow. The second page has a button to call the checkout flow as
well as one to return from the join flow:
<p><h:commandButton value="Check Out" action="callcheckoutFlow"/></p>
<p><h:commandButton value="Exit Flow" action="returnFromJoinFlow"/></p>
For this flow, the actions callcheckoutFlow and returnFromJoinFlow are defined in
the configuration file joinFlow-flow.xml.
16.3.3.2 Using a Configuration File to Configure a Flow
If you use an application configuration resource file to configure a flow, it must be
named flowName-flow.xml. In this example, the join flow uses a configuration file
named joinFlow-flow.xml. The file is a faces-config file that specifies a
flow-definition element. This element must define the flow name using the id
attribute. Under the flow-definition element, there must be a flow-return element
that specifies the return point for the flow. Any inbound parameters are specified with
inbound-parameter elements. If the flow calls another flow, the call-flow element
must use the flow-reference element to name the called flow and may use the
outbound-parameter element to specify any outbound parameters.
The configuration file for the join flow looks like this:
<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee \
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<flow-definition id="joinFlow">
<flow-return id="returnFromJoinFlow">
<from-outcome>#{joinFlowBean.returnValue}</from-outcome>
</flow-return>
<inbound-parameter>
<name>param1FromCheckoutFlow</name>
<value>#{flowScope.param1Value}</value>
</inbound-parameter>
<inbound-parameter>
<name>param2FromCheckoutFlow</name>
<value>#{flowScope.param2Value}</value>
</inbound-parameter>
<flow-call id="callcheckoutFlow">
<flow-reference>
<flow-id>checkoutFlow</flow-id>
</flow-reference>
<outbound-parameter>
<name>param1FromJoinFlow</name>
<value>param1 joinFlow value</value>
</outbound-parameter>
Configuring JavaServer Faces Applications 16-11
Using Faces Flows
<outbound-parameter>
<name>param2FromJoinFlow</name>
<value>param2 joinFlow value</value>
</outbound-parameter>
</flow-call>
</flow-definition>
</faces-config>
The id attribute of the flow-definition element defines the name of the flow as
joinFlow. The value of the id attribute of the flow-return element identifies the name
of the return node, and its value is defined in the from-outcome element as the
returnValue property of the flow-scoped managed bean for the join flow,
JoinFlowBean.
The names and values of the inbound parameters are retrieved from the flow scope in
order (flowScope.param1Value, flowScope.param2Value), based on the way they were
defined in the checkout flow configuration.
The flow-call element defines how the join flow calls the checkout flow. The id
attribute of the element, callcheckoutFlow, defines the action of calling the flow.
Within the flow-call element, the flow-reference element defines the actual name of
the flow to call, checkoutFlow. The outbound-parameter elements define the
parameters to be passed when checkoutFlow is called. Here they are just arbitrary
strings.
16.3.3.3 Using a Java Class to Configure a Flow
If you use a Java class to configure a flow, it must have the name of the flow. The class
for the checkout flow is called CheckoutFlow.java.
import
import
import
import
import
import
java.io.Serializable;
javax.enterprise.inject.Produces;
javax.faces.flow.Flow;
javax.faces.flow.builder.FlowBuilder;
javax.faces.flow.builder.FlowBuilderParameter;
javax.faces.flow.builder.FlowDefinition;
class CheckoutFlow implements Serializable {
private static final long serialVersionUID = 1L;
@Produces
@FlowDefinition
public Flow defineFlow(@FlowBuilderParameter FlowBuilder flowBuilder) {
String flowId = "checkoutFlow";
flowBuilder.id("", flowId);
flowBuilder.viewNode(flowId,
"/" + flowId + "/" + flowId + ".xhtml").
markAsStartNode();
flowBuilder.returnNode("returnFromCheckoutFlow").
fromOutcome("#{checkoutFlowBean.returnValue}");
flowBuilder.inboundParameter("param1FromJoinFlow",
"#{flowScope.param1Value}");
flowBuilder.inboundParameter("param2FromJoinFlow",
"#{flowScope.param2Value}");
flowBuilder.flowCallNode("calljoin").flowReference("", "joinFlow").
16-12 The Java EE 7 Tutorial
Using Faces Flows
outboundParameter("param1FromCheckoutFlow",
"#{checkoutFlowBean.name}").
outboundParameter("param2FromCheckoutFlow",
"#{checkoutFlowBean.city}");
return flowBuilder.getFlow();
}
}
The class performs actions that are almost identical to those performed by the
configuration file joinFlow-flow.xml. It contains a single method, defineFlow, as a
producer method with the @FlowDefinition qualifier that returns a
javax.faces.flow.Flow class. The defineFlow method takes one parameter, a
FlowBuilder with the qualifier @FlowBuilderParameter, which is passed in from the
JavaServer Faces implementation. The method then calls methods from the
javax.faces.flow.Builder.FlowBuilder class to configure the flow.
First, the method defines the flow id as checkoutFlow. Then, it explicitly defines the
start node for the flow. By default, this is the name of the flow with an .xhtml suffix.
The method then defines the return node similarly to the way the configuration file
does. The returnNode method sets the name of the return node as
returnFromCheckoutFlow, and the chained fromOutcome method specifies its value as
the returnValue property of the flow-scoped managed bean for the checkout flow,
CheckoutFlowBean.
The inboundParameter method sets the names and values of the inbound parameters
from the join flow, which are retrieved from the flow scope in order
(flowScope.param1Value, flowScope.param2Value), based on the way they were
defined in the join flow configuration.
The flowCallNode method defines how the checkout flow calls the join flow. The
argument, calljoin, specifies the action of calling the flow. The chained
flowReference method defines the actual name of the flow to call, joinFlow, then calls
outboundParameter methods to define the parameters to be passed when joinFlow is
called. Here they are values from the CheckoutFlowBean managed bean.
Finally, the defineFlow method calls the getFlow method and returns the result.
16.3.3.4 The Flow-Scoped Managed Beans
Each of the two flows has a managed bean that defines properties for the pages within
the flow. For example, the CheckoutFlowBean defines properties whose values are
entered by the user on both the checkoutFlow.xhtml page and the
checkoutFlow3.xhtml page.
Each managed bean has a getReturnValue method that sets the value of the return
node. For the CheckoutFlowBean, the return node is the index.xhtml page, specified
using implicit navigation:
public String getReturnValue() {
return "index";
}
For the JoinFlowBean, the return node is the exithome.xhtml page.
16.3.3.5 To Build, Package, and Deploy the checkout-module Example Using
NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
Configuring JavaServer Faces Applications 16-13
Configuring Managed Beans
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsf
4.
Select the checkout-module folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the checkout-module project and select Build.
This command builds and packages the application into a WAR file,
checkout-module.war, that is located in the target directory. It then deploys the
application to the server.
16.3.3.6 To Build, Package, and Deploy the checkout-module Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/jsf/checkout-module/
3.
Enter the following command:
mvn install
This command builds and packages the application into a WAR file,
checkout-module.war, that is located in the target directory. It then deploys the
application to the server.
16.3.3.7 To Run the checkout-module Example
1.
Enter the following URL in your web browser:
http://localhost:8080/checkout-module
2.
The index.xhtml page presents hypothetical results of the shopping expedition.
Click either Check Out or Join to enter one of the two flows.
3.
Follow the flow, providing input as needed and choosing whether to continue, go
back, or exit the flow.
In the checkout flow, only one of the input fields is validated (the credit card field
expects 16 digits), so you can enter any values you like. The join flow does not
require you to check any boxes in its checkbox menus.
4.
On the last page of a flow, select the option to enter the other flow. This allows you
to view the inbound parameters from the previous flow.
5.
Because flows are nested, if you click Exit Flow from a called flow, you will return
to the first page of the calling flow. (You may see a warning, which you can
ignore.) Click Exit Flow on that page to go to the specified return node.
16.4 Configuring Managed Beans
When a page references a managed bean for the first time, the JavaServer Faces
implementation initializes it either based on a @Named annotation and scope annotation
in the bean class or according to its configuration in the application configuration
resource file. For information on using annotations to initialize beans, see Using
Annotations to Configure Managed Beans.
16-14 The Java EE 7 Tutorial
Configuring Managed Beans
You can use either annotations or the application configuration resource file to
instantiate managed beans that are used in a JavaServer Faces application and to store
them in scope. The managed bean creation facility is configured in the application
configuration resource file using managed-bean XML elements to define each bean.
This file is processed at application startup time. For information on using this facility,
see Using the managed-bean Element.
Managed beans created in the application configuration resource file are JavaServer
Faces managed beans, not CDI managed beans.
With the managed bean creation facility, you can
■
■
■
■
Create beans in one centralized file that is available to the entire application, rather
than conditionally instantiate beans throughout the application
Customize a bean's properties without any additional code
Customize a bean's property values directly from within the configuration file so
that it is initialized with these values when it is created
Using value elements, set a property of one managed bean to be the result of
evaluating another value expression
This section shows you how to initialize beans using the managed bean creation
facility. See Writing Bean Properties and Writing Managed Bean Methods for
information on programming managed beans.
16.4.1 Using the managed-bean Element
A managed bean is initiated in the application configuration resource file using a
managed-bean element, which represents an instance of a bean class that must exist in
the application. At runtime, the JavaServer Faces implementation processes the
managed-bean element. If a page references the bean and no bean instance exists, the
JavaServer Faces implementation instantiates the bean as specified by the element
configuration.
Here is an example managed bean configuration from the Duke's Bookstore case
study:
<managed-bean eager="true">
<managed-bean-name>Book201</managed-bean-name>
<managed-bean-class>dukesbookstore.model.ImageArea</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<managed-property>
<property-name>shape</property-name>
<value>rect</value>
</managed-property>
<managed-property>
<property-name>alt</property-name>
<value>Duke</value>
</managed-property>
<managed-property>
<property-name>coords</property-name>
<value>67,23,212,268</value>
</managed-property>
</managed-bean>
The managed-bean-name element defines the key under which the bean will be stored
in a scope. For a component's value to map to this bean, the component tag's value
attribute must match the managed-bean-name up to the first period.
Configuring JavaServer Faces Applications 16-15
Configuring Managed Beans
The managed-bean-class element defines the fully qualified name of the JavaBeans
component class used to instantiate the bean.
The managed-bean element can contain zero or more managed-property elements, each
corresponding to a property defined in the bean class. These elements are used to
initialize the values of the bean properties. If you don't want a particular property
initialized with a value when the bean is instantiated, do not include a
managed-property definition for it in your application configuration resource file.
If a managed-bean element does not contain other managed-bean elements, it can
contain one map-entries element or list-entries element. The map-entries element
configures a set of beans that are instances of Map. The list-entries element
configures a set of beans that are instances of List.
In the following example, the newsletters managed bean, representing a
UISelectItems component, is configured as an ArrayList that represents a set of
SelectItem objects. Each SelectItem object is in turn configured as a managed bean
with properties:
<managed-bean>
<managed-bean-name>newsletters</managed-bean-name>
<managed-bean-class>java.util.ArrayList</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<list-entries>
<value-class>javax.faces.model.SelectItem</value-class>
<value>#{newsletter0}</value>
<value>#{newsletter1}</value>
<value>#{newsletter2}</value>
<value>#{newsletter3}</value>
</list-entries>
</managed-bean>
<managed-bean>
<managed-bean-name>newsletter0</managed-bean-name>
<managed-bean-class>javax.faces.model.SelectItem</managed-bean-class>
<managed-bean-scope>none</managed-bean-scope>
<managed-property>
<property-name>label</property-name>
<value>Duke's Quarterly</value>
</managed-property>
<managed-property>
<property-name>value</property-name>
<value>200</value>
</managed-property>
</managed-bean>
...
This approach may be useful for quick-and-dirty creation of selection item lists before
a development team has had time to create such lists from the database. Note that each
of the individual newsletter beans has a managed-bean-scope setting of none so that
they will not themselves be placed into any scope.
See Initializing Array and List Properties for more information on configuring
collections as beans.
To map to a property defined by a managed-property element, you must ensure that
the part of a component tag's value expression after the period matches the
managed-property element's property-name element. The next section, Initializing
Properties Using the managed-property Element, explains in more detail how to use
the managed-property element. See Initializing Managed Bean Properties for an
example of initializing a managed bean property.
16-16 The Java EE 7 Tutorial
Configuring Managed Beans
16.4.2 Initializing Properties Using the managed-property Element
A managed-property element must contain a property-name element, which must
match the name of the corresponding property in the bean. A managed-property
element must also contain one of a set of elements that defines the value of the
property. This value must be of the same type as that defined for the property in the
corresponding bean. Which element you use to define the value depends on the type
of the property defined in the bean. Table 16–1 lists all the elements that are used to
initialize a value.
Table 16–1
Subelements of managed-property Elements That Define Property Values
Element
Value It Defines
list-entries
Defines the values in a list
map-entries
Defines the values of a map
null-value
Explicitly sets the property to null
value
Defines a single value, such as a String, int, or JavaServer Faces EL
expression
Using the managed-bean Element includes an example of initializing an int property
(a primitive type) using the value subelement. You also use the value subelement to
initialize String and other reference types. The rest of this section describes how to
use the value subelement and other subelements to initialize properties of Java Enum
types, Map, array, and Collection, as well as initialization parameters.
16.4.2.1 Referencing a Java Enum Type
A managed bean property can also be a Java Enum type (see
http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html). In
this case, the value element of the managed-property element must be a String that
matches one of the String constants of the Enum. In other words, the String must be
one of the valid values that can be returned if you were to call valueOf(Class,
String) on enum, where Class is the Enum class and String is the contents of the value
subelement. For example, suppose the managed bean property is the following:
public enum Suit { Hearts, Spades, Diamonds, Clubs }
...
public Suit getSuit() { ... return Suit.Hearts; }
Assuming you want to configure this property in the application configuration
resource file, the corresponding managed-property element looks like this:
<managed-property>
<property-name>Suit</property-name>
<value>Hearts</value>
</managed-property>
When the system encounters this property, it iterates over each of the members of the
enum and calls toString() on each member until it finds one that is exactly equal to
the value from the value element.
16.4.2.2 Referencing a Context Initialization Parameter
Another powerful feature of the managed bean creation facility is the ability to
reference implicit objects from a managed bean property.
Suppose you have a page that accepts data from a customer, including the customer's
address. Suppose also that most of your customers live in a particular area code. You
Configuring JavaServer Faces Applications 16-17
Configuring Managed Beans
can make the area code component render this area code by saving it in an implicit
object and referencing it when the page is rendered.
You can save the area code as an initial default value in the context initParam implicit
object by adding a context parameter to your web application and setting its value in
the deployment descriptor. For example, to set a context parameter called
defaultAreaCode to 650, add a context-param element to the deployment descriptor
and give the parameter the name defaultAreaCode and the value 650.
Next, write a managed-bean declaration that configures a property that references the
parameter:
<managed-bean>
<managed-bean-name>customer</managed-bean-name>
<managed-bean-class>CustomerBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>areaCode</property-name>
<value>#{initParam.defaultAreaCode}</value>
</managed-property>
...
</managed-bean>
To access the area code at the time the page is rendered, refer to the property from the
area component tag's value attribute:
<h:inputText id=area value="#{customer.areaCode}"
Values are retrieved from other implicit objects in a similar way.
16.4.2.3 Initializing Map Properties
The map-entries element is used to initialize the values of a bean property with a type
of Map if the map-entries element is used within a managed-property element. A
map-entries element contains an optional key-class element, an optional
value-class element, and zero or more map-entry elements.
Each of the map-entry elements must contain a key element and either a null-value or
value element. Here is an example that uses the map-entries element:
<managed-bean>
...
<managed-property>
<property-name>prices</property-name>
<map-entries>
<map-entry>
<key>My Early Years: Growing Up on *7</key>
<value>30.75</value>
</map-entry>
<map-entry>
<key>Web Servers for Fun and Profit</key>
<value>40.75</value>
</map-entry>
</map-entries>
</managed-property>
</managed-bean>
The map created from this map-entries tag contains two entries. By default, all the
keys and values are converted to String. If you want to specify a different type for the
keys in the map, embed the key-class element just inside the map-entries element:
<map-entries>
16-18 The Java EE 7 Tutorial
Configuring Managed Beans
<key-class>java.math.BigDecimal</key-class>
...
</map-entries>
This declaration will convert all the keys into java.math.BigDecimal. Of course, you
must make sure that the keys can be converted to the type you specify. The key from
the example in this section cannot be converted to a BigDecimal, because it is a String.
If you want to specify a different type for all the values in the map, include the
value-class element after the key-class element:
<map-entries>
<key-class>int</key-class>
<value-class>java.math.BigDecimal</value-class>
...
</map-entries>
Note that this tag sets only the type of all the value subelements.
Each map-entry in the preceding example includes a value subelement. The value
subelement defines a single value, which will be converted to the type specified in the
bean.
Instead of using a map-entries element, it is also possible to assign the entire map
using a value element that specifies a map-typed expression.
16.4.2.4 Initializing Array and List Properties
The list-entries element is used to initialize the values of an array or List property.
Each individual value of the array or List is initialized using a value or null-value
element. Here is an example:
<managed-bean>
...
<managed-property>
<property-name>books</property-name>
<list-entries>
<value-class>java.lang.String</value-class>
<value>Web Servers for Fun and Profit</value>
<value>#{myBooks.bookId[3]}</value>
<null-value/>
</list-entries>
</managed-property>
</managed-bean>
This example initializes an array or a List. The type of the corresponding property in
the bean determines which data structure is created. The list-entries element
defines the list of values in the array or List. The value element specifies a single
value in the array or List and can reference a property in another bean. The
null-value element will cause the setBooks method to be called with an argument of
null. A null property cannot be specified for a property whose data type is a Java
primitive, such as int or boolean.
16.4.2.5 Initializing Managed Bean Properties
Sometimes you might want to create a bean that also references other managed beans
so that you can construct a graph or a tree of beans. For example, suppose you want to
create a bean representing a customer's information, including the mailing address
and street address, each of which is also a bean. The following managed-bean
declarations create a CustomerBean instance that has two AddressBean properties: one
representing the mailing address and the other representing the street address. This
Configuring JavaServer Faces Applications 16-19
Configuring Managed Beans
declaration results in a tree of beans with CustomerBean as its root and the two
AddressBean objects as children.
<managed-bean>
<managed-bean-name>customer</managed-bean-name>
<managed-bean-class>
com.example.mybeans.CustomerBean
</managed-bean-class>
<managed-bean-scope> request </managed-bean-scope>
<managed-property>
<property-name>mailingAddress</property-name>
<value>#{addressBean}</value>
</managed-property>
<managed-property>
<property-name>streetAddress</property-name>
<value>#{addressBean}</value>
</managed-property>
<managed-property>
<property-name>customerType</property-name>
<value>New</value>
</managed-property>
</managed-bean>
<managed-bean>
<managed-bean-name>addressBean</managed-bean-name>
<managed-bean-class>
com.example.mybeans.AddressBean
</managed-bean-class>
<managed-bean-scope> none </managed-bean-scope>
<managed-property>
<property-name>street</property-name>
<null-value/>
<managed-property>
...
</managed-bean>
The first CustomerBean declaration (with the managed-bean-name of customer) creates
a CustomerBean in request scope. This bean has two properties, mailingAddress and
streetAddress. These properties use the value element to reference a bean named
addressBean.
The second managed bean declaration defines an AddressBean but does not create it,
because its managed-bean-scope element defines a scope of none. Recall that a scope of
none means that the bean is created only when something else references it. Because
both the mailingAddress and the streetAddress properties reference addressBean
using the value element, two instances of AddressBean are created when
CustomerBean is created.
When you create an object that points to other objects, do not try to point to an object
with a shorter life span, because it might be impossible to recover that scope's
resources when it goes away. A session-scoped object, for example, cannot point to a
request-scoped object. And objects with none scope have no effective life span
managed by the framework, so they can point only to other none-scoped objects.
Table 16–2 outlines all of the allowed connections.
Table 16–2
Allowable Connections between Scoped Objects
An Object of This
Scope
May Point to an Object of This Scope
none
none
16-20 The Java EE 7 Tutorial
Registering Application Messages
Table 16–2 (Cont.) Allowable Connections between Scoped Objects
An Object of This
Scope
May Point to an Object of This Scope
application
none, application
session
none, application, session
request
none, application, session, request, view
view
none, application, session, view
Be sure not to allow cyclical references between objects. For example, neither of the
AddressBean objects in the preceding example should point back to the CustomerBean
object, because CustomerBean already points to the AddressBean objects.
16.4.3 Initializing Maps and Lists
In addition to configuring Map and List properties, you can also configure a Map and a
List directly so that you can reference them from a tag rather than referencing a
property that wraps a Map or a List.
16.5 Registering Application Messages
Application messages can include any strings displayed to the user as well as custom
error messages (which are displayed by the message and messages tags) for your
custom converters or validators. To make messages available at application startup
time, do one of the following:
■
■
Queue an individual message onto the javax.faces.context.FacesContext
instance programmatically, as described in Using FacesMessage to Create a
Message
Register all the messages with your application using the application
configuration resource file
Here is the section of the faces-config.xml file that registers the messages for the
Duke's Bookstore case study application:
<application>
<resource-bundle>
<base-name>
javaeetutorial.dukesbookstore.web.messages.Messages
</base-name>
<var>bundle</var>
</resource-bundle>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>es</supported-locale>
<supported-locale>de</supported-locale>
<supported-locale>fr</supported-locale>
</locale-config>
</application>
This set of elements causes the application to be populated with the messages that are
contained in the specified resource bundle.
The resource-bundle element represents a set of localized messages. It must contain
the fully qualified path to the resource bundle containing the localized messages (in
Configuring JavaServer Faces Applications 16-21
Registering Application Messages
this case, dukesbookstore.web.messages.Messages). The var element defines the EL
name by which page authors refer to the resource bundle.
The locale-config element lists the default locale and the other supported locales.
The locale-config element enables the system to find the correct locale based on the
browser's language settings.
The supported-locale and default-locale tags accept the lowercase, two-character
codes defined by ISO 639-1 (see
http://www.loc.gov/standards/iso639-2/php/English_list.php). Make
sure that your resource bundle actually contains the messages for the locales you
specify with these tags.
To access the localized message, the application developer merely references the key of
the message from the resource bundle.
You can pull localized text into an alt tag for a graphic image, as in the following
example:
<h:graphicImage id="mapImage"
name="book_all.jpg"
library="images"
alt="#{bundle.ChooseBook}"
usemap="#bookMap" />
The alt attribute can accept value expressions. In this case, the alt attribute refers to
localized text that will be included in the alternative text of the image rendered by this
tag.
16.5.1 Using FacesMessage to Create a Message
Instead of registering messages in the application configuration resource file, you can
access the java.util.ResourceBundle directly from managed bean code. The code
snippet below locates an email error message:
String message = "";
...
message = ExampleBean.loadErrorMessage(context,
ExampleBean.EX_RESOURCE_BUNDLE_NAME,
"EMailError");
context.addMessage(toValidate.getClientId(context),
new FacesMessage(message));
These lines call the bean's loadErrorMessage method to get the message from the
ResourceBundle. Here is the loadErrorMessage method:
public static String loadErrorMessage(FacesContext context,
String basename, String key) {
if ( bundle == null ) {
try {
bundle = ResourceBundle.getBundle(basename,
context.getViewRoot().getLocale());
} catch (Exception e) {
return null;
}
}
return bundle.getString(key);
}
16-22 The Java EE 7 Tutorial
Registering Application Messages
16.5.2 Referencing Error Messages
A JavaServer Faces page uses the message or messages tags to access error messages,
as explained in Displaying Error Messages with the h:message and h:messages Tags.
The error messages these tags access include
■
■
The standard error messages that accompany the standard converters and
validators that ship with the API. (see Section 2.5.2.4 of the JavaServer Faces
specification for a complete list of standard error messages)
Custom error messages contained in resource bundles registered with the
application by the application architect using the resource-bundle element in the
configuration file
When a converter or validator is registered on an input component, the appropriate
error message is automatically queued on the component.
A page author can override the error messages queued on a component by using the
following attributes of the component's tag:
■
■
■
converterMessage: References the error message to display when the data on the
enclosing component cannot be converted by the converter registered on this
component.
requiredMessage: References the error message to display when no value has been
entered into the enclosing component.
validatorMessage: References the error message to display when the data on the
enclosing component cannot be validated by the validator registered on this
component.
All three attributes are enabled to take literal values and value expressions. If an
attribute uses a value expression, this expression references the error message in a
resource bundle. This resource bundle must be made available to the application in
one of the following ways:
■
■
By the application architect using the resource-bundle element in the
configuration file
By the page author using the f:loadBundle tag
Conversely, the resource-bundle element must be used to make available to the
application those resource bundles containing custom error messages that are queued
on the component as a result of a custom converter or validator being registered on the
component.
The following tags show how to specify the requiredMessage attribute using a value
expression to reference an error message:
<h:inputText id="ccno" size="19"
required="true"
requiredMessage="#{customMessages.ReqMessage}">
...
</h:inputText>
<h:message styleClass="error-message" for="ccno"/>
The value expression used by requiredMessage in this example references the error
message with the ReqMessage key in the resource bundle customMessages.
This message replaces the corresponding message queued on the component and will
display wherever the message or messages tag is placed on the page.
Configuring JavaServer Faces Applications 16-23
Using Default Validators
16.6 Using Default Validators
In addition to the validators you declare on the components, you can also specify zero
or more default validators in the application configuration resource file. The default
validator applies to all javax.faces.component.UIInput instances in a view or
component tree and is appended after the local defined validators. Here is an example
of a default validator registered in the application configuration resource file:
<faces-config>
<application>
<default-validators>
<validator-id>javax.faces.Bean</validator-id>
</default-validators>
<application/>
</faces-config>
16.7 Registering a Custom Validator
If the application developer provides an implementation of the
javax.faces.validator.Validator interface to perform validation, you must register
this custom validator either by using the @FacesValidator annotation, as described in
Implementing the Validator Interface, or by using the validator XML element in the
application configuration resource file:
<validator>
...
<validator-id>FormatValidator</validator-id>
<validator-class>
myapplication.validators.FormatValidator
</validator-class>
<attribute>
...
<attribute-name>formatPatterns</attribute-name>
<attribute-class>java.lang.String</attribute-class>
</attribute>
</validator>
Attributes specified in a validator tag override any settings in the @FacesValidator
annotation.
The validator-id and validator-class elements are required subelements. The
validator-id element represents the identifier under which the Validator class
should be registered. This ID is used by the tag class corresponding to the custom
validator tag.
The validator-class element represents the fully qualified class name of the
Validator class.
The attribute element identifies an attribute associated with the Validator
implementation. It has required attribute-name and attribute-class subelements.
The attribute-name element refers to the name of the attribute as it appears in the
validator tag. The attribute-class element identifies the Java type of the value
associated with the attribute.
Creating and Using a Custom Validator explains how to implement the Validator
interface.
Using a Custom Validator explains how to reference the validator from the page.
16-24 The Java EE 7 Tutorial
Configuring Navigation Rules
16.8 Registering a Custom Converter
As is the case with a custom validator, if the application developer creates a custom
converter, you must register it with the application either by using the
@FacesConverter annotation, as described in Creating a Custom Converter, or by
using the converter XML element in the application configuration resource file. Here
is a hypothetical converter configuration for CreditCardConverter from the Duke's
Bookstore case study:
<converter>
<description>
Converter for credit card numbers that normalizes
the input to a standard format
</description>
<converter-id>CreditCardConverter</converter-id>
<converter-class>
dukesbookstore.converters.CreditCardConverter
</converter-class>
</converter>
Attributes specified in a converter tag override any settings in the @FacesConverter
annotation.
The converter element represents a javax.faces.convert.Converter implementation
and contains required converter-id and converter-class elements.
The converter-id element identifies an ID that is used by the converter attribute of a
UI component tag to apply the converter to the component's data. Using a Custom
Converter includes an example of referencing the custom converter from a component
tag.
The converter-class element identifies the Converter implementation.
Creating and Using a Custom Converter explains how to create a custom converter.
16.9 Configuring Navigation Rules
Navigation between different pages of a JavaServer Faces application, such as
choosing the next page to be displayed after a button or link component is clicked, is
defined by a set of rules. Navigation rules can be implicit, or they can be explicitly
defined in the application configuration resource file. For more information on implicit
navigation rules, see Navigation Model.
Each navigation rule specifies how to navigate from one page to another page or set of
pages. The JavaServer Faces implementation chooses the proper navigation rule
according to which page is currently displayed.
After the proper navigation rule is selected, the choice of which page to access next
from the current page depends on two factors:
■
■
The action method invoked when the component was clicked
The logical outcome referenced by the component's tag or returned from the action
method
The outcome can be anything the developer chooses, but Table 16–3 lists some
outcomes commonly used in web applications.
Configuring JavaServer Faces Applications 16-25
Configuring Navigation Rules
Table 16–3
Common Outcome Strings
Outcome
What It Means
success
Everything worked. Go on to the next page.
failure
Something is wrong. Go on to an error page.
login
The user needs to log in first. Go on to the login page.
no results
The search did not find anything. Go to the search page again.
Usually, the action method performs some processing on the form data of the current
page. For example, the method might check whether the user name and password
entered in the form match the user name and password on file. If they match, the
method returns the outcome success. Otherwise, it returns the outcome failure. As
this example demonstrates, both the method used to process the action and the
outcome returned are necessary to determine the correct page to access.
Here is a navigation rule that could be used with the example just described:
<navigation-rule>
<from-view-id>/login.xhtml</from-view-id>
<navigation-case>
<from-action>#{LoginForm.login}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/storefront.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{LoginForm.logon}</from-action>
<from-outcome>failure</from-outcome>
<to-view-id>/logon.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
This navigation rule defines the possible ways to navigate from login.xhtml. Each
navigation-case element defines one possible navigation path from login.xhtml. The
first navigation-case says that if LoginForm.login returns an outcome of success,
then storefront.xhtml will be accessed. The second navigation-case says that
login.xhtml will be re-rendered if LoginForm.login returns failure.
The configuration of an application's page flow consists of a set of navigation rules.
Each rule is defined by the navigation-rule element in the faces-config.xml file.
Each navigation-rule element corresponds to one component tree identifier defined
by the optional from-view-id element. This means that each rule defines all the
possible ways to navigate from one particular page in the application. If there is no
from-view-id element, the navigation rules defined in the navigation-rule element
apply to all the pages in the application. The from-view-id element also allows
wildcard matching patterns. For example, this from-view-id element says that the
navigation rule applies to all the pages in the books directory:
<from-view-id>/books/*</from-view-id>
A navigation-rule element can contain zero or more navigation-case elements. The
navigation-case element defines a set of matching criteria. When these criteria are
satisfied, the application will navigate to the page defined by the to-view-id element
contained in the same navigation-case element.
The navigation criteria are defined by optional from-outcome and from-action
elements. The from-outcome element defines a logical outcome, such as success. The
from-action element uses a method expression to refer to an action method that
16-26 The Java EE 7 Tutorial
Registering a Custom Renderer with a Render Kit
returns a String, which is the logical outcome. The method performs some logic to
determine the outcome and returns the outcome.
The navigation-case elements are checked against the outcome and the method
expression in the following order.
1.
Cases specifying both a from-outcome value and a from-action value. Both of
these elements can be used if the action method returns different outcomes
depending on the result of the processing it performs.
2.
Cases specifying only a from-outcome value. The from-outcome element must
match either the outcome defined by the action attribute of the
javax.faces.component.UICommand component or the outcome returned by the
method referred to by the UICommand component.
3.
Cases specifying only a from-action value. This value must match the action
expression specified by the component tag.
When any of these cases is matched, the component tree defined by the to-view-id
element will be selected for rendering.
16.10 Registering a Custom Renderer with a Render Kit
When the application developer creates a custom renderer, as described in Delegating
Rendering to a Renderer, you must register it using the appropriate render kit. Because
the image map application implements an HTML image map, the AreaRenderer and
MapRenderer classes in the Duke's Bookstore case study should be registered using the
HTML render kit.
You register the renderer either by using the @FacesRenderer annotation, as described
in Creating the Renderer Class, or by using the render-kit element of the application
configuration resource file. Here is a hypothetical configuration of AreaRenderer:
<render-kit>
<renderer>
<component-family>Area</component-family>
<renderer-type>DemoArea</renderer-type>
<renderer-class>
dukesbookstore.renderers.AreaRenderer
</renderer-class>
<attribute>
<attribute-name>onmouseout</attribute-name>
<attribute-class>java.lang.String</attribute-class>
</attribute>
<attribute>
<attribute-name>onmouseover</attribute-name>
<attribute-class>java.lang.String</attribute-class>
</attribute>
<attribute>
<attribute-name>styleClass</attribute-name>
<attribute-class>java.lang.String</attribute-class>
</attribute>
</renderer>
...
Attributes specified in a renderer tag override any settings in the @FacesRenderer
annotation.
The render-kit element represents a javax.faces.render.RenderKit implementation. If
no render-kit-id is specified, the default HTML render kit is assumed. The renderer
element represents a javax.faces.render.Renderer implementation. By nesting the
Configuring JavaServer Faces Applications 16-27
Registering a Custom Renderer with a Render Kit
renderer element inside the render-kit element, you are registering the renderer with
the RenderKit implementation associated with the render-kit element.
The renderer-class is the fully qualified class name of the Renderer.
The component-family and renderer-type elements are used by a component to find
renderers that can render it. The component-family identifier must match that
returned by the component class's getFamily method. The component family
represents a component or set of components that a particular renderer can render. The
renderer-type must match that returned by the getRendererType method of the tag
handler class.
By using the component family and renderer type to look up renderers for
components, the JavaServer Faces implementation allows a component to be rendered
by multiple renderers and allows a renderer to render multiple components.
Each of the attribute tags specifies a render-dependent attribute and its type. The
attribute element doesn't affect the runtime execution of your application. Rather, it
provides information to tools about the attributes the Renderer supports.
The object responsible for rendering a component (be it the component itself or a
renderer to which the component delegates the rendering) can use facets to aid in the
rendering process. These facets allow the custom component developer to control
some aspects of rendering the component. Consider this custom component tag
example:
<d:dataScroller>
<f:facet name="header">
<h:panelGroup>
<h:outputText value="Account Id"/>
<h:outputText value="Customer Name"/>
<h:outputText value="Total Sales"/>
</h:panelGroup>
</f:facet>
<f:facet name="next">
<h:panelGroup>
<h:outputText value="Next"/>
<h:graphicImage url="/images/arrow-right.gif" />
</h:panelGroup>
</f:facet>
...
</d:dataScroller>
The dataScroller component tag includes a component that will render the header
and a component that will render the Next button. If the renderer associated with this
component renders the facets, you can include the following facet elements in the
renderer element:
<facet>
<description>This facet renders as the header of the table. It should be
a panelGroup with the same number of columns as the data.
</description>
<display-name>header</display-name>
<facet-name>header</facet-name>
</facet>
<facet>
<description>This facet renders as the content of the "next" button in
the scroller. It should be a panelGroup that includes an outputText
tag that has the text "Next" and a right arrow icon.
</description>
<display-name>Next</display-name>
16-28 The Java EE 7 Tutorial
Basic Requirements of a JavaServer Faces Application
<facet-name>next</facet-name>
</facet>
If a component that supports facets provides its own rendering and you want to
include facet elements in the application configuration resource file, you need to put
them in the component's configuration rather than the renderer's configuration.
16.11 Registering a Custom Component
In addition to registering custom renderers (as explained in the preceding section), you
also must register the custom components that are usually associated with the custom
renderers. You use either a @FacesComponent annotation, as described in Creating
Custom Component Classes, or the component element of the application
configuration resource file.
Here is a hypothetical component element from the application configuration resource
file that registers AreaComponent:
<component>
<component-type>DemoArea</component-type>
<component-class>
dukesbookstore.components.AreaComponent
</component-class>
<property>
<property-name>alt</property-name>
<property-class>java.lang.String</property-class>
</property>
<property>
<property-name>coords</property-name>
<property-class>java.lang.String</property-class>
</property>
<property>
<property-name>shape</property-name>
<property-class>java.lang.String</property-class>
</property>
</component>
Attributes specified in a component tag override any settings in the @FacesComponent
annotation.
The component-type element indicates the name under which the component should
be registered. Other objects referring to this component use this name. For example,
the component-type element in the configuration for AreaComponent defines a value of
DemoArea, which matches the value returned by the AreaTag class's getComponentType
method.
The component-class element indicates the fully qualified class name of the
component. The property elements specify the component properties and their types.
If the custom component can include facets, you can configure the facets in the
component configuration using facet elements, which are allowed after the
component-class elements. See Registering a Custom Renderer with a Render Kit for
further details on configuring facets.
16.12 Basic Requirements of a JavaServer Faces Application
In addition to configuring your application, you must satisfy other requirements of
JavaServer Faces applications, including properly packaging all the necessary files and
Configuring JavaServer Faces Applications 16-29
Basic Requirements of a JavaServer Faces Application
providing a deployment descriptor. This section describes how to perform these
administrative tasks.
JavaServer Faces applications can be packaged in a WAR file, which must conform to
specific requirements to execute across different containers. At a minimum, a WAR file
for a JavaServer Faces application may contain the following:
■
■
■
A web application deployment descriptor, called web.xml, to configure resources
required by a web application (required)
A specific set of JAR files containing essential classes (optional)
A set of application classes, JavaServer Faces pages, and other required resources,
such as image files
A WAR file may also contain:
■
An application configuration resource file, which configures application resources
■
A set of tag library descriptor files
For example, a Java Server Faces web application WAR file using Facelets typically has
the following directory structure:
$PROJECT_DIR
[Web Pages]
+- /[xhtml or html documents]
+- /resources
+- /WEB-INF
+- /web.xml
+- /beans.xml (optional)
+- /classes (optional)
+- /lib (optional)
+- /faces-config.xml (optional)
+- /*.taglib.xml (optional)
+- /glassfish-web.xml (optional)
The web.xml file (or web deployment descriptor), the set of JAR files, and the set of
application files must be contained in the WEB-INF directory of the WAR file.
16.12.1 Configuring an Application with a Web Deployment Descriptor
Web applications are commonly configured using elements contained in the web
application deployment descriptor, web.xml. The deployment descriptor for a
JavaServer Faces application must specify certain configurations, including the
following:
■
The servlet used to process JavaServer Faces requests
■
The servlet mapping for the processing servlet
■
The path to the configuration resource file, if it exists and is not located in a default
location
The deployment descriptor can also include other, optional configurations, such as
those that
■
Specify where component state is saved
■
Encrypt state saved on the client
■
Compress state saved on the client
■
Restrict access to pages containing JavaServer Faces tags
16-30 The Java EE 7 Tutorial
Basic Requirements of a JavaServer Faces Application
■
Turn on XML validation
■
Specify the Project Stage
■
Verify custom objects
This section gives more details on these configurations. Where appropriate, it also
describes how you can make these configurations using NetBeans IDE.
16.12.1.1 Identifying the Servlet for Lifecycle Processing
A requirement of a JavaServer Faces application is that all requests to the application
that reference previously saved JavaServer Faces components must go through
javax.faces.webapp.FacesServlet. A FacesServlet instance manages the
request-processing lifecycle for web applications and initializes the resources required
by JavaServer Faces technology.
Before a JavaServer Faces application can launch its first web page, the web container
must invoke the FacesServlet instance in order for the application lifecycle process to
start. See The Lifecycle of a JavaServer Faces Application for more information.
The following example shows the default configuration of the FacesServlet:
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
</servlet>
You will provide a mapping configuration entry to make sure that the FacesServlet
instance is invoked. The mapping to FacesServlet can be a prefix mapping, such as
/faces/*, or an extension mapping, such as *.xhtml. The mapping is used to identify
a page as having JavaServer Faces content. Because of this, the URL to the first page of
the application must include the URL pattern mapping.
The following elements specify a prefix mapping:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
...
<welcome-file-list>
<welcome-file>faces/greeting.xhtml</welcome-file>
</welcome-file-list>
The following elements, used in the tutorial examples, specify an extension mapping:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
...
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
When you use this mechanism, users access the application as shown in the following
example:
http://localhost:8080/guessNumber
In the case of extension mapping, if a request comes to the server for a page with an
.xhtml extension, the container will send the request to the FacesServlet instance,
Configuring JavaServer Faces Applications 16-31
Basic Requirements of a JavaServer Faces Application
which will expect a corresponding page of the same name containing the content to
exist.
If you are using NetBeans IDE to create your application, a web deployment
descriptor is automatically created for you with default configurations. If you created
your application without an IDE, you can create a web deployment descriptor.
16.12.1.2 To Specify a Path to an Application Configuration Resource File
As explained in Application Configuration Resource File, an application can have
multiple application configuration resource files. If these files are not located in the
directories that the implementation searches by default or the files are not named
faces-config.xml, you need to specify paths to these files.
To specify these paths using NetBeans IDE, do the following.
1.
Expand the node of your project in the Projects tab.
2.
Expand the Web Pages and WEB-INF nodes that are under the project node.
3.
Double-click web.xml.
4.
After the web.xml file appears in the editor, click General at the top of the editor
window.
5.
Expand the Context Parameters node.
6.
Click Add.
7.
In the Add Context Parameter dialog box:
8.
a.
Enter javax.faces.CONFIG_FILES in the Parameter Name field.
b.
Enter the path to your configuration file in the Parameter Value field.
c.
Click OK.
Repeat steps 1 through 7 for each configuration file.
16.12.1.3 To Specify Where State Is Saved
For all the components in a web application, you can specify in your deployment
descriptor where you want the state to be saved, on either client or server. You do this
by setting a context parameter in your deployment descriptor. By default, state is
saved on the server, so you need to specify this context parameter only if you want to
save state on the client. See Saving and Restoring State for information on the
advantages and disadvantages of each location.
To specify where state is saved using NetBeans IDE, do the following.
1.
Expand the node of your project in the Projects tab.
2.
Expand the Web Pages and WEB-INF nodes under the project node.
3.
Double-click web.xml.
4.
After the web.xml file appears in the editor window, click General at the top of the
editor window.
5.
Expand the Context Parameters node.
6.
Click Add.
7.
In the Add Context Parameter dialog box:
a.
Enter javax.faces.STATE_SAVING_METHOD in the Parameter Name field.
b.
Enter client or server in the Parameter Value field.
16-32 The Java EE 7 Tutorial
Basic Requirements of a JavaServer Faces Application
c.
Click OK.
If state is saved on the client, the state of the entire view is rendered to a hidden field
on the page. The JavaServer Faces implementation saves the state on the server by
default. Duke's Forest saves its state on the client.
16.12.2 Configuring Project Stage
Project Stage is a context parameter identifying the status of a JavaServer Faces
application in the software lifecycle. The stage of an application can affect the behavior
of the application. For example, error messages can be displayed during the
Development stage but suppressed during the Production stage.
The possible Project Stage values are as follows:
■
Development
■
UnitTest
■
SystemTest
■
Production
Project Stage is configured through a context parameter in the web deployment
descriptor file. Here is an example:
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
If no Project Stage is defined, the default stage is Production. You can also add custom
stages according to your requirements.
16.12.3 Including the Classes, Pages, and Other Resources
When packaging web applications using the included build scripts, you'll notice that
the scripts package resources in the following ways.
■
■
All web pages are placed at the top level of the WAR file.
The faces-config.xml file and the web.xml file are packaged in the WEB-INF
directory.
■
All packages are stored in the WEB-INF/classes/ directory.
■
All application JAR files are packaged in the WEB-INF/lib/ directory.
■
All resource files are either under the root of the web application /resources
directory or in the web application's classpath, the
META-INF/resources/resourceIdentifier directory. For more information on
resources, see Web Resources.
When packaging your own applications, you can use NetBeans IDE or you can use
XML files such as those created for Maven. You can modify the XML files to fit your
situation. However, you can continue to package your WAR files by using the
directory structure described in this section, because this technique complies with the
commonly accepted practice for packaging web applications.
Configuring JavaServer Faces Applications 16-33
Basic Requirements of a JavaServer Faces Application
16-34 The Java EE 7 Tutorial
17
Java Servlet Technology
17
Java Servlet technology provides dynamic, user-oriented content in web applications
using a request-response programming model.
The following topics are addressed here:
■
What Is a Servlet?
■
Servlet Lifecycle
■
Sharing Information
■
Creating and Initializing a Servlet
■
Writing Service Methods
■
Filtering Requests and Responses
■
Invoking Other Web Resources
■
Accessing the Web Context
■
Maintaining Client State
■
Finalizing a Servlet
■
Uploading Files with Java Servlet Technology
■
Asynchronous Processing
■
Nonblocking I/O
■
Protocol Upgrade Processing
■
The mood Example Application
■
The fileupload Example Application
■
The dukeetf Example Application
■
Further Information about Java Servlet Technology
17.1 What Is a Servlet?
A servlet is a Java programming language class used to extend the capabilities of
servers that host applications accessed by means of a request-response programming
model. Although servlets can respond to any type of request, they are commonly used
to extend the applications hosted by web servers. For such applications, Java Servlet
technology defines HTTP-specific servlet classes.
The javax.servlet and javax.servlet.http packages provide interfaces and classes
for writing servlets. All servlets must implement the Servlet interface, which defines
Java Servlet Technology 17-1
Servlet Lifecycle
lifecycle methods. When implementing a generic service, you can use or extend the
GenericServlet class provided with the Java Servlet API. The HttpServlet class
provides methods, such as doGet and doPost, for handling HTTP-specific services.
17.2 Servlet Lifecycle
The lifecycle of a servlet is controlled by the container in which the servlet has been
deployed. When a request is mapped to a servlet, the container performs the following
steps.
1.
2.
If an instance of the servlet does not exist, the web container:
a.
Loads the servlet class
b.
Creates an instance of the servlet class
c.
Initializes the servlet instance by calling the init method (initialization is
covered in Creating and Initializing a Servlet)
The container invokes the service method, passing request and response objects.
Service methods are discussed in Writing Service Methods.
If it needs to remove the servlet, the container finalizes the servlet by calling the
servlet's destroy method. For more information, see Finalizing a Servlet.
17.2.1 Handling Servlet Lifecycle Events
You can monitor and react to events in a servlet's lifecycle by defining listener objects
whose methods get invoked when lifecycle events occur. To use these listener objects,
you must define and specify the listener class.
17.2.1.1 Defining the Listener Class
You define a listener class as an implementation of a listener interface. Table 17–1 lists
the events that can be monitored and the corresponding interface that must be
implemented. When a listener method is invoked, it is passed an event that contains
information appropriate to the event. For example, the methods in the
HttpSessionListener interface are passed an HttpSessionEvent, which contains an
HttpSession.
Table 17–1
Servlet Lifecycle Events
Object
Event
Listener Interface and Event Class
Web context
Initialization and
destruction
javax.servlet.ServletContextListener and
ServletContextEvent
Web context
Attribute added,
removed, or
replaced
javax.servlet.ServletContextAttributeListener and
ServletContextAttributeEvent
Session
Creation,
invalidation,
activation,
passivation, and
timeout
javax.servlet.http.HttpSessionListener,
javax.servlet.http.HttpSessionActivationListener,
and HttpSessionEvent
Session
Attribute added,
removed, or
replaced
javax.servlet.http.HttpSessionAttributeListener
and HttpSessionBindingEvent
17-2 The Java EE 7 Tutorial
Sharing Information
Table 17–1 (Cont.) Servlet Lifecycle Events
Object
Event
Listener Interface and Event Class
Request
A servlet request
has started being
processed by web
components
javax.servlet.ServletRequestListener and
ServletRequestEvent
Request
Attribute added,
removed, or
replaced
javax.servlet.ServletRequestAttributeListener and
ServletRequestAttributeEvent
Use the @WebListener annotation to define a listener to get events for various
operations on the particular web application context. Classes annotated with
@WebListener must implement one of the following interfaces:
javax.servlet.ServletContextListener
javax.servlet.ServletContextAttributeListener
javax.servlet.ServletRequestListener
javax.servlet.ServletRequestAttributeListener
javax.servlet..http.HttpSessionListener
javax.servlet..http.HttpSessionAttributeListener
For example, the following code snippet defines a listener that implements two of
these interfaces:
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener()
public class SimpleServletListener implements ServletContextListener,
ServletContextAttributeListener {
...
17.2.2 Handling Servlet Errors
Any number of exceptions can occur when a servlet executes. When an exception
occurs, the web container generates a default page containing the following message:
A Servlet Exception Has Occurred
But you can also specify that the container should return a specific error page for a
given exception.
17.3 Sharing Information
Web components, like most objects, usually work with other objects to accomplish
their tasks. Web components can do so by doing the following.
■
Using private helper objects (for example, JavaBeans components).
■
Sharing objects that are attributes of a public scope.
■
Using a database.
■
Invoking other web resources. The Java Servlet technology mechanisms that allow
a web component to invoke other web resources are described in Invoking Other
Web Resources.
Java Servlet Technology 17-3
Creating and Initializing a Servlet
17.3.1 Using Scope Objects
Collaborating web components share information by means of objects that are
maintained as attributes of four scope objects. You access these attributes by using the
getAttribute and setAttribute methods of the class representing the scope.
Table 17–2 lists the scope objects.
Table 17–2
Scope Objects
Scope
Object
Class
Accessible From
Web context
javax.servlet.ServletContext
Web components within a web context.
See Accessing the Web Context.
Session
javax.servlet.http.HttpSession
Web components handling a request that
belongs to the session. See Maintaining
Client State.
Request
Subtype of
javax.servlet.ServletRequest
Web components handling the request.
Page
javax.servlet.jsp.JspContext
The JSP page that creates the object.
17.3.2 Controlling Concurrent Access to Shared Resources
In a multithreaded server, shared resources can be accessed concurrently. In addition
to scope object attributes, shared resources include in-memory data, such as instance
or class variables, and external objects, such as files, database connections, and
network connections.
Concurrent access can arise in several situations.
■
Multiple web components accessing objects stored in the web context.
■
Multiple web components accessing objects stored in a session.
■
Multiple threads within a web component accessing instance variables. A web
container will typically create a thread to handle each request. To ensure that a
servlet instance handles only one request at a time, a servlet can implement the
SingleThreadModel interface. If a servlet implements this interface, no two threads
will execute concurrently in the servlet's service method. A web container can
implement this guarantee by synchronizing access to a single instance of the
servlet or by maintaining a pool of web component instances and dispatching each
new request to a free instance. This interface does not prevent synchronization
problems that result from web components' accessing shared resources, such as
static class variables or external objects.
When resources can be accessed concurrently, they can be used in an inconsistent
fashion. You prevent this by controlling the access using the synchronization
techniques described in the Threads lesson at
http://docs.oracle.com/javase/tutorial/essential/concurrency/.
17.4 Creating and Initializing a Servlet
Use the @WebServlet annotation to define a servlet component in a web application.
This annotation is specified on a class and contains metadata about the servlet being
declared. The annotated servlet must specify at least one URL pattern. This is done by
using the urlPatterns or value attribute on the annotation. All other attributes are
optional, with default settings. Use the value attribute when the only attribute on the
annotation is the URL pattern; otherwise, use the urlPatterns attribute when other
attributes are also used.
17-4 The Java EE 7 Tutorial
Writing Service Methods
Classes annotated with @WebServlet must extend the
javax.servlet.http.HttpServlet class. For example, the following code snippet
defines a servlet with the URL pattern /report:
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
@WebServlet("/report")
public class MoodServlet extends HttpServlet {
...
The web container initializes a servlet after loading and instantiating the servlet class
and before delivering requests from clients. To customize this process to allow the
servlet to read persistent configuration data, initialize resources, and perform any
other one-time activities, you can either override the init method of the Servlet
interface or specify the initParams attribute of the @WebServlet annotation. The
initParams attribute contains a @WebInitParam annotation. If it cannot complete its
initialization process, a servlet throws an UnavailableException.
Use an initialization parameter to provide data needed by a particular servlet. By
contrast, a context parameter provides data that is available to all components of a
web application.
17.5 Writing Service Methods
The service provided by a servlet is implemented in the service method of a
GenericServlet, in the doMethod methods (where Method can take the value Get,
Delete, Options, Post, Put, or Trace) of an HttpServlet object, or in any other
protocol-specific methods defined by a class that implements the Servlet interface.
The term service method is used for any method in a servlet class that provides a
service to a client.
The general pattern for a service method is to extract information from the request,
access external resources, and then populate the response, based on that information.
For HTTP servlets, the correct procedure for populating the response is to do the
following:
1.
Retrieve an output stream from the response.
2.
Fill in the response headers.
3.
Write any body content to the output stream.
Response headers must always be set before the response has been committed. The
web container will ignore any attempt to set or add headers after the response has
been committed. The next two sections describe how to get information from requests
and generate responses.
17.5.1 Getting Information from Requests
A request contains data passed between a client and the servlet. All requests
implement the ServletRequest interface. This interface defines methods for accessing
the following information:
■
■
Parameters, which are typically used to convey information between clients and
servlets
Object-valued attributes, which are typically used to pass information between the
web container and a servlet or between collaborating servlets
Java Servlet Technology 17-5
Writing Service Methods
■
■
Information about the protocol used to communicate the request and about the
client and server involved in the request
Information relevant to localization
You can also retrieve an input stream from the request and manually parse the data. To
read character data, use the BufferedReader object returned by the request's
getReader method. To read binary data, use the ServletInputStream returned by
getInputStream.
HTTP servlets are passed an HTTP request object, HttpServletRequest, which
contains the request URL, HTTP headers, query string, and so on. An HTTP request
URL contains the following parts:
http://[host]:[port][request-path]?[query-string]
The request path is further composed of the following elements.
■
■
■
Context path: A concatenation of a forward slash (/) with the context root of the
servlet's web application.
Servlet path: The path section that corresponds to the component alias that
activated this request. This path starts with a forward slash (/).
Path info: The part of the request path that is not part of the context path or the
servlet path.
You can use the getContextPath, getServletPath, and getPathInfo methods of the
HttpServletRequest interface to access this information. Except for URL encoding
differences between the request URI and the path parts, the request URI is always
comprised of the context path plus the servlet path plus the path info.
Query strings are composed of a set of parameters and values. Individual parameters
are retrieved from a request by using the getParameter method. There are two ways to
generate query strings.
■
■
A query string can explicitly appear in a web page.
A query string is appended to a URL when a form with a GET HTTP method is
submitted.
17.5.2 Constructing Responses
A response contains data passed between a server and the client. All responses
implement the ServletResponse interface. This interface defines methods that allow
you to do the following.
■
■
■
Retrieve an output stream to use to send data to the client. To send character data,
use the PrintWriter returned by the response's getWriter method. To send binary
data in a Multipurpose Internet Mail Extensions (MIME) body response, use the
ServletOutputStream returned by getOutputStream. To mix binary and text data,
as in a multipart response, use a ServletOutputStream and manage the character
sections manually.
Indicate the content type (for example, text/html) being returned by the response
with the setContentType(String) method. This method must be called before the
response is committed. A registry of content type names is kept by the Internet
Assigned Numbers Authority (IANA) at
http://www.iana.org/assignments/media-types/.
Indicate whether to buffer output with the setBufferSize(int) method. By
default, any content written to the output stream is immediately sent to the client.
17-6 The Java EE 7 Tutorial
Filtering Requests and Responses
Buffering allows content to be written before anything is sent back to the client,
thus providing the servlet with more time to set appropriate status codes and
headers or forward to another web resource. The method must be called before
any content is written or before the response is committed.
■
Set localization information, such as locale and character encoding. See
Chapter 20, "Internationalizing and Localizing Web Applications" for details.
HTTP response objects, javax.servlet.http.HttpServletResponse, have fields
representing HTTP headers, such as the following.
■
■
Status codes, which are used to indicate the reason a request is not satisfied or that
a request has been redirected.
Cookies, which are used to store application-specific information at the client.
Sometimes, cookies are used to maintain an identifier for tracking a user's session
(see Session Tracking).
17.6 Filtering Requests and Responses
A filter is an object that can transform the header and content (or both) of a request or
response. Filters differ from web components in that filters usually do not themselves
create a response. Instead, a filter provides functionality that can be "attached" to any
kind of web resource. Consequently, a filter should not have any dependencies on a
web resource for which it is acting as a filter; this way, it can be composed with more
than one type of web resource.
The main tasks that a filter can perform are as follows.
■
Query the request and act accordingly.
■
Block the request-and-response pair from passing any further.
■
■
■
Modify the request headers and data. You do this by providing a customized
version of the request.
Modify the response headers and data. You do this by providing a customized
version of the response.
Interact with external resources.
Applications of filters include authentication, logging, image conversion, data
compression, encryption, tokenizing streams, XML transformations, and so on.
You can configure a web resource to be filtered by a chain of zero, one, or more filters
in a specific order. This chain is specified when the web application containing the
component is deployed and is instantiated when a web container loads the
component.
17.6.1 Programming Filters
The filtering API is defined by the Filter, FilterChain, and FilterConfig interfaces
in the javax.servlet package. You define a filter by implementing the Filter
interface.
Use the @WebFilter annotation to define a filter in a web application. This annotation
is specified on a class and contains metadata about the filter being declared. The
annotated filter must specify at least one URL pattern. This is done by using the
urlPatterns or value attribute on the annotation. All other attributes are optional,
with default settings. Use the value attribute when the only attribute on the
Java Servlet Technology 17-7
Filtering Requests and Responses
annotation is the URL pattern; use the urlPatterns attribute when other attributes are
also used.
Classes annotated with the @WebFilter annotation must implement the
javax.servlet.Filter interface.
To add configuration data to the filter, specify the initParams attribute of the
@WebFilter annotation. The initParams attribute contains a @WebInitParam
annotation. The following code snippet defines a filter, specifying an initialization
parameter:
import javax.servlet.Filter;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
@WebFilter(filterName = "TimeOfDayFilter",
urlPatterns = {"/*"},
initParams = {
@WebInitParam(name = "mood", value = "awake")})
public class TimeOfDayFilter implements Filter {
...
The most important method in the Filter interface is doFilter, which is passed
request, response, and filter chain objects. This method can perform the following
actions.
■
Examine the request headers.
■
Customize the request object if the filter wishes to modify request headers or data.
■
■
Customize the response object if the filter wishes to modify response headers or
data.
Invoke the next entity in the filter chain. If the current filter is the last filter in the
chain that ends with the target web component or static resource, the next entity is
the resource at the end of the chain; otherwise, it is the next filter that was
configured in the WAR. The filter invokes the next entity by calling the doFilter
method on the chain object, passing in the request and response it was called with
or the wrapped versions it may have created. Alternatively, the filter can choose to
block the request by not making the call to invoke the next entity. In the latter case,
the filter is responsible for filling out the response.
■
Examine response headers after invoking the next filter in the chain.
■
Throw an exception to indicate an error in processing.
In addition to doFilter, you must implement the init and destroy methods. The
init method is called by the container when the filter is instantiated. If you wish to
pass initialization parameters to the filter, you retrieve them from the FilterConfig
object passed to init.
17.6.2 Programming Customized Requests and Responses
There are many ways for a filter to modify a request or a response. For example, a filter
can add an attribute to the request or can insert data in the response.
A filter that modifies a response must usually capture the response before it is
returned to the client. To do this, you pass a stand-in stream to the servlet that
generates the response. The stand-in stream prevents the servlet from closing the
original response stream when it completes and allows the filter to modify the servlet's
response.
17-8 The Java EE 7 Tutorial
Filtering Requests and Responses
To pass this stand-in stream to the servlet, the filter creates a response wrapper that
overrides the getWriter or getOutputStream method to return this stand-in stream.
The wrapper is passed to the doFilter method of the filter chain. Wrapper methods
default to calling through to the wrapped request or response object.
To override request methods, you wrap the request in an object that extends either
ServletRequestWrapper or HttpServletRequestWrapper. To override response
methods, you wrap the response in an object that extends either
ServletResponseWrapper or HttpServletResponseWrapper.
17.6.3 Specifying Filter Mappings
A web container uses filter mappings to decide how to apply filters to web resources.
A filter mapping matches a filter to a web component by name or to web resources by
URL pattern. The filters are invoked in the order in which filter mappings appear in
the filter mapping list of a WAR. You specify a filter mapping list for a WAR in its
deployment descriptor by either using NetBeans IDE or coding the list by hand with
XML.
If you want to log every request to a web application, you map the hit counter filter to
the URL pattern /*.
You can map a filter to one or more web resources, and you can map more than one
filter to a web resource. This is illustrated in Figure 17–1, in which filter F1 is mapped
to servlets S1, S2, and S3; filter F2 is mapped to servlet S2; and filter F3 is mapped to
servlets S1 and S2.
Figure 17–1 Filter-to-Servlet Mapping
F1
F3
S1
F2
S2
S3
Recall that a filter chain is one of the objects passed to the doFilter method of a filter.
This chain is formed indirectly by means of filter mappings. The order of the filters in
the chain is the same as the order in which filter mappings appear in the web
application deployment descriptor.
When a filter is mapped to servlet S1, the web container invokes the doFilter method
of F1. The doFilter method of each filter in S1's filter chain is invoked by the
preceding filter in the chain by means of the chain.doFilter method. Because S1's
filter chain contains filters F1 and F3, F1's call to chain.doFilter invokes the doFilter
method of filter F3. When F3's doFilter method completes, control returns to F1's
doFilter method.
17.6.3.1 To Specify Filter Mappings Using NetBeans IDE
1.
Expand the application's project node in the Project tab.
2.
Expand the Web Pages and WEB-INF nodes under the project node.
Java Servlet Technology 17-9
Invoking Other Web Resources
3.
Double-click web.xml.
4.
Click Filters at the top of the editor window.
5.
Expand the Servlet Filters node in the editor window.
6.
Click Add Filter Element to map the filter to a web resource by name or by URL
pattern.
7.
In the Add Servlet Filter dialog box, enter the name of the filter in the Filter Name
field.
8.
Click Browse to locate the servlet class to which the filter applies.
You can include wildcard characters so that you can apply the filter to more than
one servlet.
9.
Click OK.
10. To constrain how the filter is applied to requests, follow these steps.
a.
Expand the Filter Mappings node.
b.
Select the filter from the list of filters.
c.
Click Add.
d.
In the Add Filter Mapping dialog box, select one of the following dispatcher
types:
–
REQUEST: Only when the request comes directly from the client
–
ASYNC: Only when the asynchronous request comes from the client
–
FORWARD: Only when the request has been forwarded to a component
(see Transferring Control to Another Web Component)
–
INCLUDE: Only when the request is being processed by a component that
has been included (see Including Other Resources in the Response)
–
ERROR: Only when the request is being processed with the error page
mechanism (see Handling Servlet Errors)
You can direct the filter to be applied to any combination of the preceding
situations by selecting multiple dispatcher types. If no types are specified, the
default option is REQUEST.
17.7 Invoking Other Web Resources
Web components can invoke other web resources both indirectly and directly. A web
component indirectly invokes another web resource by embedding a URL that points
to another web component in content returned to a client. While it is executing, a web
component directly invokes another resource by either including the content of
another resource or forwarding a request to another resource.
To invoke a resource available on the server that is running a web component, you
must first obtain a RequestDispatcher object by using the
getRequestDispatcher("URL") method. You can get a RequestDispatcher object from
either a request or the web context; however, the two methods have slightly different
behavior. The method takes the path to the requested resource as an argument. A
request can take a relative path (that is, one that does not begin with a /), but the web
context requires an absolute path. If the resource is not available or if the server has
not implemented a RequestDispatcher object for that type of resource,
17-10 The Java EE 7 Tutorial
Accessing the Web Context
getRequestDispatcher will return null. Your servlet should be prepared to deal with
this condition.
17.7.1 Including Other Resources in the Response
It is often useful to include another web resource, such as banner content or copyright
information, in the response returned from a web component. To include another
resource, invoke the include method of a RequestDispatcher object:
include(request, response);
If the resource is static, the include method enables programmatic server-side
includes. If the resource is a web component, the effect of the method is to send the
request to the included web component, execute the web component, and then include
the result of the execution in the response from the containing servlet. An included
web component has access to the request object but is limited in what it can do with
the response object.
■
■
It can write to the body of the response and commit a response.
It cannot set headers or call any method, such as setCookie, that affects the
headers of the response.
17.7.2 Transferring Control to Another Web Component
In some applications, you might want to have one web component do preliminary
processing of a request and have another component generate the response. For
example, you might want to partially process a request and then transfer to another
component, depending on the nature of the request.
To transfer control to another web component, you invoke the forward method of a
RequestDispatcher. When a request is forwarded, the request URL is set to the path of
the forwarded page. The original URI and its constituent parts are saved as the
following request attributes:
javax.servlet.forward.request_uri
javax.servlet.forward.context_path
javax.servlet.forward.servlet_path
javax.servlet.forward.path_info
javax.servlet.forward.query_string
The forward method should be used to give another resource responsibility for
replying to the user. If you have already accessed a ServletOutputStream or
PrintWriter object within the servlet, you cannot use this method; doing so throws an
IllegalStateException.
17.8 Accessing the Web Context
The context in which web components execute is an object that implements the
ServletContext interface. You retrieve the web context by using the
getServletContext method. The web context provides methods for accessing
■
Initialization parameters
■
Resources associated with the web context
■
Object-valued attributes
■
Logging capabilities
Java Servlet Technology 17-11
Maintaining Client State
The counter's access methods are synchronized to prevent incompatible operations by
servlets that are running concurrently. A filter retrieves the counter object by using the
context's getAttribute method. The incremented value of the counter is recorded in
the log.
17.9 Maintaining Client State
Many applications require that a series of requests from a client be associated with one
another. For example, a web application can save the state of a user's shopping cart
across requests. Web-based applications are responsible for maintaining such state,
called a session, because HTTP is stateless. To support applications that need to
maintain state, Java Servlet technology provides an API for managing sessions and
allows several mechanisms for implementing sessions.
17.9.1 Accessing a Session
Sessions are represented by an HttpSession object. You access a session by calling the
getSession method of a request object. This method returns the current session
associated with this request; or, if the request does not have a session, this method
creates one.
17.9.2 Associating Objects with a Session
You can associate object-valued attributes with a session by name. Such attributes are
accessible by any web component that belongs to the same web context and is
handling a request that is part of the same session.
Recall that your application can notify web context and session listener objects of
servlet lifecycle events (Handling Servlet Lifecycle Events). You can also notify objects
of certain events related to their association with a session, such as the following.
■
■
When the object is added to or removed from a session. To receive this notification,
your object must implement the
javax.servlet.http.HttpSessionBindingListener interface.
When the session to which the object is attached will be passivated or activated. A
session will be passivated or activated when it is moved between virtual machines
or saved to and restored from persistent storage. To receive this notification, your
object must implement the
javax.servlet.http.HttpSessionActivationListener interface.
17.9.3 Session Management
Because an HTTP client has no way to signal that it no longer needs a session, each
session has an associated timeout so that its resources can be reclaimed. The timeout
period can be accessed by using a session's getMaxInactiveInterval and
setMaxInactiveInterval methods.
■
■
To ensure that an active session is not timed out, you should periodically access
the session by using service methods because this resets the session's time-to-live
counter.
When a particular client interaction is finished, you use the session's invalidate
method to invalidate a session on the server side and remove any session data.
17-12 The Java EE 7 Tutorial
Finalizing a Servlet
17.9.3.1 To Set the Timeout Period Using NetBeans IDE
To set the timeout period in the deployment descriptor using NetBeans IDE, follow
these steps.
1.
Open the project if you haven't already.
2.
Expand the node of your project in the Projects tab.
3.
Expand the Web Pages and WEB-INF nodes that are under the project node.
4.
Double-click web.xml.
5.
Click General at the top of the editor.
6.
In the Session Timeout field, enter an integer value.
The integer value represents the number of minutes of inactivity that must pass
before the session times out.
17.9.4 Session Tracking
To associate a session with a user, a web container can use several methods, all of
which involve passing an identifier between the client and the server. The identifier
can be maintained on the client as a cookie, or the web component can include the
identifier in every URL that is returned to the client.
If your application uses session objects, you must ensure that session tracking is
enabled by having the application rewrite URLs whenever the client turns off cookies.
You do this by calling the response's encodeURL(URL) method on all URLs returned by
a servlet. This method includes the session ID in the URL only if cookies are disabled;
otherwise, the method returns the URL unchanged.
17.10 Finalizing a Servlet
The web container may determine that a servlet should be removed from service (for
example, when a container wants to reclaim memory resources or when it is being
shut down). In such a case, the container calls the destroy method of the Servlet
interface. In this method, you release any resources the servlet is using and save any
persistent state. The destroy method releases the database object created in the init
method.
A servlet's service methods should all be complete when a servlet is removed. The
server tries to ensure this by calling the destroy method only after all service requests
have returned or after a server-specific grace period, whichever comes first. If your
servlet has operations that may run longer than the server's grace period, the
operations could still be running when destroy is called. You must make sure that any
threads still handling client requests complete.
The remainder of this section explains how to do the following.
■
■
■
Keep track of how many threads are currently running the service method.
Provide a clean shutdown by having the destroy method notify long-running
threads of the shutdown and wait for them to complete.
Have the long-running methods poll periodically to check for shutdown and, if
necessary, stop working, clean up, and return.
Java Servlet Technology 17-13
Finalizing a Servlet
17.10.1 Tracking Service Requests
To track service requests, include in your servlet class a field that counts the number of
service methods that are running. The field should have synchronized access methods
to increment, decrement, and return its value:
public class ShutdownExample extends HttpServlet {
private int serviceCounter = 0;
...
// Access methods for serviceCounter
protected synchronized void enteringServiceMethod() {
serviceCounter++;
}
protected synchronized void leavingServiceMethod() {
serviceCounter--;
}
protected synchronized int numServices() {
return serviceCounter;
}
}
The service method should increment the service counter each time the method is
entered and should decrement the counter each time the method returns. This is one of
the few times that your HttpServlet subclass should override the service method.
The new method should call super.service to preserve the functionality of the
original service method:
protected void service(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException,IOException {
enteringServiceMethod();
try {
super.service(req, resp);
} finally {
leavingServiceMethod();
}
}
17.10.2 Notifying Methods to Shut Down
To ensure a clean shutdown, your destroy method should not release any shared
resources until all the service requests have completed. One part of doing this is to
check the service counter. Another part is to notify long-running methods that it is
time to shut down. For this notification, another field is required. The field should
have the usual access methods:
public class ShutdownExample extends HttpServlet {
private boolean shuttingDown;
...
//Access methods for shuttingDown
protected synchronized void setShuttingDown(boolean flag) {
shuttingDown = flag;
}
protected synchronized boolean isShuttingDown() {
return shuttingDown;
}
}
Here is an example of the destroy method using these fields to provide a clean
shutdown:
17-14 The Java EE 7 Tutorial
Uploading Files with Java Servlet Technology
public
/*
/*
if
void destroy() {
Check to see whether there are still service methods /*
running, and if there are, tell them to stop. */
(numServices()> 0) {
setShuttingDown(true);
}
/* Wait for the service methods to stop. */
while (numServices()> 0) {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
}
}
}
17.10.3 Creating Polite Long-Running Methods
The final step in providing a clean shutdown is to make any long-running methods
behave politely. Methods that might run for a long time should check the value of the
field that notifies them of shutdowns and should interrupt their work, if necessary:
public void doPost(...) {
...
for(i = 0; ((i < lotsOfStuffToDo) &&
!isShuttingDown()); i++) {
try {
partOfLongRunningOperation(i);
} catch (InterruptedException e) {
...
}
}
}
17.11 Uploading Files with Java Servlet Technology
Supporting file uploads is a very basic and common requirement for many web
applications. In prior versions of the Servlet specification, implementing file upload
required the use of external libraries or complex input processing. The Java Servlet
specification now helps to provide a viable solution to the problem in a generic and
portable way. Java Servlet technology now supports file upload out of the box, so any
web container that implements the specification can parse multipart requests and
make mime attachments available through the HttpServletRequest object.
A new annotation, javax.servlet.annotation.MultipartConfig, is used to indicate
that the servlet on which it is declared expects requests to be made using the
multipart/form-data MIME type. Servlets that are annotated with @MultipartConfig
can retrieve the Part components of a given multipart/form-data request by calling
the request.getPart(String name) or request.getParts() method.
17.11.1 The @MultipartConfig Annotation
The @MultipartConfig annotation supports the following optional attributes.
■
location: An absolute path to a directory on the file system. The location
attribute does not support a path relative to the application context. This location
is used to store files temporarily while the parts are processed or when the size of
the file exceeds the specified fileSizeThreshold setting. The default location is
"".
Java Servlet Technology 17-15
Asynchronous Processing
■
■
■
fileSizeThreshold: The file size in bytes after which the file will be temporarily
stored on disk. The default size is 0 bytes.
MaxFileSize: The maximum size allowed for uploaded files, in bytes. If the size of
any uploaded file is greater than this size, the web container will throw an
exception (IllegalStateException). The default size is unlimited.
maxRequestSize: The maximum size allowed for a multipart/form-data request,
in bytes. The web container will throw an exception if the overall size of all
uploaded files exceeds this threshold. The default size is unlimited.
For, example, the @MultipartConfig annotation could be constructed as follows:
@MultipartConfig(location="/tmp", fileSizeThreshold=1024*1024,
maxFileSize=1024*1024*5, maxRequestSize=1024*1024*5*5)
Instead of using the @MultipartConfig annotation to hard-code these attributes in
your file upload servlet, you could add the following as a child element of the servlet
configuration element in the web.xml file:
<multipart-config>
<location>/tmp</location>
<max-file-size>20848820</max-file-size>
<max-request-size>418018841</max-request-size>
<file-size-threshold>1048576</file-size-threshold>
</multipart-config>
17.11.2 The getParts and getPart Methods
The Servlet specification supports two additional HttpServletRequest methods:
■
Collection<Part> getParts()
■
Part getPart(String name)
The request.getParts() method returns collections of all Part objects. If you have
more than one input of type file, multiple Part objects are returned. Because Part
objects are named, the getPart(String name) method can be used to access a
particular Part. Alternatively, the getParts() method, which returns an
Iterable<Part>, can be used to get an Iterator over all the Part objects.
The javax.servlet.http.Part interface is a simple one, providing methods that allow
introspection of each Part. The methods do the following:
■
Retrieve the name, size, and content-type of the Part
■
Query the headers submitted with a Part
■
Delete a Part
■
Write a Part out to disk
For example, the Part interface provides the write(String filename) method to
write the file with the specified name. The file can then be saved in the directory that is
specified with the location attribute of the @MultipartConfig annotation or, in the
case of the fileupload example, in the location specified by the Destination field in the
form.
17.12 Asynchronous Processing
Web containers in application servers normally use a server thread per client request.
Under heavy load conditions, containers need a large amount of threads to serve all
the client requests. Scalability limitations include running out of memory or
17-16 The Java EE 7 Tutorial
Asynchronous Processing
exhausting the pool of container threads. To create scalable web applications, you must
ensure that no threads associated with a request are sitting idle, so the container can
use them to process new requests.
There are two common scenarios in which a thread associated with a request can be
sitting idle.
■
■
The thread needs to wait for a resource to become available or process data before
building the response. For example, an application may need to query a database
or access data from a remote web service before generating the response.
The thread needs to wait for an event before generating the response. For example,
an application may have to wait for a JMS message, new information from another
client, or new data available in a queue before generating the response.
These scenarios represent blocking operations that limit the scalability of web
applications. Asynchronous processing refers to assigning these blocking operations to
a new thread and retuning the thread associated with the request immediately to the
container.
17.12.1 Asynchronous Processing in Servlets
Java EE provides asynchronous processing support for servlets and filters. If a servlet
or a filter reaches a potentially blocking operation when processing a request, it can
assign the operation to an asynchronous execution context and return the thread
associated with the request immediately to the container without generating a
response. The blocking operation completes in the asynchronous execution context in
a different thread, which can generate a response or dispatch the request to another
servlet.
To enable asynchronous processing on a servlet, set the parameter asyncSupported to
true on the @WebServlet annotation as follows:
@WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true)
public class AsyncServlet extends HttpServlet { ... }
The javax.servlet.AsyncContext class provides the functionality that you need to
perform asynchronous processing inside service methods. To obtain an instance of
AsyncContext, call the startAsync() method on the request object of your service
method; for example:
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
...
AsyncContext acontext = req.startAsync();
...
}
This call puts the request into asynchronous mode and ensures that the response is not
committed after exiting the service method. You have to generate the response in the
asynchronous context after the blocking operation completes or dispatch the request to
another servlet.
Table 17–3 describes the basic functionality provided by the AsyncContext class.
Java Servlet Technology 17-17
Asynchronous Processing
Table 17–3
Functionality Provided by the AsyncContext Class
Method Signature
Description
void start(Runnable run)
The container provides a different thread in which the
blocking operation can be processed.
You provide code for the blocking operation as a class that
implements the Runnable interface. You can provide this
class as an inner class when calling the start method or
use another mechanism to pass the AsyncContext instance
to your class.
ServletRequest getRequest()
Returns the request used to initialize this asynchronous
context. In the example above, the request is the same as
in the service method.
You can use this method inside the asynchronous context
to obtain parameters from the request.
ServletResponse getResponse()
Returns the response used to initialize this asynchronous
context. In the example above, the response is the same as
in the service method.
You can use this method inside the asynchronous context
to write to the response with the results of the blocking
operation.
void complete()
Completes the asynchronous operation and closes the
response associated with this asynchronous context.
You call this method after writing to the response object
inside the asynchronous context.
void dispatch(String path)
Dispatches the request and response objects to the given
path.
You use this method to have another servlet write to the
response after the blocking operation completes.
17.12.2 Waiting for a Resource
This section demonstrates how to use the functionality provided by the AsyncContext
class for the following use case:
1.
A servlet receives a parameter from a GET request.
2.
The servlet uses a resource, such as a database or a web service, to retrieve
information based on the value of the parameter. The resource can be slow at
times, so this may be a blocking operation.
3.
The servlet generates a response using the result from the resource.
The following code shows a basic servlet that does not use asynchronous processing:
@WebServlet(urlPatterns={"/syncservlet"})
public class SyncServlet extends HttpServlet {
private MyRemoteResource resource;
@Override
public void init(ServletConfig config) {
resource = MyRemoteResource.create("config1=x,config2=y");
}
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response) {
response.setContentType("text/html;charset=UTF-8");
String param = request.getParameter("param");
String result = resource.process(param);
17-18 The Java EE 7 Tutorial
Nonblocking I/O
/* ... print to the response ... */
}
}
The following code shows the same servlet using asynchronous processing:
@WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true)
public class AsyncServlet extends HttpServlet {
/* ... Same variables and init method as in SyncServlet ... */
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response) {
response.setContentType("text/html;charset=UTF-8");
final AsyncContext acontext = request.startAsync();
acontext.start(new Runnable() {
public void run() {
String param = acontext.getRequest().getParameter("param");
String result = resource.process(param);
HttpServletResponse response = acontext.getResponse();
/* ... print to the response ... */
acontext.complete();
}
}
AsyncServlet adds asyncSupported=true to the @WebServlet annotation. The rest of
the differences are inside the service method.
■
■
■
request.startAsync() causes the request to be processed asynchronously; the
response is not sent to the client at the end of the service method.
acontext.start(new Runnable() {...}) gets a new thread from the container.
The code inside the run() method of the inner class executes in the new thread.
The inner class has access to the asynchronous context to read parameters from the
request and write to the response. Calling the complete() method of the
asynchronous context commits the response and sends it to the client.
The service method of AsyncServlet returns immediately, and the request is processed
in the asynchronous context.
17.13 Nonblocking I/O
Web containers in application servers normally use a server thread per client request.
To develop scalable web applications, you must ensure that threads associated with
client requests are never sitting idle waiting for a blocking operation to complete.
Asynchronous Processing provides a mechanism to execute application-specific
blocking operations in a new thread, returning the thread associated with the request
immediately to the container. Even if you use asynchronous processing for all the
application-specific blocking operations inside your service methods, threads
associated with client requests can be momentarily sitting idle because of
input/output considerations.
For example, if a client is submitting a large HTTP POST request over a slow network
connection, the server can read the request faster than the client can provide it. Using
traditional I/O, the container thread associated with this request would be sometimes
sitting idle waiting for the rest of the request.
Java Servlet Technology 17-19
Nonblocking I/O
Java EE provides nonblocking I/O support for servlets and filters when processing
requests in asynchronous mode. The following steps summarize how to use
nonblocking I/O to process requests and write responses inside service methods.
1.
Put the request in asynchronous mode as described in Asynchronous Processing.
2.
Obtain an input stream and/or an output stream from the request and response
objects in the service method.
3.
Assign a read listener to the input stream and/or a write listener to the output
stream.
4.
Process the request and the response inside the listener's callback methods.
Table 17–4 and Table 17–5 describe the methods available in the servlet input and
output streams for nonblocking I/O support. Table 17–6 describes the interfaces for
read listeners and write listeners.
Table 17–4
Nonblocking I/O Support in javax.servlet.ServletInputStream
Method
Description
void setReadListener(ReadListener rl)
Associates this input stream with a listener
object that contains callback methods to read
data asynchronously. You provide the listener
object as an anonymous class or use another
mechanism to pass the input stream to the
read listener object.
boolean isReady()
Returns true if data can be read without
blocking.
boolean isFinished()
Returns true when all the data has been read.
Table 17–5
Nonblocking I/O Support in javax.servlet.ServletOutputStream
Method
Description
void setWriteListener(WriteListener wl)
Associates this output stream with a listener
object that contains callback methods to write
data asynchronously. You provide the write
listener object as an anonymous class or use
another mechanism to pass the output stream
to the write listener object.
boolean isReady()
Returns true if data can be written without
blocking.
Table 17–6
Listener Interfaces for Nonblocking I/O Support
Interface
Methods
Description
ReadListener
void onDataAvailable()
A ServletInputStream instance calls these
methods on its listener when there is data
available to read, when all the data has been
read, or when there is an error.
void onAllDataRead()
void onError(Throwable t)
WriteListener
void onWritePossible()
void onError(Throwable t)
17-20 The Java EE 7 Tutorial
A ServletOutputStream instance calls these
methods on its listener when it is possible to
write data without blocking or when there is
an error.
Protocol Upgrade Processing
17.13.1 Reading a Large HTTP POST Request Using Nonblocking I/O
The code in this section shows how to read a large HTTP POST request inside a servlet
by putting the request in asynchronous mode (as described in Asynchronous
Processing) and using the nonblocking I/O functionality from Table 17–4 and
Table 17–6.
@WebServlet(urlPatterns={"/asyncioservlet"}, asyncSupported=true)
public class AsyncIOServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException {
final AsyncContext acontext = request.startAsync();
final ServletInputStream input = request.getInputStream();
input.setReadListener(new ReadListener() {
byte buffer[] = new byte[4*1024];
StringBuilder sbuilder = new StringBuilder();
@Override
public void onDataAvailable() {
try {
do {
int length = input.read(buffer);
sbuilder.append(new String(buffer, 0, length));
} while(input.isReady());
} catch (IOException ex) { ... }
}
@Override
public void onAllDataRead() {
try {
acontext.getResponse().getWriter()
.write("...the response...");
} catch (IOException ex) { ... }
acontext.complete();
}
@Override
public void onError(Throwable t) { ... }
});
}
}
This example declares the web servlet with asynchronous support using the
@WebServlet annotation parameter asyncSupported=true. The service method first
puts the request in asynchronous mode by calling the startAsync() method of the
request object, which is required in order to use nonblocking I/O. Then, the service
method obtains an input stream associated with the request and assigns a read listener
defined as an inner class. The listener reads parts of the request as they become
available and then writes some response to the client when it finishes reading the
request.
17.14 Protocol Upgrade Processing
In HTTP/1.1, clients can request to switch to a different protocol on the current
connection by using the Upgrade header field. If the server accepts the request to
switch to the protocol indicated by the client, it generates an HTTP response with
status 101 (switching protocols). After this exchange, the client and the server
communicate using the new protocol.
Java Servlet Technology 17-21
Protocol Upgrade Processing
For example, a client can make an HTTP request to switch to the XYZP protocol as
follows:
GET /xyzpresource HTTP/1.1
Host: localhost:8080
Accept: text/html
Upgrade: XYZP
Connection: Upgrade
OtherHeaderA: Value
The client can specify parameters for the new protocol using HTTP headers. The
server can accept the request and generate a response as follows:
HTTP/1.1 101 Switching Protocols
Upgrade: XYZP
Connection: Upgrade
OtherHeaderB: Value
(XYZP data)
Java EE supports the HTTP protocol upgrade functionality in servlets, as described in
Table 17–7.
Table 17–7
Protocol Upgrade Support
Class or Interface
Method
HttpServletRequest
HttpUpgradeHandler upgrade(Class handler)
The upgrade method starts the protocol upgrade processing.
This method instantiates a class that implements the
HttpUpgradeHandler interface and delegates the connection to it.
You call the upgrade method inside a service method when
accepting a request from a client to switch protocols.
HttpUpgradeHandler
void init(WebConnection wc)
The init method is called when the servlet accepts the request
to switch protocols. You implement this method and obtain
input and output streams from the WebConnection object to
implement the new protocol.
HttpUpgradeHandler
void destroy()
The destroy method is called when the client disconnects. You
implement this method and free any resources associated with
processing the new protocol.
WebConnection
ServletInputStream getInputStream()
The getInputStream method provides access to the input stream
of the connection. You can use Nonblocking I/O with the
returned stream to implement the new protocol.
WebConnection
ServletOutputStream getOutputStream()
The getOutputStream method provides access to the output
stream of the connection. You can use Nonblocking I/O with the
returned stream to implement the new protocol.
The following code demonstrates how to accept an HTTP protocol upgrade request
from a client:
@WebServlet(urlPatterns={"/xyzpresource"})
public class XYZPUpgradeServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request,
17-22 The Java EE 7 Tutorial
The mood Example Application
HttpServletResponse response) {
if ("XYZP".equals(request.getHeader("Upgrade"))) {
/* Accept upgrade request */
response.setStatus(101);
response.setHeader("Upgrade", "XYZP");
response.setHeader("Connection", "Upgrade");
response.setHeader("OtherHeaderB", "Value");
/* Delegate the connection to the upgrade handler */
XYZPUpgradeHandler = request.upgrade(XYZPUpgradeHandler.class);
/* (the service method returns immedately) */
} else {
/* ... write error response ... */
}
}
}
The XYZPUpgradeHandler class handles the connection:
public class XYZPUpgradeHandler implements HttpUpgradeHandler {
@Override
public void init(WebConnection wc) {
ServletInputStream input = wc.getInputStream();
ServletOutputStream output = wc.getOutputStream();
/* ... implement XYZP using these streams (protocol-specific) ... */
}
@Override
public void destroy() { ... }
}
The class that implements HttpUpgradeHandler uses the streams from the current
connection to communicate with the client using the new protocol. See the Servlet 3.1
specification at http://jcp.org/en/jsr/detail?id=340 for details on HTTP
protocol upgrade support.
17.15 The mood Example Application
The mood example application, located in the tut-install/examples/web/servlet/mood/
directory, is a simple example that displays Duke's moods at different times during the
day. The example shows how to develop a simple application by using the
@WebServlet, @WebFilter, and @WebListener annotations to create a servlet, a listener,
and a filter.
17.15.1 Components of the mood Example Application
The mood example application is comprised of three components:
mood.web.MoodServlet, mood.web.TimeOfDayFilter, and
mood.web.SimpleServletListener.
MoodServlet, the presentation layer of the application, displays Duke's mood in a
graphic, based on the time of day. The @WebServlet annotation specifies the URL
pattern:
@WebServlet("/report")
public class MoodServlet extends HttpServlet {
...
TimeOfDayFilter sets an initialization parameter indicating that Duke is awake:
@WebFilter(filterName = "TimeOfDayFilter",
urlPatterns = {"/*"},
Java Servlet Technology 17-23
The mood Example Application
initParams = {
@WebInitParam(name = "mood", value = "awake")})
public class TimeOfDayFilter implements Filter {
...
The filter calls the doFilter method, which contains a switch statement that sets
Duke's mood based on the current time.
SimpleServletListener logs changes in the servlet's lifecycle. The log entries appear
in the server log.
17.15.2 Running the mood Example
You can use either NetBeans
mood example.
IDE or Maven to build, package, deploy, and run the
17.15.2.1 To Run the mood Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/servlet
4.
Select the mood folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the mood project and select Build.
7.
In a web browser, enter the following URL:
http://localhost:8080/mood/report
The URL specifies the context root, followed by the URL pattern.
A web page appears with the title "Servlet MoodServlet at /mood", a text string
describing Duke's mood, and an illustrative graphic.
17.15.2.2 To Run the mood Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/servlet/mood/
3.
Enter the following command to deploy the application:
mvn install
4.
In a web browser, enter the following URL:
http://localhost:8080/mood/report
The URL specifies the context root, followed by the URL pattern.
A web page appears with the title "Servlet MoodServlet at /mood", a text string
describing Duke's mood, and an illustrative graphic.
17-24 The Java EE 7 Tutorial
The fileupload Example Application
17.16 The fileupload Example Application
The fileupload example, located in the
tut-install/examples/web/servlet/fileupload/ directory, illustrates how to
implement and use the file upload feature.
The Duke's Forest case study provides a more complex example that uploads an image
file and stores its content in a database.
17.16.1 Architecture of the fileupload Example Application
The fileupload example application consists of a single servlet and an HTML form
that makes a file upload request to the servlet.
This example includes a very simple HTML form with two fields, File and Destination.
The input type, file, enables a user to browse the local file system to select the file.
When the file is selected, it is sent to the server as a part of a POST request. During this
process, two mandatory restrictions are applied to the form with input type file.
■
The enctype attribute must be set to a value of multipart/form-data.
■
Its method must be POST.
When the form is specified in this manner, the entire request is sent to the server in
encoded form. The servlet then uses its own means to handle the request to process the
incoming file data and extract a file from the stream. The destination is the path to the
location where the file will be saved on your computer. Pressing the Upload button at
the bottom of the form posts the data to the servlet, which saves the file in the
specified destination.
The HTML form in index.html is as follows:
<!DOCTYPE html>
<html lang="en">
<head>
<title>File Upload</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<form method="POST" action="upload" enctype="multipart/form-data" >
File:
<input type="file" name="file" id="file" /> <br/>
Destination:
<input type="text" value="/tmp" name="destination"/>
</br>
<input type="submit" value="Upload" name="upload" id="upload" />
</form>
</body>
</html>
A POST request method is used when the client needs to send data to the server as
part of the request, such as when uploading a file or submitting a completed form. In
contrast, a GET request method sends a URL and headers only to the server, whereas
POST requests also include a message body. This allows arbitrary length data of any
type to be sent to the server. A header field in the POST request usually indicates the
message body's Internet media type.
When submitting a form, the browser streams the content in, combining all parts, with
each part representing a field of a form. Parts are named after the input elements and
are separated from each other with string delimiters named boundary.
Java Servlet Technology 17-25
The fileupload Example Application
This is what submitted data from the fileupload form looks like, after selecting
sample.txt as the file that will be uploaded to the tmp directory on the local file
system:
POST /fileupload/upload HTTP/1.1
Host: localhost:8080
Content-Type: multipart/form-data;
boundary=---------------------------263081694432439
Content-Length: 441
-----------------------------263081694432439
Content-Disposition: form-data; name="file"; filename="sample.txt"
Content-Type: text/plain
Data from sample file
-----------------------------263081694432439
Content-Disposition: form-data; name="destination"
/tmp
-----------------------------263081694432439
Content-Disposition: form-data; name="upload"
Upload
-----------------------------263081694432439--
The servlet FileUploadServlet.java begins as follows:
@WebServlet(name = "FileUploadServlet", urlPatterns = {"/upload"})
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
private final static Logger LOGGER =
Logger.getLogger(FileUploadServlet.class.getCanonicalName());
The @WebServlet annotation uses the urlPatterns property to define servlet
mappings.
The @MultipartConfig annotation indicates that the servlet expects requests to be
made using the multipart/form-data MIME type.
The processRequest method retrieves the destination and file part from the request,
then calls the getFileName method to retrieve the file name from the file part. The
method then creates a FileOutputStream and copies the file to the specified
destination. The error-handling section of the method catches and handles some of the
most common reasons why a file would not be found. The processRequest and
getFileName methods look like this:
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// Create path components to save the file
final String path = request.getParameter("destination");
final Part filePart = request.getPart("file");
final String fileName = getFileName(filePart);
OutputStream out = null;
InputStream filecontent = null;
final PrintWriter writer = response.getWriter();
try {
out = new FileOutputStream(new File(path + File.separator
17-26 The Java EE 7 Tutorial
The fileupload Example Application
+ fileName));
filecontent = filePart.getInputStream();
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = filecontent.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
writer.println("New file " + fileName + " created at " + path);
LOGGER.log(Level.INFO, "File{0}being uploaded to {1}",
new Object[]{fileName, path});
} catch (FileNotFoundException fne) {
writer.println("You either did not specify a file to upload or are "
+ "trying to upload a file to a protected or nonexistent "
+ "location.");
writer.println("<br/> ERROR: " + fne.getMessage());
LOGGER.log(Level.SEVERE, "Problems during file upload. Error: {0}",
new Object[]{fne.getMessage()});
} finally {
if (out != null) {
out.close();
}
if (filecontent != null) {
filecontent.close();
}
if (writer != null) {
writer.close();
}
}
}
private String getFileName(final Part part) {
final String partHeader = part.getHeader("content-disposition");
LOGGER.log(Level.INFO, "Part Header = {0}", partHeader);
for (String content : part.getHeader("content-disposition").split(";")) {
if (content.trim().startsWith("filename")) {
return content.substring(
content.indexOf('=') + 1).trim().replace("\"", "");
}
}
return null;
}
17.16.2 Running the fileupload Example
You can use either NetBeans
fileupload example.
IDE or Maven to build, package, deploy, and run the
17.16.2.1 To Build, Package, and Deploy the fileupload Example Using NetBeans
IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/servlet
Java Servlet Technology 17-27
The dukeetf Example Application
4.
Select the fileupload folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the fileupload project and select Build.
17.16.2.2 To Build, Package, and Deploy the fileupload Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/servlet/fileupload/
3.
Enter the following command to deploy the application:
mvn install
17.16.2.3 To Run the fileupload Example
1.
In a web browser, enter the following URL:
http://localhost:8080/fileupload/
2.
On the File Upload page, click Choose File to display a file browser window.
3.
Select a file to upload and click Open.
The name of the file you selected is displayed in the File field. If you do not select
a file, an exception will be thrown.
4.
In the Destination field, type a directory name.
The directory must have already been created and must also be writable. If you do
not enter a directory name or if you enter the name of a nonexistent or protected
directory, an exception will be thrown.
5.
Click Upload to upload the file that you selected to the directory that you
specified in the Destination field.
A message reports that the file was created in the directory that you specified.
6.
Go to the directory that you specified in the Destination field and verify that the
uploaded file is present.
17.17 The dukeetf Example Application
The dukeetf example application, located in the tut-install/examples/web/dukeetf/
directory, demonstrates how to use asynchronous processing in a servlet to provide
data updates to web clients. The example resembles a service that provides periodic
updates on the price and trading volume of an electronically traded fund (ETF).
17.17.1 Architecture of the dukeetf Example Application
The dukeetf example application consists of a servlet, an enterprise bean, and an
HTML page.
■
■
The servlet puts requests in asynchronous mode, stores them in a queue, and
writes the responses when new data for price and trading volume becomes
available.
The enterprise bean updates the price and volume information once every second.
17-28 The Java EE 7 Tutorial
The dukeetf Example Application
■
The HTML page uses JavaScript code to make requests to the servlet for new data,
parse the response from the servlet, and update the price and volume information
without reloading the page.
The dukeetf example application uses a programming model known as long polling.
In the traditional HTTP request and response model, the user must make an explicit
request (such as clicking a link or submitting a form) to get any new information from
the server, and the page has to be reloaded. Long polling provides a mechanism for
web applications to push updates to clients using HTTP without the user making an
explicit request. The server handles connections asynchronously, and the client uses
JavaScript to make new connections. In this model, clients make a new request
immediately after receiving new data, and the server keeps the connection open until
new data becomes available.
17.17.1.1 The Servlet
The DukeETFServlet class uses asynchronous processing:
@WebServlet(urlPatterns={"/dukeetf"}, asyncSupported=true)
public class DukeETFServlet extends HttpServlet {
...
}
In the following code, the init method initializes a queue to hold client requests and
registers the servlet with the enterprise bean that provides the price and volume
updates. The send method gets called once per second by the PriceVolumeBean to send
updates and close the connection:
@Override
public void init(ServletConfig config) {
/* Queue for requests */
requestQueue = new ConcurrentLinkedQueue<>();
/* Register with the enterprise bean that provides price/volume updates */
pvbean.registerServlet(this);
}
/* PriceVolumeBean calls this method every second to send updates */
public void send(double price, int volume) {
/* Send update to all connected clients */
for (AsyncContext acontext : requestQueue) {
try {
String msg = String.format("%.2f / %d", price, volume);
PrintWriter writer = acontext.getResponse().getWriter();
writer.write(msg);
logger.log(Level.INFO, "Sent: {0}", msg);
/* Close the connection
* The client (JavaScript) makes a new one instantly */
acontext.complete();
} catch (IOException ex) {
logger.log(Level.INFO, ex.toString());
}
}
}
The service method puts client requests in asynchronous mode and adds a listener to
each request. The listener is implemented as an anonymous class that removes the
request from the queue when the servlet finishes writing a response or when there is
an error. Finally, the service method adds the request to the request queue created in
the init method. The service method is the following:
Java Servlet Technology 17-29
The dukeetf Example Application
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response) {
response.setContentType("text/html");
/* Put request in async mode */
final AsyncContext acontext = request.startAsync();
/* Remove from the queue when done */
acontext.addListener(new AsyncListener() {
public void onComplete(AsyncEvent ae) throws IOException {
requestQueue.remove(acontext);
}
public void onTimeout(AsyncEvent ae) throws IOException {
requestQueue.remove(acontext);
}
public void onError(AsyncEvent ae) throws IOException {
requestQueue.remove(acontext);
}
public void onStartAsync(AsyncEvent ae) throws IOException {}
});
/* Add to the queue */
requestQueue.add(acontext);
}
17.17.1.2 The Enterprise Bean
The PriceVolumeBean class is an enterprise bean that uses the timer service from the
container to update the price and volume information and call the servlet's send
method once every second:
@Startup
@Singleton
public class PriceVolumeBean {
/* Use the container's timer service */
@Resource TimerService tservice;
private DukeETFServlet servlet;
...
@PostConstruct
public void init() {
/* Initialize the EJB and create a timer */
random = new Random();
servlet = null;
tservice.createIntervalTimer(1000, 1000, new TimerConfig());
}
public void registerServlet(DukeETFServlet servlet) {
/* Associate a servlet to send updates to */
this.servlet = servlet;
}
@Timeout
public void timeout() {
/* Adjust price and volume and send updates */
price += 1.0*(random.nextInt(100)-50)/100.0;
volume += random.nextInt(5000) - 2500;
if (servlet != null)
servlet.send(price, volume);
}
}
17-30 The Java EE 7 Tutorial
The dukeetf Example Application
See Using the Timer Service in Chapter 34, "Running the Enterprise Bean Examples"
for more information on the timer service.
17.17.1.3 The HTML Page
The HTML page consists of a table and some JavaScript code. The table contains two
fields referenced from JavaScript code:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>...</head>
<body onload="makeAjaxRequest();">
...
<table>
...
<td id="price">--.--</td>
...
<td id="volume">--</td>
...
</table>
</body>
</html>
The JavaScript code uses the XMLHttpRequest API, which provides functionality for
transferring data between a client and a server. The script makes an asynchronous
request to the servlet and designates a callback method. When the server provides a
response, the callback method updates the fields in the table and makes a new request.
The JavaScript code is the following:
var ajaxRequest;
function updatePage() {
if (ajaxRequest.readyState === 4) {
var arraypv = ajaxRequest.responseText.split("/");
document.getElementById("price").innerHTML = arraypv[0];
document.getElementById("volume").innerHTML = arraypv[1];
makeAjaxRequest();
}
}
function makeAjaxRequest() {
ajaxRequest = new XMLHttpRequest();
ajaxRequest.onreadystatechange = updatePage;
ajaxRequest.open("GET", "http://localhost:8080/dukeetf/dukeetf",
true);
ajaxRequest.send(null);
}
The XMLHttpRequest API is supported by most modern browsers, and it is widely
used in Ajax web client development (Asynchronous JavaScript and XML).
See The dukeetf2 Example Application in Chapter 18, "Java API for WebSocket" for an
equivalent version of this example implemented using a WebSocket endpoint.
17.17.2 Running the dukeetf Example Application
This section describes how to run the dukeetf example application using NetBeans
IDE and from the command line.
17.17.2.1 To Run the dukeetf Example Application Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
Java Servlet Technology 17-31
Further Information about Java Servlet Technology
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/servlet
4.
Select the dukeetf folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the dukeetf project and select Run.
This command builds and packages the application into a WAR file (dukeetf.war)
located in the target directory, deploys it to the server, and launches a web
browser window with the following URL:
http://localhost:8080/dukeetf/
Open the same URL in a different web browser to see how both pages get price
and volume updates simultaneously.
17.17.2.2 To Run the dukeetf Example Application Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/servlet/dukeetf/
3.
Enter the following command to deploy the application:
mvn install
4.
Open a web browser window and type the following address:
http://localhost:8080/dukeetf/
Open the same URL in a different web browser to see how both pages get price
and volume updates simultaneously.
17.18 Further Information about Java Servlet Technology
For more information on Java Servlet technology, see the Java Servlet 3.1 specification
at http://jcp.org/en/jsr/detail?id=340.
17-32 The Java EE 7 Tutorial
18
Java API for WebSocket
18
This chapter describes the Java API for WebSocket (JSR 356), which provides support
for creating WebSocket applications. WebSocket is an application protocol that
provides full-duplex communications between two peers over the TCP protocol.
In the traditional request-response model used in HTTP, the client requests resources,
and the server provides responses. The exchange is always initiated by the client; the
server cannot send any data without the client requesting it first. This model worked
well for the World Wide Web when clients made occasional requests for documents
that changed infrequently, but the limitations of this approach are increasingly
relevant as content changes quickly and users expect a more interactive experience on
the Web. The WebSocket protocol addresses these limitations by providing a
full-duplex communication channel between the client and the server. Combined with
other client technologies, such as JavaScript and HTML5, WebSocket enables web
applications to deliver a richer user experience.
The following topics are addressed here:
■
Introduction to WebSocket
■
Creating WebSocket Applications in the Java EE Platform
■
Programmatic Endpoints
■
Annotated Endpoints
■
Sending and Receiving Messages
■
Maintaining Client State
■
Using Encoders and Decoders
■
Path Parameters
■
Handling Errors
■
Specifying an Endpoint Configurator Class
■
The dukeetf2 Example Application
■
The websocketbot Example Application
■
Further Information about WebSocket
18.1 Introduction to WebSocket
In a WebSocket application, the server publishes a WebSocket endpoint, and the client
uses the endpoint's URI to connect to the server. The WebSocket protocol is
symmetrical after the connection has been established; the client and the server can
send messages to each other at any time while the connection is open, and they can
Java API for WebSocket 18-1
Creating WebSocket Applications in the Java EE Platform
close the connection at any time. Clients usually connect only to one server, and
servers accept connections from multiple clients.
The WebSocket protocol has two parts: handshake and data transfer. The client
initiates the handshake by sending a request to a WebSocket endpoint using its URI.
The handshake is compatible with existing HTTP-based infrastructure: web servers
interpret it as an HTTP connection upgrade request. An example handshake from a
client looks like this:
GET /path/to/websocket/endpoint HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
Origin: http://localhost
Sec-WebSocket-Version: 13
An example handshake from the server in response to the client looks like this:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
The server applies a known operation to the value of the Sec-WebSocket-Key header to
generate the value of the Sec-WebSocket-Accept header. The client applies the same
operation to the value of the Sec-WebSocket-Key header, and the connection is
established successfully if the result matches the value received from the server. The
client and the server can send messages to each other after a successful handshake.
WebSocket supports text messages (encoded as UTF-8) and binary messages. The
control frames in WebSocket are close, ping, and pong (a response to a ping frame). Ping
and pong frames may also contain application data.
WebSocket endpoints are represented by URIs that have the following form:
ws://host:port/path?query
wss://host:port/path?query
The ws scheme represents an unencrypted WebSocket connection, and the wss scheme
represents an encrypted connection. The port component is optional; the default port
number is 80 for unencrypted connections and 443 for encrypted connections. The
path component indicates the location of an endpoint within a server. The query
component is optional.
Modern web browsers implement the WebSocket protocol and provide a JavaScript
API to connect to endpoints, send messages, and assign callback methods for
WebSocket events (such as opened connections, received messages, and closed
connections).
18.2 Creating WebSocket Applications in the Java EE Platform
The Java EE platform includes the Java API for WebSocket (JSR 356), which enables
you to create, configure, and deploy WebSocket endpoints in web applications. The
WebSocket client API specified in JSR 356 also enables you to access remote WebSocket
endpoints from any Java application.
The Java API for WebSocket consists of the following packages.
■
The javax.websocket.server package contains annotations, classes, and
interfaces to create and configure server endpoints.
18-2 The Java EE 7 Tutorial
Programmatic Endpoints
■
The javax.websocket package contains annotations, classes, interfaces, and
exceptions that are common to client and server endpoints.
WebSocket endpoints are instances of the javax.websocket.Endpoint class. The Java
API for WebSocket enables you to create two kinds of endpoints: programmatic
endpoints and annotated endpoints. To create a programmatic endpoint, you extend
the Endpoint class and override its lifecycle methods. To create an annotated
endpoint, you decorate a Java class and some of its methods with the annotations
provided by the packages mentioned previously. After you have created an endpoint,
you deploy it to an specific URI in the application so that remote clients can connect to
it.
In most cases, it is easier to create and deploy an annotated
endpoint than a programmatic endpoint. This chapter provides a
simple example of a programmatic endpoint, but it focuses on
annotated endpoints.
Note:
The process for creating and deploying a WebSocket endpoint follows.
1.
Create an endpoint class.
2.
Implement the lifecycle methods of the endpoint.
3.
Add your business logic to the endpoint.
4.
Deploy the endpoint inside a web application.
The process is slightly different for programmatic endpoints and annotated endpoints,
and it is covered in detail in the following sections.
As opposed to servlets, WebSocket endpoints are instantiated
multiple times. The container creates an instance of an endpoint per
connection to its deployment URI. Each instance is associated with
one and only one connection. This facilitates keeping user state for
each connection and makes development easier, because there is only
one thread executing the code of an endpoint instance at any given
time.
Note:
18.3 Programmatic Endpoints
The following example shows how to create an endpoint by extending the Endpoint
class:
public class EchoEndpoint extends Endpoint {
@Override
public void onOpen(final Session session, EndpointConfig config) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String msg) {
try {
session.getBasicRemote().sendText(msg);
} catch (IOException e) { ... }
}
});
}
}
Java API for WebSocket 18-3
Annotated Endpoints
This endpoint echoes every message received. The Endpoint class defines three
lifecycle methods: onOpen, onClose, and onError. The EchoEndpoint class implements
the onOpen method, which is the only abstract method in the Endpoint class.
The Session parameter represents a conversation between this endpoint and the
remote endpoint. The addMessageHandler method registers message handlers, and the
getBasicRemote method returns an object that represents the remote endpoint. The
Session interface is covered in detail in the rest of this chapter.
The message handler is implemented as an anonymous inner class. The onMessage
method of the message handler is invoked when the endpoint receives a text message.
To deploy this programmatic endpoint, use the following code in your Java EE
application:
ServerEndpointConfig.Builder.create(EchoEndpoint.class, "/echo").build();
When you deploy your application, the endpoint is available at
ws://<host>:<port>/<application>/echo; for example,
ws://localhost:8080/echoapp/echo.
18.4 Annotated Endpoints
The following example shows how to create the same endpoint from Programmatic
Endpoints using annotations instead:
@ServerEndpoint("/echo")
public class EchoEndpoint {
@OnMessage
public void onMessage(Session session, String msg) {
try {
session.getBasicRemote().sendText(msg);
} catch (IOException e) { ... }
}
}
The annotated endpoint is simpler than the equivalent programmatic endpoint, and it
is deployed automatically with the application to the relative path defined in the
ServerEndpoint annotation. Instead of having to create an additional class for the
message handler, this example uses the OnMessage annotation to designate the method
invoked to handle messages.
Table 18–1 lists the annotations available in the javax.websocket package to designate
the methods that handle lifecycle events. The examples in the table show the most
common parameters for these methods. See the API reference for details on what
combinations of parameters are allowed in each case.
Table 18–1
WebSocket Endpoint Lifecycle Annotations
Annotation
Event
Example
OnOpen
Connection opened
@OnOpen
public void open(Session session,
EndpointConfig conf) { }
OnMessage
Message received
@OnMessage
public void message(Session session,
String msg) { }
OnError
Connection error
@OnError
public void error(Session session,
Throwable error) { }
18-4 The Java EE 7 Tutorial
Sending and Receiving Messages
Table 18–1 (Cont.) WebSocket Endpoint Lifecycle Annotations
Annotation
Event
Example
OnClose
Connection closed
@OnClose
public void close(Session session,
CloseReason reason) { }
18.5 Sending and Receiving Messages
WebSocket endpoints can send and receive text and binary messages. In addition, they
can also send ping frames and receive pong frames. This section describes how to use
the Session and RemoteEndpoint interfaces to send messages to the connected peer
and how to use the OnMessage annotation to receive messages from it.
18.5.1 Sending Messages
Follow these steps to send messages in an endpoint.
1.
Obtain the Session object from the connection.
The Session object is available as a parameter in the annotated lifecycle methods
of the endpoint, like those in Table 18–1. When your message is a response to a
message from the peer, you have the Session object available inside the method
that received the message (the method annotated with @OnMessage). If you have to
send messages that are not responses, store the Session object as an instance
variable of the endpoint class in the method annotated with @OnOpen so that you
can access it from other methods.
2.
Use the Session object to obtain a RemoteEndpoint object.
The Session.getBasicRemote method and the Session.getAsyncRemote method
return RemoteEndpoint.Basic and RemoteEndpoint.Async objects respectively.
The RemoteEndpoint.Basic interface provides blocking methods to send
messages; the RemoteEndpoint.Async interface provides nonblocking methods.
3.
Use the RemoteEndpoint object to send messages to the peer.
The following list shows some of the methods you can use to send messages to the
peer.
■
void RemoteEndpoint.Basic.sendText(String text)
Send a text message to the peer. This method blocks until the whole message
has been transmitted.
■
void RemoteEndpoint.Basic.sendBinary(ByteBuffer data)
Send a binary message to the peer. This method blocks until the whole
message has been transmitted.
■
void RemoteEndpoint.sendPing(ByteBuffer appData)
Send a ping frame to the peer.
■
void RemoteEndpoint.sendPong(ByteBuffer appData)
Send a pong frame to the peer.
The example in Annotated Endpoints demonstrates how to use this procedure to reply
to every incoming text message.
Java API for WebSocket 18-5
Maintaining Client State
18.5.1.1 Sending Messages to All Peers Connected to an Endpoint
Each instance of an endpoint class is associated with one and only one connection and
peer; however, there are cases in which an endpoint instance needs to send messages
to all connected peers. Examples include chat applications and online auctions. The
Session interface provides the getOpenSessions method for this purpose. The
following example demonstrates how to use this method to forward incoming text
messages to all connected peers:
@ServerEndpoint("/echoall")
public class EchoAllEndpoint {
@OnMessage
public void onMessage(Session session, String msg) {
try {
for (Session sess : session.getOpenSessions()) {
if (sess.isOpen())
sess.getBasicRemote().sendText(msg);
}
} catch (IOException e) { ... }
}
}
18.5.2 Receiving Messages
The OnMessage annotation designates methods that handle incoming messages. You
can have at most three methods annotated with @OnMessage in an endpoint, one for
each message type: text, binary, and pong. The following example demonstrates how
to designate methods to receive all three types of messages:
@ServerEndpoint("/receive")
public class ReceiveEndpoint {
@OnMessage
public void textMessage(Session session, String msg) {
System.out.println("Text message: " + msg);
}
@OnMessage
public void binaryMessage(Session session, ByteBuffer msg) {
System.out.println("Binary message: " + msg.toString());
}
@OnMessage
public void pongMessage(Session session, PongMessage msg) {
System.out.println("Pong message: " +
msg.getApplicationData().toString());
}
}
18.6 Maintaining Client State
Because the container creates an instance of the endpoint class for every connection,
you can define and use instance variables to store client state information. In addition,
the Session.getUserProperties method provides a modifiable map to store user
properties. For example, the following endpoint replies to incoming text messages
with the contents of the previous message from each client:
@ServerEndpoint("/delayedecho")
public class DelayedEchoEndpoint {
@OnOpen
public void open(Session session) {
session.getUserProperties().put("previousMsg", " ");
}
18-6 The Java EE 7 Tutorial
Using Encoders and Decoders
@OnMessage
public void message(Session session, String msg) {
String prev = (String) session.getUserProperties()
.get("previousMsg");
session.getUserProperties().put("previousMsg", msg);
try {
session.getBasicRemote().sendText(prev);
} catch (IOException e) { ... }
}
}
To store information common to all connected clients, you can use class (static)
variables; however, you are responsible for ensuring thread-safe access to them.
18.7 Using Encoders and Decoders
The Java API for WebSocket provides support for converting between WebSocket
messages and custom Java types using encoders and decoders. An encoder takes a
Java object and produces a representation that can be transmitted as a WebSocket
message; for example, encoders typically produce JSON, XML, or binary
representations. A decoder performs the reverse function; it reads a WebSocket
message and creates a Java object.
This mechanism simplifies WebSocket applications, because it decouples the business
logic from the serialization and deserialization of objects.
18.7.1 Implementing Encoders to Convert Java Objects into WebSocket Messages
The procedure to implement and use encoders in endpoints follows.
1.
Implement one of the following interfaces:
■
Encoder.Text<T> for text messages
■
Encoder.Binary<T> for binary messages
These interfaces specify the encode method. Implement an encoder class for each
custom Java type that you want to send as a WebSocket message.
2.
Add the names of your encoder implementations to the encoders optional
parameter of the ServerEndpoint annotation.
3.
Use the sendObject(Object data) method of the RemoteEndpoint.Basic or
RemoteEndpoint.Async interfaces to send your objects as messages. The container
looks for an encoder that matches your type and uses it to convert the object to a
WebSocket message.
For example, if you have two Java types (MessageA and MessageB) that you want to
send as text messages, implement the Encoder.Text<MessageA> and
Encoder.Text<MessageB> interfaces as follows:
public class MessageATextEncoder implements Encoder.Text<MessageA> {
@Override
public void init(EndpointConfig ec) { }
@Override
public void destroy() { }
@Override
public String encode(MessageA msgA) throws EncodeException {
// Access msgA's properties and convert to JSON text...
return msgAJsonString;
}
Java API for WebSocket 18-7
Using Encoders and Decoders
}
Implement Encoder.Text<MessageB> similarly. Then, add the encoders parameter to
the ServerEndpoint annotation as follows:
@ServerEndpoint(
value = "/myendpoint",
encoders = { MessageATextEncoder.class, MessageBTextEncoder.class }
)
public class EncEndpoint { ... }
Now, you can send MessageA and MessageB objects as WebSocket messages using the
sendObject method as follows:
MessageA msgA = new MessageA(...);
MessageB msgB = new MessageB(...);
session.getBasicRemote.sendObject(msgA);
session.getBasicRemote.sendObject(msgB);
As in this example, you can have more than one encoder for text messages and more
than one encoder for binary messages. Like endpoints, encoder instances are
associated with one and only one WebSocket connection and peer, so there is only one
thread executing the code of an encoder instance at any given time.
18.7.2 Implementing Decoders to Convert WebSocket Messages into Java Objects
The procedure to implement and use decoders in endpoints follows.
1.
Implement one of the following interfaces:
■
Decoder.Text<T> for text messages
■
Decoder.Binary<T> for binary messages
These interfaces specify the willDecode and decode methods.
Note: Unlike with encoders, you can specify at most one decoder for
binary messages and one decoder for text messages.
2.
Add the names of your decoder implementations to the decoders optional
parameter of the ServerEndpoint annotation.
3.
Use the OnMessage annotation in the endpoint to designate a method that takes
your custom Java type as a parameter. When the endpoint receives a message that
can be decoded by one of the decoders you specified, the container calls the
method annotated with @OnMessage that takes your custom Java type as a
parameter if this method exists.
For example, if you have two Java types (MessageA and MessageB) that you want to
send and receive as text messages, define them so that they extend a common class
(Message). Because you can only define one decoder for text messages, implement a
decoder for the Message class as follows:
public class MessageTextDecoder implements Decoder.Text<Message> {
@Override
public void init(EndpointConfig ec) { }
@Override
public void destroy() { }
@Override
public Message decode(String string) throws DecodeException {
18-8 The Java EE 7 Tutorial
Path Parameters
// Read message...
if ( /* message is an A message */ )
return new MessageA(...);
else if ( /* message is a B message */ )
return new MessageB(...);
}
@Override
public boolean willDecode(String string) {
// Determine if the message can be converted into either a
// MessageA object or a MessageB object...
return canDecode;
}
}
Then, add the decoder parameter to the ServerEndpoint annotation as follows:
@ServerEndpoint(
value = "/myendpoint",
encoders = { MessageATextEncoder.class, MessageBTextEncoder.class },
decoders = { MessageTextDecoder.class }
)
public class EncDecEndpoint { ... }
Now, define a method in the endpoint class that receives MessageA and MessageB
objects as follows:
@OnMessage
public void message(Session session, Message msg) {
if (msg instanceof MessageA) {
// We received a MessageA object...
} else if (msg instanceof MessageB) {
// We received a MessageB object...
}
}
Like endpoints, decoder instances are associated with one and only one WebSocket
connection and peer, so there is only one thread executing the code of a decoder
instance at any given time.
18.8 Path Parameters
The ServerEndpoint annotation enables you to use URI templates to specify parts of
an endpoint deployment URI as application parameters. For example, consider this
endpoint:
@ServerEndpoint("/chatrooms/{room-name}")
public class ChatEndpoint {
...
}
If the endpoint is deployed inside a web application called chatapp at a local Java EE
server in port 8080, clients can connect to the endpoint using any of the following
URIs:
http://localhost:8080/chatapp/chatrooms/currentnews
http://localhost:8080/chatapp/chatrooms/music
http://localhost:8080/chatapp/chatrooms/cars
http://localhost:8080/chatapp/chatrooms/technology
Java API for WebSocket 18-9
Handling Errors
Annotated endpoints can receive path parameters as arguments in methods annotated
with @OnOpen, @OnMessage, and @OnClose. In this example, the endpoint uses the
parameter in the @OnOpen method to determine which chat room the client wants to
join:
@ServerEndpoint("/chatrooms/{room-name}")
public class ChatEndpoint {
@OnOpen
public void open(Session session,
EndpointConfig c,
@PathParam("room-name") String roomName) {
// Add the client to the chat room of their choice ...
}
}
The path parameters used as arguments in these methods can be strings, primitive
types, or the corresponding wrapper types.
18.9 Handling Errors
To designate a method that handles errors in an annotated WebSocket endpoint,
decorate it with @OnError:
@ServerEndpoint("/testendpoint")
public class TestEndpoint {
...
@OnError
public void error(Session session, Throwable t) {
t.printStackTrace();
...
}
}
This method is invoked when there are connection problems, runtime errors from
message handlers, or conversion errors when decoding messages.
18.10 Specifying an Endpoint Configurator Class
The Java API for WebSocket enables you to configure how the container creates server
endpoint instances. You can provide custom endpoint configuration logic to:
■
Access the details of the initial HTTP request for a WebSocket connection
■
Perform custom checks on the Origin HTTP header
■
Modify the WebSocket handshake response
■
Choose a WebSocket subprotocol from those requested by the client
■
Control the instantiation and initialization of endpoint instances
To provide custom endpoint configuration logic, you extend the
ServerEndpointConfig.Configurator class and override some of its methods. In the
endpoint class, you specify the configurator class using the configurator parameter of
the ServerEndpoint annotation.
For example, the following configurator class makes the handshake request object
available to endpoint instances:
public class CustomConfigurator extends ServerEndpointConfig.Configurator {
18-10 The Java EE 7 Tutorial
The dukeetf2 Example Application
@Override
public void modifyHandshake(ServerEndpointConfig conf,
HandshakeRequest req,
HandshakeResponse resp) {
conf.getUserProperties().put("handshakereq", req);
}
}
The following endpoint class configures endpoint instances with the custom
configurator, which enables them to access the handshake request object:
@ServerEndpoint(
value = "/myendpoint",
configurator = CustomConfigurator.class
)
public class MyEndpoint {
@OnOpen
public void open(Session s, EndpointConfig conf) {
HandshakeRequest req = (HandshakeRequest) conf.getUserProperties()
.get("handshakereq");
Map<String,List<String>> headers = req.getHeaders();
...
}
}
The endpoint class can use the handshake request object to access the details of the
initial HTTP request, such as its headers or the HttpSession object.
For more information on endpoint configuration, see the API reference for the
ServerEndpointConfig.Configurator class.
18.11 The dukeetf2 Example Application
The dukeetf2 example application, located in the
tut-install/examples/web/websocket/dukeetf2/ directory, demonstrates how to use a
WebSocket endpoint to provide data updates to web clients. The example resembles a
service that provides periodic updates on the price and trading volume of an
electronically traded fund (ETF).
18.11.1 Architecture of the dukeetf2 Sample Application
The dukeetf2 example application consists of a WebSocket endpoint, an enterprise
bean, and an HTML page.
■
■
■
The endpoint accepts connections from clients and sends them updates when new
data for price and trading volume becomes available.
The enterprise bean updates the price and volume information once every second.
The HTML page uses JavaScript code to connect to the WebSocket endpoint, parse
incoming messages, and update the price and volume information without
reloading the page.
Java API for WebSocket 18-11
The dukeetf2 Example Application
18.11.1.1 The Endpoint
The WebSocket endpoint is implemented in the ETFEndpoint class, which stores all
connected sessions in a queue and provides a method that the enterprise bean calls
when there is new information available to send:
@ServerEndpoint("/dukeetf")
public class ETFEndpoint {
private static final Logger logger = Logger.getLogger("ETFEndpoint");
/* Queue for all open WebSocket sessions */
static Queue<Session> queue = new ConcurrentLinkedQueue<>();
/* PriceVolumeBean calls this method to send updates */
public static void send(double price, int volume) {
String msg = String.format("%.2f / %d", price, volume);
try {
/* Send updates to all open WebSocket sessions */
for (Session session : queue) {
session.getBasicRemote().sendText(msg);
logger.log(Level.INFO, "Sent: {0}", msg);
}
} catch (IOException e) {
logger.log(Level.INFO, e.toString());
}
}
...
}
The lifecycle methods of the endpoint add and remove sessions to and from the queue:
@ServerEndpoint("/dukeetf")
public class ETFEndpoint {
...
@OnOpen
public void openConnection(Session session) {
/* Register this connection in the queue */
queue.add(session);
logger.log(Level.INFO, "Connection opened.");
}
@OnClose
public void closedConnection(Session session) {
/* Remove this connection from the queue */
queue.remove(session);
logger.log(Level.INFO, "Connection closed.");
}
@OnError
public void error(Session session, Throwable t) {
/* Remove this connection from the queue */
queue.remove(session);
logger.log(Level.INFO, t.toString());
logger.log(Level.INFO, "Connection error.");
}
}
18.11.1.2 The Enterprise Bean
The enterprise bean uses the timer service to generate new price and volume
information every second:
@Startup
18-12 The Java EE 7 Tutorial
The dukeetf2 Example Application
@Singleton
public class PriceVolumeBean {
/* Use the container's timer service */
@Resource TimerService tservice;
private Random random;
private volatile double price = 100.0;
private volatile int volume = 300000;
private static final Logger logger = Logger.getLogger("PriceVolumeBean");
@PostConstruct
public void init() {
/* Initialize the EJB and create a timer */
logger.log(Level.INFO, "Initializing EJB.");
random = new Random();
tservice.createIntervalTimer(1000, 1000, new TimerConfig());
}
@Timeout
public void timeout() {
/* Adjust price and volume and send updates */
price += 1.0*(random.nextInt(100)-50)/100.0;
volume += random.nextInt(5000) - 2500;
ETFEndpoint.send(price, volume);
}
}
The enterprise bean calls the send method of the ETFEndpoint class in the timeout
method. See Using the Timer Service in Chapter 34, "Running the Enterprise Bean
Examples" for more information on the timer service.
18.11.1.3 The HTML Page
The HTML page consists of a table and some JavaScript code. The table contains two
fields referenced from JavaScript code:
<!DOCTYPE html>
<html>
<head>...</head>
<body>
...
<table>
...
<td id="price">--.--</td>
...
<td id="volume">--</td>
...
</table>
</body>
</html>
The JavaScript code uses the WebSocket API to connect to the server endpoint and to
designate a callback method for incoming messages. The callback method updates the
page with the new information.
var wsocket;
function connect() {
wsocket = new WebSocket("ws://localhost:8080/dukeetf2/dukeetf");
wsocket.onmessage = onMessage;
}
function onMessage(evt) {
var arraypv = evt.data.split("/");
Java API for WebSocket 18-13
The websocketbot Example Application
document.getElementById("price").innerHTML = arraypv[0];
document.getElementById("volume").innerHTML = arraypv[1];
}
window.addEventListener("load", connect, false);
The WebSocket API is supported by most modern browsers, and it is widely used in
HTML5 web client development.
18.11.2 Running the dukeetf2 Example Application
This section describes how to run the dukeetf2 example application using NetBeans
IDE and from the command line.
18.11.2.1 To Run the dukeetf2 Example Application Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/websocket
4.
Select the dukeetf2 folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the dukeetf2 project and select Run.
This command builds and packages the application into a WAR file
(dukeetf2.war) located in the target/ directory, deploys it to the server, and
launches a web browser window with the following URL:
http://localhost:8080/dukeetf2/
Open the same URL on a different web browser tab or window to see how both
pages get price and volume updates simultaneously.
18.11.2.2 To Run the dukeetf2 Example Application Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/websocket/dukeetf2/
3.
Enter the following command to deploy the application:
mvn install
4.
Open a web browser window and enter the following URL:
http://localhost:8080/dukeetf2/
Open the same URL on a different web browser tab or window to see how both
pages get price and volume updates simultaneously.
18.12 The websocketbot Example Application
The websocketbot example application, located in the
tut-install/examples/web/websocket/websocketbot/ directory, demonstrates how to
18-14 The Java EE 7 Tutorial
The websocketbot Example Application
use a WebSocket endpoint to implement a chat. The example resembles a chat room in
which many users can join and have a conversation. Users can ask simple questions to
a bot agent that is always available in the chat room.
18.12.1 Architecture of the websocketbot Example Application
The websocketbot example application consists of the following elements:
■
A CDI bean (BotBean) that contains the logic for the bot agent to reply to messages
■
A WebSocket endpoint (BotEndpoint) that implements the chat room
■
■
■
■
A set of classes (Message, ChatMessage, InfoMessage, JoinMessage, and
UsersMessage) that represent application messages
A set of classes (ChatMessageEncoder, InfoMessageEncoder, JoinMessageEncoder,
and UsersMessageEncoder) that encode application messages into WebSocket text
messages as JSON data
A class (MessageDecoder) the parses WebSocket text messages as JSON data and
decodes them into JoinMessage or ChatMessage objects
An HTML page (index.html) that uses JavaScript code to implement the client for
the chat room
18.12.1.1 The CDI Bean
The CDI bean (BotBean) is a Java class that contains the respond method. This method
compares the incoming chat message with a set of predefined questions and returns a
chat response.
@Named
public class BotBean {
public String respond(String msg) { ... }
}
18.12.1.2 The WebSocket Endpoint
The WebSocket endpoint (BotEndpoint) is an annotated endpoint that performs the
following functions:
■
Receives messages from clients
■
Forwards messages to clients
■
Maintains a list of connected clients
■
Invokes the bot agent functionality
The endpoint specifies its deployment URI and the message encoders and decoders
using the ServerEndpoint annotation. The endpoint obtains an instance of the BotBean
class and a managed executor service resource through dependency injection:
@ServerEndpoint(
value = "/websocketbot",
decoders = { MessageDecoder.class },
encoders = { JoinMessageEncoder.class, ChatMessageEncoder.class,
InfoMessageEncoder.class, UsersMessageEncoder.class }
)
/* There is a BotEndpoint instance per connection */
public class BotEndpoint {
private static final Logger logger = Logger.getLogger("BotEndpoint");
/* Bot functionality bean */
Java API for WebSocket 18-15
The websocketbot Example Application
@Inject private BotBean botbean;
/* Executor service for asynchronous processing */
@Resource(name="comp/DefaultManagedExecutorService")
private ManagedExecutorService mes;
@OnOpen
public void openConnection(Session session) {
logger.log(Level.INFO, "Connection opened.");
}
...
}
The message method processes incoming messages from clients. The decoder converts
incoming text messages into JoinMessage or ChatMessage objects, which inherit from
the Message class. The message method receives a Message object as a parameter:
@OnMessage
public void message(Session session, Message msg) {
logger.log(Level.INFO, "Received: {0}", msg.toString());
if (msg instanceof JoinMessage) {
/* Add the new user and notify everybody */
JoinMessage jmsg = (JoinMessage) msg;
session.getUserProperties().put("name", jmsg.getName());
session.getUserProperties().put("active", true);
logger.log(Level.INFO, "Received: {0}", jmsg.toString());
sendAll(session, new InfoMessage(jmsg.getName() +
" has joined the chat"));
sendAll(session, new ChatMessage("Duke", jmsg.getName(),
"Hi there!!"));
sendAll(session, new UsersMessage(this.getUserList(session)));
} else if (msg instanceof ChatMessage) {
/* Forward the message to everybody */
ChatMessage cmsg = (ChatMessage) msg;
logger.log(Level.INFO, "Received: {0}", cmsg.toString());
sendAll(session, cmsg);
if (cmsg.getTarget().compareTo("Duke") == 0) {
/* The bot replies to the message */
mes.submit(new Runnable() {
@Override
public void run() {
String resp = botbean.respond(cmsg.getMessage());
sendAll(session, new ChatMessage("Duke",
cmsg.getName(), resp));
}
});
}
}
}
If the message is a join message, the endpoint adds the new user to the list and notifies
all connected clients. If the message is a chat message, the endpoint forwards it to all
connected clients.
If a chat message is for the bot agent, the endpoint obtains a response using the
BotBean instance and sends it to all connected clients. The sendAll method is similar
to the example in Sending Messages to All Peers Connected to an Endpoint.
Asynchronous Processing and Concurrency Considerations
18-16 The Java EE 7 Tutorial
The websocketbot Example Application
The WebSocket endpoint calls the BotBean.respond method to obtain a response from
the bot. In this example, this is a blocking operation; the user that sent the associated
message would not be able to send or receive other chat messages until the operation
completes. To avoid this problem, the endpoint obtains an executor service from the
container and executes the blocking operation in a different thread using the
ManagedExecutorService.submit method from Concurrency Utilities for Java EE.
The Java API for WebSocket specification requires that Java EE implementations
instantiate endpoint classes once per connection. This facilitates the development of
WebSocket endpoints, because you are guaranteed that only one thread is executing
the code in a WebSocket endpoint class at any given time. When you introduce a new
thread in an endpoint, as in this example, you must ensure that variables and methods
accessed by more than one thread are thread safe. In this example, the code in BotBean
is thread safe, and the BotEndpoint.sendAll method has been declared synchronized.
Refer to Chapter 56, "Concurrency Utilities for Java EE" for more information on the
managed executor service and Concurrency Utilities for Java EE.
18.12.1.3 The Application Messages
The classes that represent application messages (Message, ChatMessage, InfoMessage,
JoinMessage, and UsersMessage) contain only properties and getter and setter
methods. For example, the ChatMessage class looks like this:
public class ChatMessage extends Message {
private String name;
private String target;
private String message;
/* ... Constructor, getters, and setters ... */
}
18.12.1.4 The Encoder Classes
The encoder classes convert application message objects into JSON text using the Java
API for JSON Processing. For example, the ChatMessageEncoder class is implemented
as follows:
/* Encode a ChatMessage as JSON.
* For example, (new ChatMessage("Peter","Duke","How are you?"))
* is encoded as follows:
* {"type":"chat","target":"Duke","message":"How are you?"}
*/
public class ChatMessageEncoder implements Encoder.Text<ChatMessage> {
@Override
public void init(EndpointConfig ec) { }
@Override
public void destroy() { }
@Override
public String encode(ChatMessage chatMessage) throws EncodeException {
// Access properties in chatMessage and write JSON text...
}
}
See Chapter 19, JSON Processing for more information on the Java API for JSON
Processing.
Java API for WebSocket 18-17
The websocketbot Example Application
18.12.1.5 The Message Decoder
The message decoder (MessageDecoder) class converts WebSocket text messages into
application messages by parsing JSON text. It is implemented as follows:
/* Decode a JSON message into a JoinMessage or a ChatMessage.
* For example, the incoming message
* {"type":"chat","name":"Peter","target":"Duke","message":"How are you?"}
* is decoded as (new ChatMessage("Peter", "Duke", "How are you?"))
*/
public class MessageDecoder implements Decoder.Text<Message> {
/* Stores the name-value pairs from a JSON message as a Map */
private Map<String,String> messageMap;
@Override
public void init(EndpointConfig ec) { }
@Override
public void destroy() { }
/* Create a new Message object if the message can be decoded */
@Override
public Message decode(String string) throws DecodeException {
Message msg = null;
if (willDecode(string)) {
switch (messageMap.get("type")) {
case "join":
msg = new JoinMessage(messageMap.get("name"));
break;
case "chat":
msg = new ChatMessage(messageMap.get("name"),
messageMap.get("target"),
messageMap.get("message"));
}
} else {
throw new DecodeException(string, "[Message] Can't decode.");
}
return msg;
}
/* Decode a JSON message into a Map and check if it contains
* all the required fields according to its type. */
@Override
public boolean willDecode(String string) {
// Convert JSON data from the message into a name-value map...
// Check if the message has all the fields for its message type...
}
}
18.12.1.6 The HTML Page
The HTML page (index.html) contains a field for the user name. After the user types a
name and clicks Join, three text areas are available: one to type and send messages,
one for the chat room, and one with the list of users. The page also contains a
WebSocket console that shows the messages sent and received as JSON text.
The JavaScript code on the page uses the WebSocket API to connect to the endpoint,
send messages, and designate callback methods. The WebSocket API is supported by
most modern browsers and is widely used for web client development with HTML5.
18-18 The Java EE 7 Tutorial
The websocketbot Example Application
18.12.2 Running the websocketbot Example Application
This section describes how to run the websocketbot example application using
NetBeans IDE and from the command line.
18.12.2.1 To Run the websocketbot Example Application Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/websocket
4.
Select the websocketbot folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the websocketbot project and select Run.
This command builds and packages the application into a WAR file,
websocketbot.war, located in the target/ directory; deploys it to the server; and
launches a web browser window with the following URL:
http://localhost:8080/websocketbot/
See To Test the websocketbot Example Application for more information.
18.12.2.2 To Run the websocketbot Example Application Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/websocket/websocketbot/
3.
Enter the following command to deploy the application:
mvn install
4.
Open a web browser window and type the following address:
http://localhost:8080/websocketbot/
See To Test the websocketbot Example Application for more information.
18.12.2.3 To Test the websocketbot Example Application
1.
On the main page, type your name on the first text field and press the Enter key.
The list of connected users appears on the text area on the right. The text area on
the left is the chat room.
2.
Type a message on the text area below the login button. For example, type the
messages in bold and press enter to obtain responses similar to the following:
[--Peter has
Duke: @Peter
Peter: @Duke
Duke: @Peter
Peter: @Duke
Duke: @Peter
joined the chat--]
Hi there!!
how are you?
I'm doing great, thank you!
when is your birthday?
My birthday is on May 23rd. Thanks for asking!
Java API for WebSocket 18-19
Further Information about WebSocket
3.
Join the chat from another browser window by copying and pasting the URI on
the address bar and joining with a different name.
The new user name appears in the list of users in both browser windows. You can
send messages from either window and see how they appear in the other.
4.
Click Show WebSocket Console.
The console shows the messages sent and received as JSON text.
18.13 Further Information about WebSocket
For more information on WebSocket in Java EE, see the Java API for WebSocket
specification:
http://www.jcp.org/en/jsr/detail?id=356
18-20 The Java EE 7 Tutorial
19
JSON Processing
19
This chapter describes the Java API for JSON Processing (JSR 353). JSON is a data
exchange format widely used in web services and other connected applications. JSR
353 provides an API to parse, transform, and query JSON data using the object model
or the streaming model.
The following topics are addressed here:
■
Introduction to JSON
■
JSON Processing in the Java EE Platform
■
Using the Object Model API
■
Using the Streaming API
■
JSON in Java EE RESTful Web Services
■
The jsonpmodel Example Application
■
The jsonpstreaming Example Application
■
Further Information about the Java API for JSON Processing
19.1 Introduction to JSON
JSON is a text-based data exchange format derived from JavaScript that is used in web
services and other connected applications. The following sections provide an
introduction to JSON syntax, an overview of JSON uses, and a description of the most
common approaches to generate and parse JSON.
19.1.1 JSON Syntax
JSON defines only two data structures: objects and arrays. An object is a set of
name-value pairs, and an array is a list of values. JSON defines seven value types:
string, number, object, array, true, false, and null.
The following example shows JSON data for a sample object that contains name-value
pairs. The value for the name "phoneNumbers" is an array whose elements are two
objects.
{
"firstName": "Duke",
"lastName": "Java",
"age": 18,
"streetAddress": "100 Internet Dr",
"city": "JavaTown",
"state": "JA",
JSON Processing 19-1
Introduction to JSON
"postalCode": "12345",
"phoneNumbers": [
{ "Mobile": "111-111-1111" },
{ "Home": "222-222-2222" }
]
}
JSON has the following syntax.
■
■
■
Objects are enclosed in braces ({}), their name-value pairs are separated by a
comma (,), and the name and value in a pair are separated by a colon (:). Names
in an object are strings, whereas values may be of any of the seven value types,
including another object or an array.
Arrays are enclosed in brackets ([]), and their values are separated by a comma
(,). Each value in an array may be of a different type, including another array or
an object.
When objects and arrays contain other objects or arrays, the data has a tree-like
structure.
19.1.2 Uses of JSON
JSON is often used as a common format to serialize and deserialize data in
applications that communicate with each other over the Internet. These applications
are created using different programming languages and run in very different
environments. JSON is suited to this scenario because it is an open standard, it is easy
to read and write, and it is more compact than other representations.
RESTful web services use JSON extensively as the format for the data inside requests
and responses. The HTTP header used to indicate that the content of a request or a
response is JSON data is
Content-Type: application/json
JSON representations are usually more compact than XML representations because
JSON does not have closing tags. Unlike XML, JSON does not have a widely accepted
schema for defining and validating the structure of JSON data.
19.1.3 Generating and Parsing JSON Data
For generating and parsing JSON data, there are two programming models, which are
similar to those used for XML documents.
■
■
The object model creates a tree that represents the JSON data in memory. The tree
can then be navigated, analyzed, or modified. This approach is the most flexible
and allows for processing that requires access to the complete contents of the tree.
However, it is often slower than the streaming model and requires more memory.
The object model generates JSON output by navigating the entire tree at once.
The streaming model uses an event-based parser that reads JSON data one
element at a time. The parser generates events and stops for processing when an
object or an array begins or ends, when it finds a key, or when it finds a value.
Each element can be processed or discarded by the application code, and then the
parser proceeds to the next event. This approach is adequate for local processing,
in which the processing of an element does not require information from the rest
of the data. The streaming model generates JSON output to a given stream by
making a function call with one element at a time.
19-2 The Java EE 7 Tutorial
JSON Processing in the Java EE Platform
There are many JSON generators and parsers available for different programming
languages and environments. JSON Processing in the Java EE Platform describes the
functionality provided by the Java API for JSON Processing (JSR 353).
19.2 JSON Processing in the Java EE Platform
Java EE includes support for JSR 353, which provides an API to parse, transform, and
query JSON data using the object model or the streaming model described in
Generating and Parsing JSON Data. The Java API for JSON Processing contains the
following packages.
■
■
The javax.json package contains a reader interface, a writer interface, and a
model builder interface for the object model. This package also contains other
utility classes and Java types for JSON elements. Table 19–1 lists the main classes
and interfaces in this package.
The javax.json.stream package contains a parser interface and a generator
interface for the streaming model. Table 19–2 lists the main classes and interfaces
in this package.
Table 19–1
Main Classes and Interfaces in javax.json
Class or Interface
Description
Json
Contains static methods to create instances of JSON parsers, builders,
and generators. This class also contains methods to create parser,
builder, and generator factory objects.
JsonReader
Reads JSON data from a stream and creates an object model in
memory.
JsonObjectBuilder
JsonArrayBuilder
Create an object model or an array model in memory by adding
elements from application code.
JsonWriter
Writes an object model from memory to a stream.
JsonValue
Represents an element (such as an object, an array, or a value) in JSON
data.
JsonStructure
Represents an object or an array in JSON data. This interface is a
subtype of JsonValue.
JsonObject
Represent an object or an array in JSON data. These two interfaces are
subtypes of JsonStructure.
JsonArray
JsonNumber
Represent data types for elements in JSON data. These two interfaces
are subtypes of JsonValue.
JsonException
Indicates that a problem occurred during JSON processing.
JsonString
Table 19–2
Main Classes and Interfaces in javax.json.stream
Class or Interface
Description
JsonParser
Represents an event-based parser that can read JSON data from a
stream or from an object model.
JsonGenerator
Writes JSON data to a stream one element at a time.
JSON Processing 19-3
Using the Object Model API
19.3 Using the Object Model API
This section describes four use cases of the object model API: creating an object model
from JSON data, creating an object model from application code, navigating an object
model, and writing an object model to a stream.
19.3.1 Creating an Object Model from JSON Data
The following code demonstrates how to create an object model from JSON data in a
text file:
import java.io.FileReader;
import javax.json.Json;
import javax.json.JsonReader;
import javax.json.JsonStructure;
...
JsonReader reader = Json.createReader(new FileReader("jsondata.txt"));
JsonStructure jsonst = reader.read();
The object reference jsonst can be either of type JsonObject or of type JsonArray,
depending on the contents of the file. JsonObject and JsonArray are subtypes of
JsonStructure. This reference represents the top of the tree and can be used to
navigate the tree or to write it to a stream as JSON data.
19.3.2 Creating an Object Model from Application Code
The following code demonstrates how to create an object model from application code:
import javax.json.Json;
import javax.json.JsonObject;
...
JsonObject model = Json.createObjectBuilder()
.add("firstName", "Duke")
.add("lastName", "Java")
.add("age", 18)
.add("streetAddress", "100 Internet Dr")
.add("city", "JavaTown")
.add("state", "JA")
.add("postalCode", "12345")
.add("phoneNumbers", Json.createArrayBuilder()
.add(Json.createObjectBuilder()
.add("type", "mobile")
.add("number", "111-111-1111"))
.add(Json.createObjectBuilder()
.add("type", "home")
.add("number", "222-222-2222")))
.build();
The object reference model represents the top of the tree, which is created by nesting
calls to the add methods and built by calling the build method. The
JsonObjectBuilder class contains the following add methods:
JsonObjectBuilder
JsonObjectBuilder
JsonObjectBuilder
JsonObjectBuilder
JsonObjectBuilder
JsonObjectBuilder
JsonObjectBuilder
JsonObjectBuilder
19-4 The Java EE 7 Tutorial
add(String
add(String
add(String
add(String
add(String
add(String
add(String
add(String
name,
name,
name,
name,
name,
name,
name,
name,
BigDecimal value)
BigInteger value)
boolean value)
double value)
int value)
JsonArrayBuilder builder)
JsonObjectBuilder builder)
JsonValue value)
Using the Object Model API
JsonObjectBuilder add(String name, long value)
JsonObjectBuilder add(String name, String value)
JsonObjectBuilder addNull(String name)
The JsonArrayBuilder class contains similar add methods that do not have a name
(key) parameter. You can nest arrays and objects by passing a new JsonArrayBuilder
object or a new JsonObjectBuilder object to the corresponding add method, as shown
in this example.
The resulting tree represents the JSON data from JSON Syntax.
19.3.3 Navigating an Object Model
The following code demonstrates a simple approach to navigating an object model:
import javax.json.JsonValue;
import javax.json.JsonObject;
import javax.json.JsonArray;
import javax.json.JsonNumber;
import javax.json.JsonString;
...
public static void navigateTree(JsonValue tree, String key) {
if (key != null)
System.out.print("Key " + key + ": ");
switch(tree.getValueType()) {
case OBJECT:
System.out.println("OBJECT");
JsonObject object = (JsonObject) tree;
for (String name : object.keySet())
navigateTree(object.get(name), name);
break;
case ARRAY:
System.out.println("ARRAY");
JsonArray array = (JsonArray) tree;
for (JsonValue val : array)
navigateTree(val, null);
break;
case STRING:
JsonString st = (JsonString) tree;
System.out.println("STRING " + st.getString());
break;
case NUMBER:
JsonNumber num = (JsonNumber) tree;
System.out.println("NUMBER " + num.toString());
break;
case TRUE:
case FALSE:
case NULL:
System.out.println(tree.getValueType().toString());
break;
}
}
The method navigateTree can be used with the models built in Creating an Object
Model from JSON Data and Creating an Object Model from Application Code as
follows:
navigateTree(model, null);
JSON Processing 19-5
Using the Object Model API
The navigateTree method takes two arguments: a JSON element and a key. The key is
used only to help print the key-value pairs inside objects. Elements in a tree are
represented by the JsonValue type. If the element is an object or an array, a new call to
this method is made for every element contained in the object or array. If the element
is a value, it is printed to the standard output.
The JsonValue.getValueType method identifies the element as an object, an array, or a
value. For objects, the JsonObject.keySet method returns a set of strings that contains
the keys in the object, and the JsonObject.get(String name) method returns the
value of the element whose key is name. For arrays, JsonArray implements the
List<JsonValue> interface. You can use enhanced for loops with the Set<String>
instance returned by JsonObject.keySet and with instances of JsonArray, as shown in
this example.
The navigateTree method for the model built in Creating an Object Model from
Application Code produces the following output:
OBJECT
Key firstName: STRING Duke
Key lastName: STRING Java
Key age: NUMBER 18
Key streetAddress: STRING 100 Internet Dr
Key city: STRING JavaTown
Key state: STRING JA
Key postalCode: STRING 12345
Key phoneNumbers: ARRAY
OBJECT
Key type: STRING mobile
Key number: STRING 111-111-1111
OBJECT
Key type: STRING home
Key number: STRING 222-222-2222
19.3.4 Writing an Object Model to a Stream
The object models created in Creating an Object Model from JSON Data and Creating
an Object Model from Application Code can be written to a stream using the
JsonWriter class as follows:
import java.io.StringWriter;
import javax.json.JsonWriter;
...
StringWriter stWriter = new StringWriter();
JsonWriter jsonWriter = Json.createWriter(stWriter);
jsonWriter.writeObject(model);
jsonWriter.close();
String jsonData = stWriter.toString();
System.out.println(jsonData);
The Json.createWriter method takes an output stream as a parameter. The
JsonWriter.writeObject method writes the object to the stream. The
JsonWriter.close method closes the underlying output stream.
The following example uses try-with-resources to close the JSON writer
automatically:
StringWriter stWriter = new StringWriter();
try (JsonWriter jsonWriter = Json.createWriter(stWriter)) {
jsonWriter.writeObject(model);
}
19-6 The Java EE 7 Tutorial
Using the Streaming API
String jsonData = stWriter.toString();
System.out.println(jsonData);
19.4 Using the Streaming API
This section describes two use cases of the streaming API:
■
Reading JSON data using a parser
■
Writing JSON data using a generator
19.4.1 Reading JSON Data Using a Parser
The streaming API is the most efficient approach for parsing JSON text. The following
code demonstrates how to create a JsonParser object and how to parse JSON data
using events:
import javax.json.Json;
import javax.json.stream.JsonParser;
...
JsonParser parser = Json.createParser(new StringReader(jsonData));
while (parser.hasNext()) {
JsonParser.Event event = parser.next();
switch(event) {
case START_ARRAY:
case END_ARRAY:
case START_OBJECT:
case END_OBJECT:
case VALUE_FALSE:
case VALUE_NULL:
case VALUE_TRUE:
System.out.println(event.toString());
break;
case KEY_NAME:
System.out.print(event.toString() + " " +
parser.getString() + " - ");
break;
case VALUE_STRING:
case VALUE_NUMBER:
System.out.println(event.toString() + " " +
parser.getString());
break;
}
}
This example consists of three steps.
1.
Obtain a parser instance by calling the Json.createParser static method.
2.
Iterate over the parser events with the JsonParser.hasNext and the
JsonParser.next methods.
3.
Perform local processing for each element.
The example shows the ten possible event types from the parser. The parser's next
method advances it to the next event. For the event types KEY_NAME, VALUE_STRING,
and VALUE_NUMBER, you can obtain the content of the element by calling the method
JsonParser.getString. For VALUE_NUMBER events, you can also use the following
methods:
JSON Processing 19-7
Using the Streaming API
■
JsonParser.isIntegralNumber
■
JsonParser.getInt
■
JsonParser.getLong
■
JsonParser.getBigDecimal
See the Java EE 7 API reference for the javax.json.stream.JsonParser interface for
more information.
The output of this example is the following:
START_OBJECT
KEY_NAME firstName - VALUE_STRING Duke
KEY_NAME lastName - VALUE_STRING Java
KEY_NAME age - VALUE_NUMBER 18
KEY_NAME streetAddress - VALUE_STRING 100 Internet Dr
KEY_NAME city - VALUE_STRING JavaTown
KEY_NAME state - VALUE_STRING JA
KEY_NAME postalCode - VALUE_STRING 12345
KEY_NAME phoneNumbers - START_ARRAY
START_OBJECT
KEY_NAME type - VALUE_STRING mobile
KEY_NAME number - VALUE_STRING 111-111-1111
END_OBJECT
START_OBJECT
KEY_NAME type - VALUE_STRING home
KEY_NAME number - VALUE_STRING 222-222-2222
END_OBJECT
END_ARRAY
END_OBJECT
19.4.2 Writing JSON Data Using a Generator
The following code demonstrates how to write JSON data to a file using the streaming
API:
FileWriter writer = new FileWriter("test.txt");
JsonGenerator gen = Json.createGenerator(writer);
gen.writeStartObject()
.write("firstName", "Duke")
.write("lastName", "Java")
.write("age", 18)
.write("streetAddress", "100 Internet Dr")
.write("city", "JavaTown")
.write("state", "JA")
.write("postalCode", "12345")
.writeStartArray("phoneNumbers")
.writeStartObject()
.write("type", "mobile")
.write("number", "111-111-1111")
.writeEnd()
.writeStartObject()
.write("type", "home")
.write("number", "222-222-2222")
.writeEnd()
.writeEnd()
.writeEnd();
gen.close();
19-8 The Java EE 7 Tutorial
The jsonpmodel Example Application
This example obtains a JSON generator by calling the Json.createGenerator static
method, which takes a writer or an output stream as a parameter. The example writes
JSON data to the test.txt file by nesting calls to the write, writeStartArray,
writeStartObject, and writeEnd methods. The JsonGenerator.close method closes
the underlying writer or output stream.
19.5 JSON in Java EE RESTful Web Services
This section explains how the Java API for JSON Processing is related to other Java EE
packages that provide JSON support for RESTful web services. See Chapter 29,
"Building RESTful Web Services with JAX-RS," for more information on RESTful web
services.
Jersey, the reference implementation for JAX-RS (JSR 311) included in GlassFish Server,
provides support for binding JSON data from RESTful resource methods to Java
objects using JAXB, as described in Using JAX-RS with JAXB in Chapter 31, "JAX-RS:
Advanced Topics and an Example". However, JSON support is not part of JAX-RS (JSR
311) or JAXB (JSR 222), so that procedure may not work for Java EE implementations
other than GlassFish Server.
The Java API for JSON Processing (JSR 353) does not explicitly support JSON binding
in Java. A future JSR (JSON Binding) that is similar to JAXB for XML is under
consideration for a future release of Java EE.
You can still use the Java API for JSON Processing with JAX-RS resource methods. For
more information, see the sample code for JSON Processing included with the Java EE
7 SDK.
19.6 The jsonpmodel Example Application
This section describes how to build and run the jsonpmodel example application. This
example is a web application that demonstrates how to create an object model from
form data, how to parse JSON data, and how write JSON data using the object model
API.
The jsonpmodel example application is in the
tut-install/examples/web/jsonp/jsonpmodel directory.
19.6.1 Components of the jsonpmodel Example Application
The jsonpmodel example application contains the following files.
■
■
Three JavaServer Faces pages.
–
The index.xhtml page contains a form to collect information.
–
The modelcreated.xhtml page contains a text area that displays JSON data.
–
The parsejson.xhtml page contains a table that shows the elements of the
object model.
The ObjectModelBean.java managed bean, which is a session-scoped managed
bean that stores the data from the form and directs the navigation between the
Facelets pages. This file also contains code that uses the JSON object model API.
The code used in ObjectModelBean.java to create an object model from the data in the
form is similar to the example in Creating an Object Model from Application Code.
The code to write JSON output from the model is similar to the example in Writing an
Object Model to a Stream. The code to navigate the object model tree is similar to the
example in Navigating an Object Model.
JSON Processing 19-9
The jsonpstreaming Example Application
19.6.2 Running the jsonpmodel Example Application
This section describes how to run the jsonpmodel example application using NetBeans
IDE and from the command line.
19.6.2.1 To Run the jsonpmodel Example Application Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsonp
4.
Select the jsonpmodel folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the jsonpmodel project and select Run.
This command builds and packages the application into a WAR file
(jsonpmodel.war) located in the target directory, deploys it to the server, and
opens a web browser window with the following URL:
http://localhost:8080/jsonpmodel/
7.
Edit the data on the page and click Create a JSON Object to submit the form. The
following page shows a JSON object that contains the data from the form.
8.
Click Parse JSON. The following page contains a table that lists the nodes of the
object model tree.
19.6.2.2 To Run the jsonpmodel Example Application Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/web/jsonp/jsonpmodel
3.
Enter the following command to deploy the application:
mvn install
4.
Open a web browser window and enter the following address:
http://localhost:8080/jsonpmodel/
5.
Edit the data on the page and click Create a JSON Object to submit the form. The
following page shows a JSON object that contains the data from the form.
6.
Click Parse JSON. The following page contains a table that lists the nodes of the
object model tree.
19.7 The jsonpstreaming Example Application
This section describes how to build and run the jsonpstreaming example application.
This example is a web application that demonstrates how to create JSON data from
form data, how to parse JSON data, and how to write JSON output using the
streaming API.
19-10 The Java EE 7 Tutorial
The jsonpstreaming Example Application
The jsonpstreaming example application is in the
tut-install/examples/web/jsonp/jsonpstreaming directory.
19.7.1 Components of the jsonpstreaming Example Application
The jsonpstreaming example application contains the following files.
■
■
Three JavaServer Faces pages.
–
The index.xhtml page contains a form to collect information.
–
The filewritten.xhtml page contains a text area that displays JSON data.
–
The parsed.xhtml page contains a table that lists the events from the parser.
The StreamingBean.java managed bean, a session-scoped managed bean that
stores the data from the form and directs the navigation between the Facelets
pages. This file also contains code that uses the JSON streaming API.
The code used in StreamingBean.java to write JSON data to a file is similar to the
example in Writing JSON Data Using a Generator. The code to parse JSON data from a
file is similar to the example in Reading JSON Data Using a Parser.
19.7.2 Running the jsonpstreaming Example Application
This section describes how to run the jsonpstreaming example application using
NetBeans IDE and from the command line.
19.7.2.1 To Run the jsonpstreaming Example Application Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/web/jsonp
4.
Select the jsonpstreaming folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the jsonpstreaming project and select Run.
This command builds and packages the application into a WAR file
(jsonpstreaming.war) located in the target directory, deploys it to the server, and
opens a web browser window with the following URL:
http://localhost:8080/jsonpstreaming/
7.
Edit the data on the page and click Write a JSON Object to a File to submit the
form and write a JSON object to a text file. The following page shows the contents
of the text file.
8.
Click Parse JSON from File. The following page contains a table that lists the
parser events for the JSON data in the text file.
19.7.2.2 To Run the jsonpstreaming Example Application Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
JSON Processing
19-11
Further Information about the Java API for JSON Processing
tut-install/examples/web/jsonp/jsonpstreaming/
3.
Enter the following command to deploy the application:
mvn install
4.
Open a web browser window and enter the following URL:
http://localhost:8080/jsonpstreaming/
5.
Edit the data on the page and click Write a JSON Object to a File to submit the
form and write a JSON object to a text file. The following page shows the contents
of the text file.
6.
Click Parse JSON from File. The following page contains a table that lists the
parser events for the JSON data in the text file.
19.8 Further Information about the Java API for JSON Processing
For more information on JSON processing in Java EE, see the Java API for JSON
Processing specification:
http://www.jcp.org/en/jsr/detail?id=353
19-12 The Java EE 7 Tutorial
20
Internationalizing and Localizing Web
Applications
20
The process of preparing an application to support more than one language and data
format is called internationalization. Localization is the process of adapting an
internationalized application to support a specific region or locale. Examples of
locale-dependent information include messages and user interface labels, character
sets and encoding, and date and currency formats. Although all client user interfaces
should be internationalized and localized, it is particularly important for web
applications because of the global nature of the web.
The following topics are addressed here:
■
Java Platform Localization Classes
■
Providing Localized Messages and Labels
■
Date and Number Formatting
■
Character Sets and Encodings
20.1 Java Platform Localization Classes
In the Java platform, java.util.Locale
(http://docs.oracle.com/javase/7/docs/api/java/util/Locale.html)
represents a specific geographical, political, or cultural region. The string
representation of a locale consists of the international standard two-character
abbreviation for language and country and an optional variant, all separated by
underscore (_) characters. Examples of locale strings include fr (French), de_CH (Swiss
German), and en_US_POSIX (English on a POSIX-compliant platform).
Locale-sensitive data is stored in a java.util.ResourceBundle
(http://docs.oracle.com/javase/7/docs/api/java/util/ResourceBund
le.html). A resource bundle contains key-value pairs, where the keys uniquely
identify a locale-specific object in the bundle. A resource bundle can be backed by a
text file (properties resource bundle) or a class (list resource bundle) containing the
pairs. You construct a resource bundle instance by appending a locale string
representation to a base name.
The Duke's Bookstore application (see Chapter 57, "Duke's Bookstore Case Study
Example") contains resource bundles with the base name messages.properties for the
locales de (German), es (Spanish), and fr (French). The default locale, en (English),
which is specified in the faces-config.xml file, uses the resource bundle with the base
name, messages.properties.
Internationalizing and Localizing Web Applications 20-1
Providing Localized Messages and Labels
For more details on internationalization and localization in the Java platform, see
http://docs.oracle.com/javase/tutorial/i18n/index.html.
20.2 Providing Localized Messages and Labels
Messages and labels should be tailored according to the conventions of a user's
language and region. There are two approaches to providing localized messages and
labels in a web application.
■
■
Provide a version of the web page in each of the target locales and have a
controller servlet dispatch the request to the appropriate page depending on the
requested locale. This approach is useful if large amounts of data on a page or an
entire web application need to be internationalized.
Isolate any locale-sensitive data on a page into resource bundles, and access the
data so that the corresponding translated message is fetched automatically and
inserted into the page. Thus, instead of creating strings directly in your code, you
create a resource bundle that contains translations and read the translations from
that bundle using the corresponding key.
The Duke's Bookstore application follows the second approach. Here are a few lines
from the default resource bundle messages.properties:
TitleShoppingCart=Shopping Cart
TitleReceipt=Receipt
TitleBookCatalog=Book Catalog
TitleCashier=Cashier
TitleBookDescription=Book Description
Visitor=You are visitor number
What=What We\'re Reading
20.2.1 Establishing the Locale
To get the correct strings for a given user, a web application either retrieves the locale
(set by a browser language preference) from the request using the getLocale method,
or allows the user to explicitly select the locale.
A component can explicitly set the locale by using the fmt:setLocale tag.
The locale-config element in the configuration file registers the default locale and
also registers other supported locales. This element in Duke's Bookstore registers
English as the default locale and indicates that German, French, and Spanish are
supported locales.
<locale-config>
<default-locale>en</default-locale>
<supported-locale>es</supported-locale>
<supported-locale>de</supported-locale>
<supported-locale>fr</supported-locale>
</locale-config>
The LocaleBean in the Duke's Bookstore application uses the getLocale method to
retrieve the locale.
public class LocaleBean {
...
private FacesContext ctx = FacesContext.getCurrentInstance();
private Locale locale = ctx.getViewRoot().getLocale();;
...
20-2 The Java EE 7 Tutorial
Providing Localized Messages and Labels
}
20.2.2 Setting the Resource Bundle
The resource bundle is set with the resource-bundle element in the configuration file.
The setting for Duke's Bookstore looks like this:
<resource-bundle>
<base-name>
javaeetutorial.dukesbookstore.web.messages.Messages
</base-name>
<var>bundle</var>
</resource-bundle>
After the locale is set, the controller of a web application could retrieve the resource
bundle for that locale and save it as a session attribute (see Associating Objects with a
Session) for use by other components or simply be used to return a text string
appropriate for the selected locale:
public String toString(Locale locale) {
ResourceBundle res =
ResourceBundle.getBundle(
"javaeetutorial.dukesbookstore.web.messages.Messages", locale);
return res.getString(name() + ".string");
}
Alternatively, an application could use the f:loadBundle tag to set the resource
bundle. This tag loads the correct resource bundle according to the locale stored in
FacesContext.
<f:loadBundle basename="javaeetutorial.dukesbookstore.web.messages.Messages"
var="bundle"/>
Resource bundles containing messages that are explicitly referenced from a JavaServer
Faces tag attribute using a value expression must be registered using the
resource-bundle element of the configuration file.
For more information on using this element, see Registering Application Messages.
20.2.3 Retrieving Localized Messages
A web component written in the Java programming language retrieves the resource
bundle from the session:
ResourceBundle messages = (ResourceBundle)session.getAttribute("messages");
Then it looks up the string associated with the key person.lastName as follows:
messages.getString("person.lastName");
You can only use a message or messages tag to display messages that are queued onto
a component as a result of a converter or validator being registered on the component.
The following example shows a message tag that displays the error message queued
on the userNo input component if the validator registered on the component fails to
validate the value the user enters into the component.
<h:inputText id="userNo" value="#{UserNumberBean.userNumber}">
<f:validateLongRange minimum="0" maximum="10" />
</h:inputText>
...
<h:message style="color: red; text-decoration: overline"
Internationalizing and Localizing Web Applications 20-3
Date and Number Formatting
id="errors1" for="userNo"/>
For more information on using the message or messages tags, see Displaying Error
Messages with the h:message and h:messages Tags.
Messages that are not queued on a component and are therefore not loaded
automatically are referenced using a value expression. You can reference a localized
message from almost any JavaServer Faces tag attribute.
The value expression that references a message has the same notation whether you
loaded the resource bundle with the loadBundle tag or registered it with the
resource-bundle element in the configuration file.
The value expression notation is var.message, in which var matches the var attribute
of the loadBundle tag or the var element defined in the resource-bundle element of
the configuration file, and message matches the key of the message contained in the
resource bundle, referred to by the var attribute.
Here is an example from bookcashier.xhtml in Duke's Bookstore:
<h:outputLabel for="name" value="#{bundle.Name}" />
Notice that bundle matches the var element from the configuration file and that Name
matches the key in the resource bundle.
20.3 Date and Number Formatting
Java programs use the DateFormat.getDateInstance(int, locale) method to parse
and format dates in a locale-sensitive manner. Java programs use the
NumberFormat.getXXXInstance(locale) method, where XXX can be Currency,
Number, or Percent, to parse and format numerical values in a locale-sensitive manner.
An application can use date/time and number converters to format dates and
numbers in a locale-sensitive manner. For example, a shipping date could be
converted as follows:
<h:outputText value="#{cashier.shipDate}">
<f:convertDateTime dateStyle="full"/>
</h:outputText>
For information on JavaServer Faces converters, see Using the Standard Converters.
20.4 Character Sets and Encodings
The following sections describe character sets and character encodings.
20.4.1 Character Sets
A character set is a set of textual and graphic symbols, each of which is mapped to a
set of nonnegative integers.
The first character set used in computing was US-ASCII. It is limited in that it can
represent only American English. US-ASCII contains uppercase and lowercase Latin
alphabets, numerals, punctuation, a set of control codes, and a few miscellaneous
symbols.
Unicode defines a standardized, universal character set that can be extended to
accommodate additions. When the Java program source file encoding doesn't support
Unicode, you can represent Unicode characters as escape sequences by using the
notation \uXXXX, where XXXX is the character's 16-bit representation in hexadecimal.
20-4 The Java EE 7 Tutorial
Character Sets and Encodings
For example, the Spanish version of a message file could use Unicode for non-ASCII
characters, as follows:
admin.nav.main=P\u00e1gina principal de administraci\u00f3n
20.4.2 Character Encoding
A character encoding maps a character set to units of a specific width and defines byte
serialization and ordering rules. Many character sets have more than one encoding.
For example, Java programs can represent Japanese character sets using the EUC-JP or
Shift-JIS encodings, among others. Each encoding has rules for representing and
serializing a character set.
The ISO 8859 series defines 13 character encodings that can represent texts in dozens
of languages. Each ISO 8859 character encoding can have up to 256 characters.
ISO-8859-1 (Latin-1) comprises the ASCII character set, characters with diacritics
(accents, diaereses, cedillas, circumflexes, and so on), and additional symbols.
UTF-8 (Unicode Transformation Format, 8-bit form) is a variable-width character
encoding that encodes 16-bit Unicode characters as one to four bytes. A byte in UTF-8
is equivalent to 7-bit ASCII if its high-order bit is zero; otherwise, the character
comprises a variable number of bytes.
UTF-8 is compatible with the majority of existing web content and provides access to
the Unicode character set. Current versions of browsers and email clients support
UTF-8. In addition, many web standards specify UTF-8 as their character encoding.
For example, UTF-8 is one of the two required encodings for XML documents (the
other is UTF-16).
Web components usually use PrintWriter to produce responses; PrintWriter
automatically encodes using ISO-8859-1. Servlets can also output binary data using
OutputStream classes, which perform no encoding. An application that uses a
character set that cannot use the default encoding must explicitly set a different
encoding.
Internationalizing and Localizing Web Applications 20-5
Character Sets and Encodings
20-6 The Java EE 7 Tutorial
Part IV
Part IV
Bean Validation
Part IV explores Java API for JavaBean Validation ("Bean Validation"). This part
contains the following chapters:
■
Chapter 21, "Introduction to Bean Validation"
■
Chapter 22, "Bean Validation: Advanced Topics"
21
Introduction to Bean Validation
21
Validating input received from the user to maintain data integrity is an important part
of application logic. Validation of data can take place at different layers in even the
simplest of applications, as shown in Developing a Simple Facelets Application: The
guessnumber-jsf Example Application. The guessnumber-jsf example application
validates the user input (in the h:inputText tag) for numerical data at the presentation
layer and for a valid range of numbers at the business layer.
The Java API for JavaBean Validation ("Bean Validation") provides a facility for
validating objects, object members, methods, and constructors. In Java EE
environments, Bean Validation integrates with Java EE containers and services to
allow developers to easily define and enforce validation constraints. Bean Validation is
available as part of the Java EE 7 platform.
The following topics are addressed here:
■
Using Bean Validation Constraints
■
Validating Null and Empty Strings
■
Validating Constructors and Methods
■
Further Information about Bean Validation
21.1 Using Bean Validation Constraints
The Bean Validation model is supported by constraints in the form of annotations
placed on a field, method, or class of a JavaBeans component, such as a managed bean.
Constraints can be built in or user defined. User-defined constraints are called custom
constraints. Several built-in constraints are available in the
javax.validation.constraints package. Table 21–1 lists all the built-in constraints.
See Creating Custom Constraints for information on creating custom constraints.
Table 21–1
Constraint
Built-In Bean Validation Constraints
Description
@AssertFalse The value of the field or
property must be false.
@AssertTrue
The value of the field or
property must be true.
Example
@AssertFalse
boolean isUnsupported;
@AssertTrue
boolean isActive;
Introduction to Bean Validation
21-1
Using Bean Validation Constraints
Table 21–1 (Cont.) Built-In Bean Validation Constraints
Constraint
Description
@DecimalMax
The value of the field or
@DecimalMax("30.00")
property must be a
BigDecimal discount;
decimal value lower than
or equal to the number in
the value element.
@DecimalMin
The value of the field or
property must be a
decimal value greater
than or equal to the
number in the value
element.
@Digits
The value of the field or
@Digits(integer=6, fraction=2)
property must be a
BigDecimal price;
number within a
specified range. The
integer element specifies
the maximum integral
digits for the number, and
the fraction element
specifies the maximum
fractional digits for the
number.
@Future
The value of the field or
property must be a date
in the future.
@Max
The value of the field or
@Max(10)
property must be an
int quantity;
integer value lower than
or equal to the number in
the value element.
@Min
The value of the field or
@Min(5)
property must be an
int quantity;
integer value greater than
or equal to the number in
the value element.
@NotNull
The value of the field or
property must not be
null.
@NotNull
String username;
@Null
The value of the field or
property must be null.
@Null
String unusedString;
@Past
The value of the field or
property must be a date
in the past.
@Past
Date birthday;
@Pattern
The value of the field or
property must match the
regular expression
defined in the regexp
element.
@Pattern(regexp="\\(\\d{3}\\)\\d{3}-\\d{4}")
String phoneNumber;
21-2 The Java EE 7 Tutorial
Example
@DecimalMin("5.00")
BigDecimal discount;
@Future
Date eventDate;
Using Bean Validation Constraints
Table 21–1 (Cont.) Built-In Bean Validation Constraints
Constraint
Description
Example
@Size
The size of the field or
@Size(min=2, max=240)
property is evaluated and String briefMessage;
must match the specified
boundaries. If the field or
property is a String, the
size of the string is
evaluated. If the field or
property is a Collection,
the size of the Collection
is evaluated. If the field or
property is a Map, the size
of the Map is evaluated. If
the field or property is an
array, the size of the array
is evaluated. Use one of
the optional max or min
elements to specify the
boundaries.
In the following example, a constraint is placed on a field using the built-in @NotNull
constraint:
public class Name {
@NotNull
private String firstname;
@NotNull
private String lastname;
...
}
You can also place more than one constraint on a single JavaBeans component object.
For example, you can place an additional constraint for size of field on the firstname
and the lastname fields:
public class Name {
@NotNull
@Size(min=1, max=16)
private String firstname;
@NotNull
@Size(min=1, max=16)
private String lastname;
...
}
The following example shows a method with a user-defined constraint that checks for
a predefined email address pattern, such as a corporate email account:
@ValidEmail
public String getEmailAddress() {
return emailAddress;
}
For a built-in constraint, a default implementation is available. A user-defined or
custom constraint needs a validation implementation. In the preceding example, the
@ValidEmail custom constraint needs an implementation class.
Introduction to Bean Validation
21-3
Validating Null and Empty Strings
Any validation failures are gracefully handled and can be displayed by the
h:messages tag.
Any managed bean that contains Bean Validation annotations automatically gets
validation constraints placed on the fields on a JavaServer Faces application's web
pages.
For more information on using validation constraints, see the following:
■
Chapter 22, "Bean Validation: Advanced Topics"
■
Validating Resource Data with Bean Validation
■
Validating Persistent Fields and Properties
21.2 Validating Null and Empty Strings
The Java programming language distinguishes between null and empty strings. An
empty string is a string instance of zero length, whereas a null string has no value at
all.
An empty string is represented as "". It is a character sequence of zero characters. A
null string is represented by null. It can be described as the absence of a string
instance.
Managed bean elements represented as a JavaServer Faces text component such as
inputText are initialized with the value of the empty string by the JavaServer Faces
implementation. Validating these strings can be an issue when user input for such
fields is not required. Consider the following example, in which the string testString
is a bean variable that will be set using input entered by the user. In this case, the user
input for the field is not required.
if (testString==null) {
doSomething();
} else {
doAnotherThing();
}
By default, the doAnotherThing method is called even when the user enters no data,
because the testString element has been initialized with the value of an empty string.
In order for the Bean Validation model to work as intended, you must set the context
parameter javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL to
true in the web deployment descriptor file, web.xml:
<context-param>
<param-name>
javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
</param-name>
<param-value>true</param-value>
</context-param>
This parameter enables the JavaServer Faces implementation to treat empty strings as
null.
Suppose, on the other hand, that you have a @NotNull constraint on an element,
meaning that input is required. In this case, an empty string will pass this validation
constraint. However, if you set the context parameter javax.faces.INTERPRET_EMPTY_
STRING_SUBMITTED_VALUES_AS_NULL to true, the value of the managed bean attribute
is passed to the Bean Validation runtime as a null value, causing the @NotNull
constraint to fail.
21-4 The Java EE 7 Tutorial
Validating Constructors and Methods
21.3 Validating Constructors and Methods
Bean Validation constraints may be placed on the parameters of nonstatic methods and
constructors and on the return values of nonstatic methods. Static methods and
constructors will not be validated.
public class Employee {
...
public Employee (@NotNull String name) { ... }
public void setSalary(
@NotNull
@Digits(integer=6, fraction=2) BigDecimal salary,
@NotNull
@ValidCurrency
String currencyType) {
...
}
...
}
In this example, the Employee class has a constructor constraint requiring a name and
has two sets of method parameter constraints. The amount of the salary for the
employee must not be null, cannot be greater than six digits to the left of the decimal
point, and cannot have more than two digits to the right of the decimal place. The
currency type must not be null and is validated using a custom constraint.
If you add method constraints to classes in an object hierarchy, special care must be
taken to avoid unintended behavior by subtypes. See Using Method Constraints in
Type Hierarchies for more information.
21.3.1 Cross-Parameter Constraints
Constraints that apply to multiple parameters are called cross-parameter constraints,
and may be applied at the method or constructor level.
@ConsistentPhoneParameters
@NotNull
public Employee (String name, String officePhone, String mobilePhone) {
...
}
In this example, a custom cross-parameter constraint, @ConsistentPhoneParameters,
validates that the format of the phone numbers passed into the constructor match. The
@NotNull constraint applies to all the parameters in the constructor.
Introduction to Bean Validation
21-5
Further Information about Bean Validation
Tip: Cross-parameter constraint annotations are applied directly to
the method or constructor. Return value constraints are also applied
directly to the method or constructor. To avoid confusion as to where
the constraint applies, parameter or return value, choose a name for
any custom constraints that identifies where the constraint applies.
For instance, the preceding example applies a custom constraint,
@ConsistentPhoneParameters, that indicates that it applies to the
parameters of the method or constructor.
When you create a custom constraint that applies to both method
parameters and return values, the validationAppliesTo element of
the constraint annotation may be set to ConstraintTarget.RETURN_
VALUE or ConstraintTarget.PARAMETERS to explicitly set the target of
the validation constraint.
21.3.2 Identifying Parameter Constraint Violations
If a ConstraintViolationException occurs during a method call, the Bean Validation
runtime returns a parameter index to identify which parameter caused the constraint
violation. The parameter index is in the form argPARAMETER_INDEX, where
PARAMETER_INDEX is an integer that starts at 0 for the first parameter of the method
or constructor.
21.3.3 Adding Constraints to Method Return Values
To validate the return value for a method, you can apply constraints directly to the
method or constructor declaration.
@NotNull
public Employee getEmployee() { ... }
Cross-parameter constraints are also applied at the method level. Custom constraints
that could be applied to both the return value and the method parameters have an
ambiguous constraint target. To avoid this ambiguity, add a validationAppliesTo
element to the constraint annotation definition with the default set to either
ConstraintTarget.RETURN_VALUE or ConstraintTarget.PARAMETERS to explicitly set
the target of the validation constraint.
@Manager(validationAppliesTo=ConstraintTarget.RETURN_VALUE)
public Employee getManager(Employee employee) { ... }
See Removing Ambiguity in Constraint Targets for more information.
21.4 Further Information about Bean Validation
For more information on Bean Validation, see
■
Bean Validation 1.1 Specification:
http://www.jcp.org/en/jsr/detail?id=349
■
Bean Validation Specification website:
http://beanvalidation.org/
21-6 The Java EE 7 Tutorial
22
Bean Validation: Advanced Topics
22
This chapter describes how to create custom constraints, custom validator messages,
and constraint groups using the Java API for JavaBeans Validation (Bean Validation).
The following topics are addressed here:
■
Creating Custom Constraints
■
Customizing Validator Messages
■
Grouping Constraints
■
Using Method Constraints in Type Hierarchies
22.1 Creating Custom Constraints
Bean Validation defines annotations, interfaces, and classes to allow developers to
create custom constraints.
22.1.1 Using the Built-In Constraints to Make a New Constraint
Bean Validation includes several built-in constraints that can be combined to create
new, reusable constraints. This can simplify constraint definition by allowing
developers to define a custom constraint made up of several built-in constraints that
may then be applied to component attributes with a single annotation.
@Pattern.List({
@Pattern(regexp = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\."
+"[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*"
+"@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")
})
@Constraint(validatedBy = {})
@Documented
@Target({ElementType.METHOD,
ElementType.FIELD,
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Email {
String message() default "{invalid.email}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Bean Validation: Advanced Topics 22-1
Customizing Validator Messages
@Target({ElementType.METHOD,
ElementType.FIELD,
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
Email[] value();
}
}
This custom constraint can then be applied to an attribute.
...
@Email
protected String email;
...
22.1.2 Removing Ambiguity in Constraint Targets
Custom constraints that can be applied to both return values and method parameters
require a validationAppliesTo element to identify the target of the constraint.
@Constraint(validatedBy=MyConstraintValidator.class)
@Target({ METHOD, FIELD, TYPE, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface MyConstraint {
String message() default "{com.example.constraint.MyConstraint.message}";
Class<?>[] groups() default {};
ConstraintTarget validationAppliesTo() default ConstraintTarget.PARAMETERS;
...
}
This constraint sets the validationAppliesTo target by default to the method
parameters.
@MyConstraint(validationAppliesTo=ConstraintTarget.RETURN_TYPE)
public String doSomething(String param1, String param2) { ... }
In the preceding example, the target is set to the return value of the method.
22.2 Customizing Validator Messages
Bean Validation includes a resource bundle of default messages for the built-in
constraints. These messages can be customized and can be localized for
non-English-speaking locales.
22.2.1 The ValidationMessages Resource Bundle
The ValidationMessages resource bundle and the locale variants of this resource
bundle contain strings that override the default validation messages. The
ValidationMessages resource bundle is typically a properties file,
ValidationMessages.properties, in the default package of an application.
22-2 The Java EE 7 Tutorial
Grouping Constraints
22.2.1.1 Localizing Validation Messages
Locale variants of ValidationMessages.properties are added by appending an
underscore and the locale prefix to the base name of the file. For example, the Spanish
locale variant resource bundle would be ValidationMessages_es.properties.
22.3 Grouping Constraints
Constraints may be added to one or more groups. Constraint groups are used to create
subsets of constraints so that only certain constraints will be validated for a particular
object. By default, all constraints are included in the Default constraint group.
Constraint groups are represented by interfaces.
public interface Employee {}
public interface Contractor {}
Constraint groups can inherit from other groups.
public interface Manager extends Employee {}
When a constraint is added to an element, the constraint declares the groups to which
that constraint belongs by specifying the class name of the group interface name in the
groups element of the constraint.
@NotNull(groups=Employee.class)
Phone workPhone;
Multiple groups can be declared by surrounding the groups with braces ({ and }) and
separating the groups' class names with commas.
@NotNull(groups={ Employee.class, Contractor.class })
Phone workPhone;
If a group inherits from another group, validating that group results in validating all
constraints declared as part of the supergroup. For example, validating the Manager
group results in the workPhone field being validated, because Employee is a
superinterface of Manager.
22.3.1 Customizing Group Validation Order
By default, constraint groups are validated in no particular order. There are cases in
which some groups should be validated before others. For example, in a particular
class, basic data should be validated before more advanced data.
To set the validation order for a group, add a javax.validation.GroupSequence
annotation to the interface definition, listing the order in which the validation should
occur.
@GroupSequence({Default.class, ExpensiveValidationGroup.class})
public interface FullValidationGroup {}
When validating FullValidationGroup, first the Default group is validated. If all the
data passes validation, then the ExpensiveValidationGroup group is validated. If a
constraint is part of both the Default and the ExpensiveValidationGroup groups, the
constraint is validated as part of the Default group and will not be validated on the
subsequent ExpensiveValidationGroup pass.
Bean Validation: Advanced Topics 22-3
Using Method Constraints in Type Hierarchies
22.4 Using Method Constraints in Type Hierarchies
If you add validation constraints to objects in an inheritance hierarchy, take special
care to avoid unintended errors when using subtypes.
For a given type, subtypes should be able to be substituted without encountering
errors. For example, if you have a Person class and an Employee subclass that extends
Person, you should be able to use Employee instances wherever you might use Person
instances. If Employee overrides a method in Person by adding method parameter
constraints, code that works correctly with Person objects may throw validation
exceptions with Employee objects.
The following code shows an incorrect use of method parameter constraints within a
class hierarchy:
public class Person {
...
public void setEmail(String email) { ... }
}
public class Employee extends Person {
...
@Override
public void setEmail(@Verified String email) { ... }
}
By adding the @Verified constraint to Employee.setEmail, parameters that were valid
with Person.setEmail will not be valid with Employee.setEmail. This is called
strengthening the preconditions (that is, the method parameters) of a subtype's
method. You may not strengthen the preconditions of subtype method calls.
Similarly, the return values from method calls should not be weakened in subtypes.
The following code shows an incorrect use of constraints on method return values in a
class hierarchy:
public class Person {
...
@Verified
public Email getEmail() { ... }
}
public class Employee extends Person {
...
@Override
public Email getEmail() { ... }
}
In this example, the Employee.getEmail method removes the @Verified constraint on
the return value. Return values that would be not pass validation when calling
Person.getEmail are allowed when calling Employee.getEmail. This is called
weakening the postconditions (that is, return values) of a subtype. You may not
weaken the postconditions of a subtype method call.
If your type hierarchy strengthens the preconditions or weakens the postconditions of
subtype method calls, a javax.validation.ConstraintDeclarationException will be
thrown by the Bean Validation runtime.
Classes that implement several interfaces that each have the same method signature,
known as parallel types, need to be aware of the constraints applied to the interfaces
that they implement to avoid strengthening the preconditions. For example:
22-4 The Java EE 7 Tutorial
Using Method Constraints in Type Hierarchies
public interface PaymentService {
void processOrder(Order order, double amount);
...
}
public interface CreditCardPaymentService {
void processOrder(@NotNull Order order, @NotNull double amount);
...
}
public class MyPaymentService implements PaymentService,
CreditCardPaymentService {
@Override
public void processOrder(Order order, double amount) { ... }
...
}
In this case, MyPaymentService has the constraints from the processOrder method in
CreditCardPaymentService, but client code that calls PaymentService.processOrder
doesn't expect these constraints. This is another example of strengthening the
preconditions of a subtype and will result in a ConstraintDeclarationException.
22.4.1 Rules for Using Method Constraints in Type Hierarchies
The following rules define how method validation constraints should be used in type
hierarchies.
■
■
■
Do not add method parameter constraints to overridden or implemented methods
in a subtype.
Do not add method parameter constraints to overridden or implemented methods
in a subtype that was originally declared in several parallel types.
You may add return value constraints to an overridden or implemented method in
a subtype.
Bean Validation: Advanced Topics 22-5
Using Method Constraints in Type Hierarchies
22-6 The Java EE 7 Tutorial
Part V
Part V
Contexts and Dependency Injection for
Java EE
Part V explores Contexts and Dependency Injection for Java EE (CDI). This part
contains the following chapters:
■
Chapter 23, "Introduction to Contexts and Dependency Injection for Java EE"
■
Chapter 24, "Running the Basic Contexts and Dependency Injection Examples"
■
Chapter 25, "Contexts and Dependency Injection for Java EE: Advanced Topics"
■
Chapter 26, "Running the Advanced Contexts and Dependency Injection
Examples"
23
Introduction to Contexts and Dependency
Injection for Java EE
23
Contexts and Dependency Injection for Java EE (CDI) is one of several Java EE features
that help to knit together the web tier and the transactional tier of the Java EE
platform. CDI is a set of services that, used together, make it easy for developers to use
enterprise beans along with JavaServer Faces technology in web applications.
Designed for use with stateful objects, CDI also has many broader uses, allowing
developers a great deal of flexibility to integrate various kinds of components in a
loosely coupled but typesafe way.
CDI 1.1 is specified by JSR 346. Related specifications that CDI uses include the
following:
■
■
JSR 330, Dependency Injection for Java
The Managed Beans specification, an offshoot of the Java EE 7 platform
specification (JSR 342)
The following topics are addressed here:
■
Getting Started
■
Overview of CDI
■
About Beans
■
About CDI Managed Beans
■
Beans as Injectable Objects
■
Using Qualifiers
■
Injecting Beans
■
Using Scopes
■
Giving Beans EL Names
■
Adding Setter and Getter Methods
■
Using a Managed Bean in a Facelets Page
■
Injecting Objects by Using Producer Methods
■
Configuring a CDI Application
■
■
Using the @PostConstruct and @PreDestroy Annotations with CDI Managed Bean
Classes
Further Information about CDI
Introduction to Contexts and Dependency Injection for Java EE 23-1
Getting Started
23.1 Getting Started
Contexts and Dependency Injection (CDI) enables your objects to have their
dependencies provided to them automatically, instead of creating them or receiving
them as parameters. CDI also manages the lifecycle of those dependencies for you.
For example, consider the following servlet:
@WebServlet("/cdiservlet")
public class NewServlet extends HttpServlet {
private Message message;
@Override
public void init() {
message = new MessageB();
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.getWriter().write(message.get());
}
}
This servlet needs an instance of an object that implements the Message interface:
public interface Message {
public String get();
}
The servlet creates itself an instance of the following object:
public class MessageB implements Message {
public MessageB() { }
@Override
public String get() {
return "message B";
}
}
Using CDI, this servlet can declare its dependency on a Message instance and have it
injected automatically by the CDI runtime. The new servlet code is the following:
@WebServlet("/cdiservlet")
public class NewServlet extends HttpServlet {
@Inject private Message message;
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.getWriter().write(message.get());
}
}
The CDI runtime looks for classes that implement the Message interface, finds the
MessageB class, creates a new instance of it, and injects it into the servlet at runtime. To
manage the lifecycle of the new instance, the CDI runtime needs to know what the
scope of the instance should be. In this example, the servlet only needs the instance to
process an HTTP request; the instance can then be garbage collected. This is specified
using the javax.enterprise.context.RequestScoped annotation:
23-2 The Java EE 7 Tutorial
Overview of CDI
@RequestScoped
public class MessageB implements Message { ... }
For more information on scopes, see Using Scopes.
The MessageB class is a CDI bean. CDI beans are classes that CDI can instantiate,
manage, and inject automatically to satisfy the dependencies of other objects. Almost
any Java class can be managed and injected by CDI. For more information on beans,
see About Beans. A JAR or WAR file that contains a CDI bean is a bean archive. For
more information on packaging bean archives, see Configuring a CDI Application in
this chapter and Packaging CDI Applications in Chapter 25, "Contexts and
Dependency Injection for Java EE: Advanced Topics".
In this example, MessageB is the only class that implements the Message interface. If an
application has more than one implementation of an interface, CDI provides
mechanisms that you can use to select which implementation to inject. For more
information, see Using Qualifiers in this chapter and Using Alternatives in CDI
Applications in Chapter 25, "Contexts and Dependency Injection for Java EE:
Advanced Topics".
23.2 Overview of CDI
The most fundamental services provided by CDI are as follows.
■
■
Contexts: This service enables you to bind the lifecycle and interactions of stateful
components to well-defined but extensible lifecycle contexts.
Dependency injection: This service enables you to inject components into an
application in a typesafe way and to choose at deployment time which
implementation of a particular interface to inject.
In addition, CDI provides the following services:
■
■
■
■
■
■
Integration with the Expression Language (EL), which allows any component to be
used directly within a JavaServer Faces page or a JavaServer Pages page
The ability to decorate injected components
The ability to associate interceptors with components using typesafe interceptor
bindings
An event-notification model
A web conversation scope in addition to the three standard scopes (request,
session, and application) defined by the Java Servlet specification
A complete Service Provider Interface (SPI) that allows third-party frameworks to
integrate cleanly in the Java EE 7 environment
A major theme of CDI is loose coupling. CDI does the following:
■
■
Decouples the server and the client by means of well-defined types and qualifiers,
so that the server implementation may vary
Decouples the lifecycles of collaborating components by
–
Making components contextual, with automatic lifecycle management
–
Allowing stateful components to interact like services, purely by message
passing
■
Completely decouples message producers from consumers, by means of events
■
Decouples orthogonal concerns by means of Java EE interceptors
Introduction to Contexts and Dependency Injection for Java EE 23-3
About Beans
Along with loose coupling, CDI provides strong typing by
■
■
Eliminating lookup using string-based names for wiring and correlations so that
the compiler will detect typing errors
Allowing the use of declarative Java annotations to specify everything, largely
eliminating the need for XML deployment descriptors, and making it easy to
provide tools that introspect the code and understand the dependency structure at
development time
23.3 About Beans
CDI redefines the concept of a bean beyond its use in other Java technologies, such as
the JavaBeans and Enterprise JavaBeans (EJB) technologies. In CDI, a bean is a source
of contextual objects that define application state and/or logic. A Java EE component
is a bean if the lifecycle of its instances may be managed by the container according to
the lifecycle context model defined in the CDI specification.
More specifically, a bean has the following attributes:
■
A (nonempty) set of bean types
■
A (nonempty) set of qualifiers (see Using Qualifiers)
■
A scope (see Using Scopes)
■
Optionally, a bean EL name (see Giving Beans EL Names)
■
A set of interceptor bindings
■
A bean implementation
A bean type defines a client-visible type of the bean. Almost any Java type may be a
bean type of a bean.
■
■
■
■
■
A bean type may be an interface, a concrete class, or an abstract class and may be
declared final or have final methods.
A bean type may be a parameterized type with type parameters and type
variables.
A bean type may be an array type. Two array types are considered identical only if
the element type is identical.
A bean type may be a primitive type. Primitive types are considered to be identical
to their corresponding wrapper types in java.lang.
A bean type may be a raw type.
23.4 About CDI Managed Beans
A managed bean is implemented by a Java class, which is called its bean class. A
top-level Java class is a managed bean if it is defined to be a managed bean by any
other Java EE technology specification, such as the JavaServer Faces technology
specification, or if it meets all the following conditions.
■
It is not a nonstatic inner class.
■
It is a concrete class or is annotated @Decorator.
■
■
It is not annotated with an EJB component-defining annotation or declared as an
EJB bean class in ejb-jar.xml.
It has an appropriate constructor. That is, one of the following is the case.
23-4 The Java EE 7 Tutorial
Using Qualifiers
–
The class has a constructor with no parameters.
–
The class declares a constructor annotated @Inject.
No special declaration, such as an annotation, is required to define a managed bean.
23.5 Beans as Injectable Objects
The concept of injection has been part of Java technology for some time. Since the Java
EE 5 platform was introduced, annotations have made it possible to inject resources
and some other kinds of objects into container-managed objects. CDI makes it possible
to inject more kinds of objects and to inject them into objects that are not
container-managed.
The following kinds of objects can be injected:
■
(Almost) any Java class
■
Session beans
■
Java EE resources: data sources, Java Message Service topics, queues, connection
factories, and the like
■
Persistence contexts (Java Persistence API EntityManager objects)
■
Producer fields
■
Objects returned by producer methods
■
Web service references
■
Remote enterprise bean references
For example, suppose that you create a simple Java class with a method that returns a
string:
package greetings;
public class Greeting {
public String greet(String name) {
return "Hello, " + name + ".";
}
}
This class becomes a bean that you can then inject into another class. This bean is not
exposed to the EL in this form. Giving Beans EL Names explains how you can make a
bean accessible to the EL.
23.6 Using Qualifiers
You can use qualifiers to provide various implementations of a particular bean type. A
qualifier is an annotation that you apply to a bean. A qualifier type is a Java
annotation defined as @Target({METHOD, FIELD, PARAMETER, TYPE}) and
@Retention(RUNTIME).
For example, you could declare an @Informal qualifier type and apply it to another
class that extends the Greeting class. To declare this qualifier type, you would use the
following code:
package greetings;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
Introduction to Contexts and Dependency Injection for Java EE 23-5
Injecting Beans
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Informal {}
You can then define a bean class that extends the Greeting class and uses this
qualifier:
package greetings;
@Informal
public class InformalGreeting extends Greeting {
public String greet(String name) {
return "Hi, " + name + "!";
}
}
Both implementations of the bean can now be used in the application.
If you define a bean with no qualifier, the bean automatically has the qualifier
@Default. The unannotated Greeting class could be declared as follows:
package greetings;
import javax.enterprise.inject.Default;
@Default
public class Greeting {
public String greet(String name) {
return "Hello, " + name + ".";
}
}
23.7 Injecting Beans
In order to use the beans you create, you inject them into yet another bean that can
then be used by an application, such as a JavaServer Faces application. For example,
you might create a bean called Printer into which you would inject one of the
Greeting beans:
import javax.inject.Inject;
public class Printer {
@Inject Greeting greeting;
...
}
This code injects the @Default Greeting implementation into the bean. The following
code injects the @Informal implementation:
23-6 The Java EE 7 Tutorial
Using Scopes
import javax.inject.Inject;
public class Printer {
@Inject @Informal Greeting greeting;
...
}
More is needed for the complete picture of this bean. Its use of scope needs to be
understood. In addition, for a JavaServer Faces application, the bean needs to be
accessible through the EL.
23.8 Using Scopes
For a web application to use a bean that injects another bean class, the bean needs to
be able to hold state over the duration of the user's interaction with the application.
The way to define this state is to give the bean a scope. You can give an object any of
the scopes described in Table 23–1, depending on how you are using it.
Table 23–1
Scopes
Scope
Annotation
Duration
Request
@RequestScoped
A user's interaction with a web application in a
single HTTP request.
Session
@SessionScoped
A user's interaction with a web application
across multiple HTTP requests.
Application
@ApplicationScoped
Shared state across all users' interactions with a
web application.
Dependent
@Dependent
The default scope if none is specified; it means
that an object exists to serve exactly one client
(bean) and has the same lifecycle as that client
(bean).
Conversation
@ConversationScoped
A user's interaction with a servlet, including
JavaServer Faces applications. The
conversation scope exists within
developer-controlled boundaries that extend it
across multiple requests for long-running
conversations. All long-running conversations
are scoped to a particular HTTP servlet session
and may not cross session boundaries.
The first three scopes are defined by both JSR 346 and the JavaServer Faces
specification. The last two are defined by JSR 346.
All predefined scopes except @Dependent are contextual scopes. CDI places beans of
contextual scope in the context whose lifecycle is defined by the Java EE specifications.
For example, a session context and its beans exist during the lifetime of an HTTP
session. Injected references to the beans are contextually aware. The references always
apply to the bean that is associated with the context for the thread that is making the
reference. The CDI container ensures that the objects are created and injected at the
correct time as determined by the scope that is specified for these objects.
You can also define and implement custom scopes, but that is an advanced topic.
Custom scopes are likely to be used by those who implement and extend the CDI
specification.
Introduction to Contexts and Dependency Injection for Java EE 23-7
Giving Beans EL Names
A scope gives an object a well-defined lifecycle context. A scoped object can be
automatically created when it is needed and automatically destroyed when the context
in which it was created ends. Moreover, its state is automatically shared by any clients
that execute in the same context.
Java EE components, such as servlets and enterprise beans, and JavaBeans
components do not by definition have a well-defined scope. These components are one
of the following:
■
■
■
Singletons, such as Enterprise JavaBeans singleton beans, whose state is shared
among all clients
Stateless objects, such as servlets and stateless session beans, which do not contain
client-visible state
Objects that must be explicitly created and destroyed by their client, such as
JavaBeans components and stateful session beans, whose state is shared by explicit
reference passing between clients
If, however, you create a Java EE component that is a managed bean, it becomes a
scoped object, which exists in a well-defined lifecycle context.
The web application for the Printer bean will use a simple request and response
mechanism, so the managed bean can be annotated as follows:
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
@RequestScoped
public class Printer {
@Inject @Informal Greeting greeting;
...
}
Beans that use session, application, or conversation scope must be serializable, but
beans that use request scope do not have to be serializable.
23.9 Giving Beans EL Names
To make a bean accessible through the EL, use the @Named built-in qualifier:
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
@Named
@RequestScoped
public class Printer {
@Inject @Informal Greeting greeting;
...
}
The @Named qualifier allows you to access the bean by using the bean name, with the
first letter in lowercase. For example, a Facelets page would refer to the bean as
printer.
You can specify an argument to the @Named qualifier to use a nondefault name:
@Named("MyPrinter")
23-8 The Java EE 7 Tutorial
Using a Managed Bean in a Facelets Page
With this annotation, the Facelets page would refer to the bean as MyPrinter.
23.10 Adding Setter and Getter Methods
To make the state of the managed bean accessible, you need to add setter and getter
methods for that state. The createSalutation method calls the bean's greet method,
and the getSalutation method retrieves the result.
Once the setter and getter methods have been added, the bean is complete. The final
code looks like this:
package greetings;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
@Named
@RequestScoped
public class Printer {
@Inject @Informal Greeting greeting;
private String name;
private String salutation;
public void createSalutation() {
this.salutation = greeting.greet(name);
}
public String getSalutation() {
return salutation;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
23.11 Using a Managed Bean in a Facelets Page
To use the managed bean in a Facelets page, you typically create a form that uses user
interface elements to call its methods and display their results. This example provides
a button that asks the user to type a name, retrieves the salutation, and then displays
the text in a paragraph below the button:
<h:form id="greetme">
<p><h:outputLabel value="Enter your name: " for="name"/>
<h:inputText id="name" value="#{printer.name}"/></p>
<p><h:commandButton value="Say Hello"
action="#{printer.createSalutation}"/></p>
<p><h:outputText value="#{printer.salutation}"/></p>
</h:form>
Introduction to Contexts and Dependency Injection for Java EE 23-9
Injecting Objects by Using Producer Methods
23.12 Injecting Objects by Using Producer Methods
Producer methods provide a way to inject objects that are not beans, objects whose
values may vary at runtime, and objects that require custom initialization. For
example, if you want to initialize a numeric value defined by a qualifier named
@MaxNumber, you can define the value in a managed bean and then define a producer
method, getMaxNumber, for it:
private int maxNumber = 100;
...
@Produces @MaxNumber int getMaxNumber() {
return maxNumber;
}
When you inject the object in another managed bean, the container automatically
invokes the producer method, initializing the value to 100:
@Inject @MaxNumber private int maxNumber;
If the value can vary at runtime, the process is slightly different. For example, the
following code defines a producer method that generates a random number defined
by a qualifier called @Random:
private java.util.Random random =
new java.util.Random( System.currentTimeMillis() );
java.util.Random getRandom() {
return random;
}
@Produces @Random int next() {
return getRandom().nextInt(maxNumber);
}
When you inject this object in another managed bean, you declare a contextual
instance of the object:
@Inject @Random Instance<Integer> randomInt;
You then call the get method of the Instance:
this.number = randomInt.get();
23.13 Configuring a CDI Application
When your beans are annotated with a scope type, the server recognizes the
application as a bean archive and no additional configuration is required. The possible
scope types for CDI beans are listed in Using Scopes.
CDI uses an optional deployment descriptor named beans.xml. Like other Java EE
deployment descriptors, the configuration settings in beans.xml are used in addition
to annotation settings in CDI classes. The settings in beans.xml override the
annotation settings if there is a conflict. An archive must contain the beans.xml
deployment descriptor only in certain limited situations, described in Chapter 25,
"Contexts and Dependency Injection for Java EE: Advanced Topics".
For a web application, the beans.xml deployment descriptor, if present, must be in the
WEB-INF directory. For EJB modules or JAR files, the beans.xml deployment descriptor,
if present, must be in the META-INF directory.
23-10 The Java EE 7 Tutorial
Using the @PostConstruct and @PreDestroy Annotations with CDI Managed Bean Classes
23.14 Using the @PostConstruct and @PreDestroy Annotations with CDI
Managed Bean Classes
CDI managed bean classes and their superclasses support the annotations for
initializing and for preparing for the destruction of a bean. These annotations are
defined in JSR 250: Common Annotations for the Java platform
(http://jcp.org/en/jsr/detail?id=250).
23.14.1 To Initialize a Managed Bean Using the @PostConstruct Annotation
Initializing a managed bean specifies the lifecycle callback method that the CDI
framework should call after dependency injection but before the class is put into
service.
1.
In the managed bean class or any of its superclasses, define a method that
performs the initialization that you require.
2.
Annotate the declaration of the method with the
javax.annotation.PostConstruct annotation.
When the managed bean is injected into a component, CDI calls the method after all
injection has occurred and after all initializers have been called.
As mandated in JSR 250, if the annotated method is declared
in a superclass, the method is called unless a subclass of the declaring
class overrides the method.
Note:
The UserNumberBean managed bean in The guessnumber-cdi CDI Example uses
@PostConstruct to annotate a method that resets all bean fields:
@PostConstruct
public void reset () {
this.minimum = 0;
this.userNumber = 0;
this.remainingGuesses = 0;
this.maximum = maxNumber;
this.number = randomInt.get();
}
23.14.2 To Prepare for the Destruction of a Managed Bean Using the @PreDestroy
Annotation
Preparing for the destruction of a managed bean specifies the lifecycle call back
method that signals that an application component is about to be destroyed by the
container.
1.
In the managed bean class or any of its superclasses, prepare for the destruction of
the managed bean.
In this method, perform any cleanup that is required before the bean is destroyed,
such as releasing a resource that the bean has been holding.
2.
Annotate the declaration of the method with the javax.annotation.PreDestroy
annotation.
CDI calls this method before starting to destroy the bean.
Introduction to Contexts and Dependency Injection for Java EE
23-11
Further Information about CDI
23.15 Further Information about CDI
For more information about CDI, see
■
Contexts and Dependency Injection for Java EE specification:
http://jcp.org/en/jsr/detail?id=346
■
An introduction to Contexts and Dependency Injection for Java EE:
http://docs.jboss.org/weld/reference/latest/en-US/html/
■
Dependency Injection for Java specification:
http://jcp.org/en/jsr/detail?id=330
■
Managed Beans specification, which is part of the Java Platform, Enterprise
Edition 7 (Java EE 7) Specification:
http://jcp.org/en/jsr/detail?id=342
23-12 The Java EE 7 Tutorial
24
Running the Basic Contexts and
Dependency Injection Examples
24
This chapter describes in detail how to build and run simple examples that use CDI.
The examples are in the tut-install/examples/cdi/ directory.
To build and run the examples, you will do the following.
1.
Use NetBeans IDE or the Maven tool to compile and package the example.
2.
Use NetBeans IDE or the Maven tool to deploy the example.
3.
Run the example in a web browser.
See Chapter 2, "Using the Tutorial Examples", for basic information on installing,
building, and running the examples.
The following topics are addressed here:
■
The simplegreeting CDI Example
■
The guessnumber-cdi CDI Example
24.1 The simplegreeting CDI Example
The simplegreeting example illustrates some of the most basic features of CDI:
scopes, qualifiers, bean injection, and accessing a managed bean in a JavaServer Faces
application. When you run the example, you click a button that presents either a
formal or an informal greeting, depending on how you edited one of the classes. The
example includes four source files, a Facelets page and template, and configuration
files.
24.1.1 The simplegreeting Source Files
The four source files for the simplegreeting example are
■
■
■
The default Greeting class, shown in Beans as Injectable Objects
The @Informal qualifier interface definition and the InformalGreeting class that
implements the interface, both shown in Using Qualifiers
The Printer managed bean class, which injects one of the two interfaces, shown in
full in Adding Setter and Getter Methods
The source files are located in the
tut-install/examples/cdi/simplegreeting/src/main/java/javaeetutorial/simplegr
eeting directory.
Running the Basic Contexts and Dependency Injection Examples
24-1
The simplegreeting CDI Example
24.1.2 The Facelets Template and Page
To use the managed bean in a simple Facelets application, you can use a very simple
template file and index.xhtml page. The template page, template.xhtml, looks like
this:
<?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 lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<h:outputStylesheet library="css" name="default.css"/>
<title><ui:insert name="title">Default Title</ui:insert></title>
</h:head>
<body>
<div id="container">
<div id="header">
<h2><ui:insert name="head">Head</ui:insert></h2>
</div>
<div id="space">
<p></p>
</div>
<div id="content">
<ui:insert name="content"/>
</div>
</div>
</body>
</html>
To create the Facelets page, you can redefine the title and head, then add a small form
to the content:
<?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 lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<ui:composition template="/template.xhtml">
<ui:define name="title">Simple Greeting</ui:define>
<ui:define name="head">Simple Greeting</ui:define>
<ui:define name="content">
<h:form id="greetme">
<p><h:outputLabel value="Enter your name: " for="name"/>
<h:inputText id="name" value="#{printer.name}"/></p>
<p><h:commandButton value="Say Hello"
action="#{printer.createSalutation}"/></p>
<p><h:outputText value="#{printer.salutation}"/> </p>
</h:form>
</ui:define>
</ui:composition>
24-2 The Java EE 7 Tutorial
The simplegreeting CDI Example
</html>
The form asks the user to enter a name. The button is labeled Say Hello, and the action
defined for it is to call the createSalutation method of the Printer managed bean.
This method in turn calls the greet method of the defined Greeting class.
The output text for the form is the value of the greeting returned by the setter method.
Depending on whether the default or the @Informal version of the greeting is injected,
this is one of the following, where name is the name entered by the user:
Hello, name.
Hi, name!
The Facelets page and template are located in the
tut-install/examples/cdi/simplegreeting/src/main/webapp/ directory.
The simple CSS file that is used by the Facelets page is in the following location:
tut-install/examples/cdi/simplegreeting/src/main/webapp/resources/css/default.css
24.1.3 Running the simplegreeting Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
simplegreeting application.
24.1.3.1 To Build, Package, and Run the simplegreeting Example Using NetBeans
IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/cdi
4.
Select the simplegreeting folder.
5.
Click Open Project.
6.
To modify the Printer.java file, perform these steps:
a.
Expand the Source Packages node.
b.
Expand the greetings node.
c.
Double-click the Printer.java file.
d.
In the editor, comment out the @Informal annotation:
@Inject
//@Informal
Greeting greeting;
e.
7.
Save the file.
In the Projects tab, right-click the simplegreeting project and select Build.
This command builds and packages the application into a WAR file,
simplegreeting.war, located in the target directory, and then deploys it to
GlassFish Server.
Running the Basic Contexts and Dependency Injection Examples
24-3
The guessnumber-cdi CDI Example
24.1.3.2 To Build, Package, and Deploy the simplegreeting Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/cdi/simplegreeting/
3.
Enter the following command to deploy the application:
mvn install
This command builds and packages the application into a WAR file,
simplegreeting.war, located in the target directory, and then deploys it to
GlassFish Server.
24.1.3.3 To Run the simplegreeting Example
1.
In a web browser, enter the following URL:
http://localhost:8080/simplegreeting
The Simple Greeting page opens.
2.
Enter a name in the field.
For example, suppose that you enter Duke.
3.
Click Say Hello.
If you did not modify the Printer.java file, the following text string appears
below the button:
Hi, Duke!
If you commented out the @Informal annotation in the Printer.java file, the
following text string appears below the button:
Hello, Duke.
24.2 The guessnumber-cdi CDI Example
The guessnumber-cdi example, somewhat more complex than the simplegreeting
example, illustrates the use of producer methods and of session and application scope.
The example is a game in which you try to guess a number in fewer than ten attempts.
It is similar to the guessnumber-jsf example described in Chapter 8, "Introduction to
Facelets", except that you can keep guessing until you get the right answer or until you
use up your ten attempts.
The example includes four source files, a Facelets page and template, and
configuration files. The configuration files and the template are the same as those used
for the simplegreeting example.
24.2.1 The guessnumber-cdi Source Files
The four source files for the guessnumber-cdi example are
■
The @MaxNumber qualifier interface
■
The @Random qualifier interface
■
The Generator managed bean, which defines producer methods
24-4 The Java EE 7 Tutorial
The guessnumber-cdi CDI Example
■
The UserNumberBean managed bean
The source files are located in the
tut-install/examples/cdi/guessnumber-cdi/src/main/java/javaeetutorial/guessnu
mber directory.
24.2.1.1 The @MaxNumber and @Random Qualifier Interfaces
The @MaxNumber qualifier interface is defined as follows:
package guessnumber;
import
import
import
import
import
import
import
import
import
java.lang.annotation.Documented;
static java.lang.annotation.ElementType.FIELD;
static java.lang.annotation.ElementType.METHOD;
static java.lang.annotation.ElementType.PARAMETER;
static java.lang.annotation.ElementType.TYPE;
java.lang.annotation.Retention;
static java.lang.annotation.RetentionPolicy.RUNTIME;
java.lang.annotation.Target;
javax.inject.Qualifier;
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
@Documented
@Qualifier
public @interface MaxNumber {
}
The @Random qualifier interface is defined as follows:
package guessnumber;
import
import
import
import
import
import
import
import
import
java.lang.annotation.Documented;
static java.lang.annotation.ElementType.FIELD;
static java.lang.annotation.ElementType.METHOD;
static java.lang.annotation.ElementType.PARAMETER;
static java.lang.annotation.ElementType.TYPE;
java.lang.annotation.Retention;
static java.lang.annotation.RetentionPolicy.RUNTIME;
java.lang.annotation.Target;
javax.inject.Qualifier;
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
@Documented
@Qualifier
public @interface Random {
}
24.2.1.2 The Generator Managed Bean
The Generator managed bean contains the two producer methods for the application.
The bean has the @ApplicationScoped annotation to specify that its context extends
for the duration of the user's interaction with the application:
package guessnumber;
import java.io.Serializable;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
Running the Basic Contexts and Dependency Injection Examples
24-5
The guessnumber-cdi CDI Example
@ApplicationScoped
public class Generator implements Serializable {
private static final long serialVersionUID = -7213673465118041882L;
private final java.util.Random random =
new java.util.Random( System.currentTimeMillis() );
private final int maxNumber = 100;
java.util.Random getRandom() {
return random;
}
@Produces @Random int next() {
return getRandom().nextInt(maxNumber + 1);
}
@Produces @MaxNumber int getMaxNumber() {
return maxNumber;
}
}
24.2.1.3 The UserNumberBean Managed Bean
The UserNumberBean managed bean, the managed bean for the JavaServer Faces
application, provides the basic logic for the game. This bean does the following:
■
Implements setter and getter methods for the bean fields
■
Injects the two qualifier objects
■
■
■
Provides a reset method that allows you to begin a new game after you complete
one
Provides a check method that determines whether the user has guessed the
number
Provides a validateNumberRange method that determines whether the user's input
is correct
The bean is defined as follows:
package guessnumber;
import
import
import
import
import
import
import
import
import
import
java.io.Serializable;
javax.annotation.PostConstruct;
javax.enterprise.context.SessionScoped;
javax.enterprise.inject.Instance;
javax.faces.application.FacesMessage;
javax.faces.component.UIComponent;
javax.faces.component.UIInput;
javax.faces.context.FacesContext;
javax.inject.Inject;
javax.inject.Named;
@Named
@SessionScoped
public class UserNumberBean implements Serializable {
private static final long serialVersionUID = -7698506329160109476L;
24-6 The Java EE 7 Tutorial
The guessnumber-cdi CDI Example
private
private
private
private
int number;
Integer userNumber;
int minimum;
int remainingGuesses;
@MaxNumber
@Inject
private int maxNumber;
private int maximum;
@Random
@Inject
Instance<Integer> randomInt;
public UserNumberBean() {
}
public int getNumber() {
return number;
}
public void setUserNumber(Integer user_number) {
userNumber = user_number;
}
public Integer getUserNumber() {
return userNumber;
}
public int getMaximum() {
return (this.maximum);
}
public void setMaximum(int maximum) {
this.maximum = maximum;
}
public int getMinimum() {
return (this.minimum);
}
public void setMinimum(int minimum) {
this.minimum = minimum;
}
public int getRemainingGuesses() {
return remainingGuesses;
}
public String check() throws InterruptedException {
if (userNumber > number) {
maximum = userNumber - 1;
}
if (userNumber < number) {
minimum = userNumber + 1;
}
if (userNumber == number) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Correct!"));
Running the Basic Contexts and Dependency Injection Examples
24-7
The guessnumber-cdi CDI Example
}
remainingGuesses--;
return null;
}
@PostConstruct
public void reset() {
this.minimum = 0;
this.userNumber = 0;
this.remainingGuesses = 10;
this.maximum = maxNumber;
this.number = randomInt.get();
}
public void validateNumberRange(FacesContext context,
UIComponent toValidate,
Object value) {
int input = (Integer) value;
if (input < minimum || input > maximum) {
((UIInput) toValidate).setValid(false);
FacesMessage message = new FacesMessage("Invalid guess");
context.addMessage(toValidate.getClientId(context), message);
}
}
}
24.2.2 The Facelets Page
This example uses the same template that the simplegreeting example uses. The
index.xhtml file, however, is more complex.
<?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 lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<ui:composition template="/template.xhtml">
<ui:define name="title">Guess My Number</ui:define>
<ui:define name="head">Guess My Number</ui:define>
<ui:define name="content">
<h:form id="GuessMain">
<div style="color: black; font-size: 24px;">
<p>I'm thinking of a number from
<span style="color: blue">#{userNumberBean.minimum}</span>
to
<span style="color: blue">#{userNumberBean.maximum}</span>.
You have
<span style="color: blue">
#{userNumberBean.remainingGuesses}
</span>
guesses.</p>
</div>
<h:panelGrid border="0" columns="5" style="font-size: 18px;">
<h:outputLabel for="inputGuess">Number:</h:outputLabel>
<h:inputText id="inputGuess"
24-8 The Java EE 7 Tutorial
The guessnumber-cdi CDI Example
value="#{userNumberBean.userNumber}"
required="true" size="3"
disabled="#{userNumberBean.number eq userNumberBean.userNumber or
userNumberBean.remainingGuesses le 0}"
validator="#{userNumberBean.validateNumberRange}">
</h:inputText>
<h:commandButton id="GuessButton" value="Guess"
action="#{userNumberBean.check}"
disabled="#{userNumberBean.number eq userNumberBean.userNumber or
userNumberBean.remainingGuesses le 0}"/>
<h:commandButton id="RestartButton" value="Reset"
action="#{userNumberBean.reset}"
immediate="true" />
<h:outputText id="Higher" value="Higher!"
rendered="#{userNumberBean.number gt userNumberBean.userNumber and
userNumberBean.userNumber ne 0}"
style="color: #d20005"/>
<h:outputText id="Lower" value="Lower!"
rendered="#{userNumberBean.number lt userNumberBean.userNumber and
userNumberBean.userNumber ne 0}"
style="color: #d20005"/>
</h:panelGrid>
<div style="color: #d20005; font-size: 14px;">
<h:messages id="messages" globalOnly="false"/>
</div>
</h:form>
</ui:define>
</ui:composition>
</html>
The Facelets page presents the user with the minimum and maximum values and the
number of guesses remaining. The user's interaction with the game takes place within
the panelGrid table, which contains an input field, Guess and Reset buttons, and a
field that appears if the guess is higher or lower than the correct number. Every time
the user clicks the Guess button, the userNumberBean.check method is called to reset
the maximum or minimum value or, if the guess is correct, to generate a FacesMessage
to that effect. The method that determines whether each guess is valid is
userNumberBean.validateNumberRange.
24.2.3 Running the guessnumber-cdi Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
guessnumber-cdi application.
24.2.3.1 To Build, Package, and Deploy the guessnumber-cdi Example Using
NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/cdi
4.
Select the guessnumber-cdi folder.
5.
Click Open Project.
Running the Basic Contexts and Dependency Injection Examples
24-9
The guessnumber-cdi CDI Example
6.
In the Projects tab, right-click the guessnumber-cdi project and select Build.
This command builds and packages the application into a WAR file,
guessnumber-cdi.war, located in the target directory, and then deploys it to
GlassFish Server.
24.2.3.2 To Build, Package, and Deploy the guessnumber-cdi Example Using
Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/cdi/guessnumber-cdi/
3.
Enter the following command to deploy the application:
mvn install
This command builds and packages the application into a WAR file,
guessnumber-cdi.war, located in the target directory, and then deploys it to
GlassFish Server.
24.2.3.3 To Run the guessnumber Example
1.
In a web browser, enter the following URL:
http://localhost:8080/guessnumber-cdi
The Guess My Number page opens.
2.
On the Guess My Number page, enter a number in the Number field and click
Guess.
The minimum and maximum values are modified, along with the remaining
number of guesses.
3.
Keep guessing numbers until you get the right answer or run out of guesses.
If you get the right answer or run out of guesses, the input field and Guess button
are grayed out.
4.
Click Reset to play the game again with a new random number.
24-10 The Java EE 7 Tutorial
25
Contexts and Dependency Injection for Java
EE: Advanced Topics
25
This chapter describes more advanced features of Contexts and Dependency Injection
for Java EE (CDI). Specifically, it covers additional features CDI provides to enable
loose coupling of components with strong typing, in addition to those described in
Overview of CDI.
The following topics are addressed here:
■
Packaging CDI Applications
■
Using Alternatives in CDI Applications
■
Using Producer Methods, Producer Fields, and Disposer Methods in CDI
Applications
■
Using Predefined Beans in CDI Applications
■
Using Events in CDI Applications
■
Using Interceptors in CDI Applications
■
Using Decorators in CDI Applications
■
Using Stereotypes in CDI Applications
25.1 Packaging CDI Applications
When you deploy a Java EE application, CDI looks for beans inside bean archives. A
bean archive is any module that contains beans that the CDI runtime can manage and
inject. There are two kinds of bean archives: explicit bean archives and implicit bean
archives.
An explicit bean archive is an archive that contains a beans.xml deployment
descriptor, which can be an empty file, contain no version number, or contain the
version number 1.1 with the bean-discovery-mode attribute set to all. For example:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
...
</beans>
CDI can manage and inject any bean in an explicit archive, except those annotated
with @Vetoed.
Contexts and Dependency Injection for Java EE: Advanced Topics
25-1
Using Alternatives in CDI Applications
An implicit bean archive is an archive that contains some beans annotated with a
scope type, contains no beans.xml deployment descriptor, or contains a beans.xml
deployment descriptor with the bean-discovery-mode attribute set to annotated.
In an implicit archive, CDI can only manage and inject beans annotated with a scope
type.
For a web application, the beans.xml deployment descriptor, if present, must be in the
WEB-INF directory. For EJB modules or JAR files, the beans.xml deployment descriptor,
if present, must be in the META-INF directory.
25.2 Using Alternatives in CDI Applications
When you have more than one version of a bean that you use for different purposes,
you can choose between them during the development phase by injecting one qualifier
or another, as shown in The simplegreeting CDI Example.
Instead of having to change the source code of your application, however, you can
make the choice at deployment time by using alternatives.
Alternatives are commonly used for purposes such as the following:
■
■
■
To handle client-specific business logic that is determined at runtime
To specify beans that are valid for a particular deployment scenario (for example,
when country-specific sales tax laws require country-specific sales tax business
logic)
To create dummy (mock) versions of beans to be used for testing
To make a bean available for lookup, injection, or EL resolution using this mechanism,
give it a javax.enterprise.inject.Alternative annotation and then use the
alternatives element to specify it in the beans.xml file.
For example, you might want to create a full version of a bean and also a simpler
version that you use only for certain kinds of testing. The example described in The
encoder Example: Using Alternatives contains two such beans, CoderImpl and
TestCoderImpl. The test bean is annotated as follows:
@Alternative
public class TestCoderImpl implements Coder { ... }
The full version is not annotated:
public class CoderImpl implements Coder { ... }
The managed bean injects an instance of the Coder interface:
@Inject
Coder coder;
The alternative version of the bean is used by the application only if that version is
declared as follows in the beans.xml file:
<beans ...>
<alternatives>
<class>javaeetutorial.encoder.TestCoderImpl</class>
</alternatives>
</beans>
If the alternatives element is commented out in the beans.xml file, the CoderImpl
class is used.
25-2 The Java EE 7 Tutorial
Using Alternatives in CDI Applications
You can also have several beans that implement the same interface, all annotated
@Alternative. In this case, you must specify in the beans.xml file which of these
alternative beans you want to use. If CoderImpl were also annotated @Alternative,
one of the two beans would always have to be specified in the beans.xml file.
The alternatives that you specify in the beans.xml file apply only to classes in the same
archive. Use the @Priority annotation to specify alternatives globally for an
application that consists of multiple modules, as in the following example:
@Alternative
@Priority(Interceptor.Priority.APPLICATION+10)
public class TestCoderImpl implements Coder { ... }
The alternative with higher priority value is selected if several alternative beans that
implement the same interface are annotated with @Priority. You do not need to
specify the alternative in the beans.xml file when you use the @Priority annotation.
25.2.1 Using Specialization
Specialization has a function similar to that of alternatives in that it allows you to
substitute one bean for another. However, you might want to make one bean override
the other in all cases. Suppose you defined the following two beans:
@Default @Asynchronous
public class AsynchronousService implements Service { ... }
@Alternative
public class MockAsynchronousService extends AsynchronousService { ... }
If you then declared MockAsynchronousService as an alternative in your beans.xml
file, the following injection point would resolve to MockAsynchronousService:
@Inject Service service;
The following, however, would resolve to AsynchronousService rather than
MockAsynchronousService, because MockAsynchronousService does not have the
@Asynchronous qualifier:
@Inject @Asynchronous Service service;
To make sure that MockAsynchronousService was always injected, you would have to
implement all bean types and bean qualifiers of AsynchronousService. However, if
AsynchronousService declared a producer method or observer method, even this
cumbersome mechanism would not ensure that the other bean was never invoked.
Specialization provides a simpler mechanism.
Specialization happens at development time as well as at runtime. If you declare that
one bean specializes another, it extends the other bean class, and at runtime the
specialized bean completely replaces the other bean. If the first bean is produced by
means of a producer method, you must also override the producer method.
You specialize a bean by giving it the javax.enterprise.inject.Specializes
annotation. For example, you might declare a bean as follows:
@Specializes
public class MockAsynchronousService extends AsynchronousService { ... }
In this case, the MockAsynchronousService class will always be invoked instead of the
AsynchronousService class.
Contexts and Dependency Injection for Java EE: Advanced Topics
25-3
Using Producer Methods, Producer Fields, and Disposer Methods in CDI Applications
Usually, a bean marked with the @Specializes annotation is also an alternative and is
declared as an alternative in the beans.xml file. Such a bean is meant to stand in as a
replacement for the default implementation, and the alternative implementation
automatically inherits all qualifiers of the default implementation as well as its EL
name, if it has one.
25.3 Using Producer Methods, Producer Fields, and Disposer Methods in
CDI Applications
A producer method generates an object that can then be injected. Typically, you use
producer methods in the following situations:
■
When you want to inject an object that is not itself a bean
■
When the concrete type of the object to be injected may vary at runtime
■
When the object requires some custom initialization that the bean constructor does
not perform
For more information on producer methods, see Injecting Objects by Using Producer
Methods.
A producer field is a simpler alternative to a producer method; it is a field of a bean
that generates an object. It can be used instead of a simple getter method. Producer
fields are particularly useful for declaring Java EE resources such as data sources, JMS
resources, and web service references.
A producer method or field is annotated with the
javax.enterprise.inject.Produces annotation.
25.3.1 Using Producer Methods
A producer method can allow you to select a bean implementation at runtime instead
of at development time or deployment time. For example, in the example described in
The producermethods Example: Using a Producer Method to Choose a Bean
Implementation, the managed bean defines the following producer method:
@Produces
@Chosen
@RequestScoped
public Coder getCoder() {
switch (coderType) {
case TEST:
return new TestCoderImpl();
case SHIFT:
return new CoderImpl();
default:
return null;
}
}
Here, getCoder becomes in effect a getter method, and when the coder property is
injected with the same qualifier and other annotations as the method, the selected
version of the interface is used.
@Inject
@Chosen
@RequestScoped
Coder coder;
25-4 The Java EE 7 Tutorial
Using Predefined Beans in CDI Applications
Specifying the qualifier is essential: It tells CDI which Coder to inject. Without it, the
CDI implementation would not be able to choose between CoderImpl, TestCoderImpl,
and the one returned by getCoder and would cancel deployment, informing the user
of the ambiguous dependency.
25.3.2 Using Producer Fields to Generate Resources
A common use of a producer field is to generate an object such as a JDBC DataSource
or a Java Persistence API EntityManager (see Chapter 37, "Introduction to the Java
Persistence API," for more information). The object can then be managed by the
container. For example, you could create a @UserDatabase qualifier and then declare a
producer field for an entity manager as follows:
@Produces
@UserDatabase
@PersistenceContext
private EntityManager em;
The @UserDatabase qualifier can be used when you inject the object into another bean,
RequestBean, elsewhere in the application:
@Inject
@UserDatabase
EntityManager em;
...
The producerfields Example: Using Producer Fields to Generate Resources shows how
to use producer fields to generate an entity manager. You can use a similar mechanism
to inject @Resource, @EJB, or @WebServiceRef objects.
To minimize the reliance on resource injection, specify the producer field for the
resource in one place in the application, and then inject the object wherever in the
application you need it.
25.3.3 Using a Disposer Method
You can use a producer method or a producer field to generate an object that needs to
be removed when its work is completed. If you do, you need a corresponding disposer
method, annotated with a @Disposes annotation. For example, you can close the entity
manager as follows:
public void close(@Disposes @UserDatabase EntityManager em) {
em.close();
}
The disposer method is called automatically when the context ends (in this case, at the
end of the conversation, because RequestBean has conversation scope), and the
parameter in the close method receives the object produced by the producer field.
25.4 Using Predefined Beans in CDI Applications
Java EE provides predefined beans that implement the following interfaces.
■
■
javax.transaction.UserTransaction: A Java Transaction API (JTA) user
transaction.
java.security.Principal: The abstract notion of a principal, which represents
any entity, such as an individual, a corporation, or a login ID. Whenever the
Contexts and Dependency Injection for Java EE: Advanced Topics
25-5
Using Predefined Beans in CDI Applications
injected principal is accessed, it always represents the identity of the current caller.
For example, a principal is injected into a field at initialization. Later, a method
that uses the injected principal is called on the object into which the principal was
injected. In this situation, the injected principal represents the identity of the
current caller when the method is run.
■
■
■
■
■
javax.validation.Validator: A validator for bean instances. The bean that
implements this interface enables a Validator object for the default bean
validation object ValidatorFactory to be injected.
javax.validation.ValidatorFactory: A factory class for returning initialized
Validator instances. The bean that implements this interface enables the default
bean validation ValidatorFactory object to be injected.
javax.servlet.http.HttpServletRequest: An HTTP request from a client. The
bean that implements this interface enables a servlet to obtain all the details of a
request.
javax.servlet.http.HttpSession: An HTTP session between a client and a
server. The bean that implements this interface enables a servlet to access
information about a session and to bind objects to a session.
javax.servlet.ServletContext: A context object that servlets can use to
communicate with the servlet container.
To inject a predefined bean, create an injection point to obtain an instance of the bean
by using the javax.annotation.Resource annotation for resources or the
javax.inject.Inject annotation for CDI beans. For the bean type, specify the class
name of the interface the bean implements.
Table 25–1
Injection of Predefined Beans
Predefined Bean
Resource or CDI Bean
Injection Example
UserTransaction
Resource
@Resource UserTransaction transaction;
Principal
Resource
@Resource Principal principal;
Validator
Resource
@Resource Validator validator;
ValidatorFactory
Resource
@Resource ValidatorFactory factory;
HttpServletRequest
CDI bean
@Inject HttpServletRequest req;
HttpSession
CDI bean
@Inject HttpSession session;
ServletContext
CDI bean
@Inject ServletContext context;
Predefined beans are injected with dependent scope and the predefined default
qualifier @Default.
For more information about injecting resources, see Resource Injection.
The following code snippet shows how to use the @Resource and @Inject annotations
to inject predefined beans. This code snippet injects a user transaction and a context
object into the servlet class TransactionServlet. The user transaction is an instance of
the predefined bean that implements the javax.transaction.UserTransaction
interface. The context object is an instance of the predefined bean that implements the
javax.servlet.ServletContext interface.
import
import
import
import
javax.annotation.Resource;
javax.inject.Inject;
javax.servlet.http.HttpServlet;
javax.transaction.UserTransaction;
25-6 The Java EE 7 Tutorial
Using Events in CDI Applications
...
public class TransactionServlet extends HttpServlet {
@Resource UserTransaction transaction;
@Inject ServletContext context;
...
}
25.5 Using Events in CDI Applications
Events allow beans to communicate without any compile-time dependency. One bean
can define an event, another bean can fire the event, and yet another bean can handle
the event. The beans can be in separate packages and even in separate tiers of the
application.
25.5.1 Defining Events
An event consists of the following:
■
The event object, a Java object
■
Zero or more qualifier types, the event qualifiers
For example, in the billpayment example described in The billpayment Example:
Using Events and Interceptors, a PaymentEvent bean defines an event using three
properties, which have setter and getter methods:
public String paymentType;
public BigDecimal value;
public Date datetime;
public PaymentEvent() {
}
The example also defines qualifiers that distinguish between two kinds of
PaymentEvent. Every event also has the default qualifier @Any.
25.5.2 Using Observer Methods to Handle Events
An event handler uses an observer method to consume events.
Each observer method takes as a parameter an event of a specific event type that is
annotated with the @Observes annotation and with any qualifiers for that event type.
The observer method is notified of an event if the event object matches the event type
and if all the qualifiers of the event match the observer method event qualifiers.
The observer method can take other parameters in addition to the event parameter.
The additional parameters are injection points and can declare qualifiers.
The event handler for the billpayment example, PaymentHandler, defines two
observer methods, one for each type of PaymentEvent:
public void creditPayment(@Observes @Credit PaymentEvent event) {
...
}
public void debitPayment(@Observes @Debit PaymentEvent event) {
...
}
Observer methods can also be conditional or transactional:
Contexts and Dependency Injection for Java EE: Advanced Topics
25-7
Using Events in CDI Applications
■
A conditional observer method is notified of an event only if an instance of the
bean that defines the observer method already exists in the current context. To
declare a conditional observer method, specify notifyObserver=IF_EXISTS as an
argument to @Observes:
@Observes(notifyObserver=IF_EXISTS)
To obtain the default unconditional behavior, you can specify
@Observes(notifyObserver=ALWAYS).
■
A transactional observer method is notified of an event during the
before-completion or after-completion phase of the transaction in which the event
was fired. You can also specify that the notification is to occur only after the
transaction has completed successfully or unsuccessfully. To specify a
transactional observer method, use any of the following arguments to @Observes:
@Observes(during=BEFORE_COMPLETION)
@Observes(during=AFTER_COMPLETION)
@Observes(during=AFTER_SUCCESS)
@Observes(during=AFTER_FAILURE)
To obtain the default nontransactional behavior, specify @Observes(during=IN_
PROGRESS).
An observer method that is called before completion of a transaction may call the
setRollbackOnly method on the transaction instance to force a transaction
rollback.
Observer methods may throw exceptions. If a transactional observer method throws
an exception, the exception is caught by the container. If the observer method is
nontransactional, the exception terminates processing of the event, and no other
observer methods for the event are called.
25.5.3 Firing Events
To activate an event, call the javax.enterprise.event.Event.fire method. This
method fires an event and notifies any observer methods.
In the billpayment example, a managed bean called PaymentBean fires the appropriate
event by using information it receives from the user interface. There are actually four
event beans, two for the event object and two for the payload. The managed bean
injects the two event beans. The pay method uses a switch statement to choose which
event to fire, using new to create the payload.
@Inject
@Credit
Event<PaymentEvent> creditEvent;
@Inject
@Debit
Event<PaymentEvent> debitEvent;
private static final int DEBIT = 1;
private static final int CREDIT = 2;
private int paymentOption = DEBIT;
...
@Logged
25-8 The Java EE 7 Tutorial
Using Interceptors in CDI Applications
public String pay() {
...
switch (paymentOption) {
case DEBIT:
PaymentEvent debitPayload = new PaymentEvent();
// populate payload ...
debitEvent.fire(debitPayload);
break;
case CREDIT:
PaymentEvent creditPayload = new PaymentEvent();
// populate payload ...
creditEvent.fire(creditPayload);
break;
default:
logger.severe("Invalid payment option!");
}
...
}
The argument to the fire method is a PaymentEvent that contains the payload. The
fired event is then consumed by the observer methods.
25.6 Using Interceptors in CDI Applications
An interceptor is a class used to interpose in method invocations or lifecycle events
that occur in an associated target class. The interceptor performs tasks, such as logging
or auditing, that are separate from the business logic of the application and are
repeated often within an application. Such tasks are often called cross-cutting tasks.
Interceptors allow you to specify the code for these tasks in one place for easy
maintenance. When interceptors were first introduced to the Java EE platform, they
were specific to enterprise beans. On the Java EE 7 platform, you can use them with
Java EE managed objects of all kinds, including managed beans.
For information on Java EE interceptors, see Chapter 54, "Using Java EE Interceptors".
An interceptor class often contains a method annotated @AroundInvoke, which
specifies the tasks the interceptor will perform when intercepted methods are invoked.
It can also contain a method annotated @PostConstruct, @PreDestroy, @PrePassivate,
or @PostActivate, to specify lifecycle callback interceptors, and a method annotated
@AroundTimeout, to specify EJB timeout interceptors. An interceptor class can contain
more than one interceptor method, but it must have no more than one method of each
type.
Along with an interceptor, an application defines one or more interceptor binding
types, which are annotations that associate an interceptor with target beans or
methods. For example, the billpayment example contains an interceptor binding type
named @Logged and an interceptor named LoggedInterceptor. The interceptor
binding type declaration looks something like a qualifier declaration, but it is
annotated with javax.interceptor.InterceptorBinding:
@Inherited
@InterceptorBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Logged {
}
An interceptor binding also has the java.lang.annotation.Inherited annotation, to
specify that the annotation can be inherited from superclasses. The @Inherited
Contexts and Dependency Injection for Java EE: Advanced Topics
25-9
Using Decorators in CDI Applications
annotation also applies to custom scopes (not discussed in this tutorial) but does not
apply to qualifiers.
An interceptor binding type may declare other interceptor bindings.
The interceptor class is annotated with the interceptor binding as well as with the
@Interceptor annotation. For an example, see The LoggedInterceptor Interceptor
Class.
Every @AroundInvoke method takes a javax.interceptor.InvocationContext
argument, returns a java.lang.Object, and throws an Exception. It can call
InvocationContext methods. The @AroundInvoke method must call the proceed
method, which causes the target class method to be invoked.
Once an interceptor and binding type are defined, you can annotate beans and
individual methods with the binding type to specify that the interceptor is to be
invoked either on all methods of the bean or on specific methods. For example, in the
billpayment example, the PaymentHandler bean is annotated @Logged, which means
that any invocation of its business methods will cause the interceptor's @AroundInvoke
method to be invoked:
@Logged
@SessionScoped
public class PaymentHandler implements Serializable {...}
However, in the PaymentBean bean, only the pay and reset methods have the @Logged
annotation, so the interceptor is invoked only when these methods are invoked:
@Logged
public String pay() {...}
@Logged
public void reset() {...}
In order for an interceptor to be invoked in a CDI application, it must, like an
alternative, be specified in the beans.xml file. For example, the LoggedInterceptor
class is specified as follows:
<interceptors>
<class>javaeetutorial.billpayment.interceptors.LoggedInterceptor</class>
</interceptors>
If an application uses more than one interceptor, the interceptors are invoked in the
order specified in the beans.xml file.
The interceptors that you specify in the beans.xml file apply only to classes in the
same archive. Use the @Priority annotation to specify interceptors globally for an
application that consists of multiple modules, as in the following example:
@Logged
@Interceptor
@Priority(Interceptor.Priority.APPLICATION)
public class LoggedInterceptor implements Serializable { ... }
Interceptors with lower priority values are called first. You do not need to specify the
interceptor in the beans.xml file when you use the @Priority annotation.
25.7 Using Decorators in CDI Applications
A decorator is a Java class that is annotated javax.decorator.Decorator and that has
a corresponding decorators element in the beans.xml file.
25-10 The Java EE 7 Tutorial
Using Decorators in CDI Applications
A decorator bean class must also have a delegate injection point, which is annotated
javax.decorator.Delegate. This injection point can be a field, a constructor
parameter, or an initializer method parameter of the decorator class.
Decorators are outwardly similar to interceptors. However, they actually perform tasks
complementary to those performed by interceptors. Interceptors perform cross-cutting
tasks associated with method invocation and with the lifecycles of beans, but cannot
perform any business logic. Decorators, on the other hand, do perform business logic
by intercepting business methods of beans. This means that instead of being reusable
for different kinds of applications, as are interceptors, their logic is specific to a
particular application.
For example, instead of using an alternative TestCoderImpl class for the encoder
example, you could create a decorator as follows:
@Decorator
public abstract class CoderDecorator implements Coder {
@Inject
@Delegate
@Any
Coder coder;
public String codeString(String s, int tval) {
int len = s.length();
return "\"" + s + "\" becomes " + "\"" + coder.codeString(s, tval)
+ "\", " + len + " characters in length";
}
}
See The decorators Example: Decorating a Bean for an example that uses this
decorator.
This simple decorator returns more detailed output than the encoded string returned
by the CoderImpl.codeString method. A more complex decorator could store
information in a database or perform some other business logic.
A decorator can be declared as an abstract class so that it does not have to implement
all the business methods of the interface.
In order for a decorator to be invoked in a CDI application, it must, like an interceptor
or an alternative, be specified in the beans.xml file. For example, the CoderDecorator
class is specified as follows:
<decorators>
<class>javaeetutorial.decorators.CoderDecorator</class>
</decorators>
If an application uses more than one decorator, the decorators are invoked in the order
in which they are specified in the beans.xml file.
If an application has both interceptors and decorators, the interceptors are invoked
first. This means, in effect, that you cannot intercept a decorator.
The decorators that you specify in the beans.xml file apply only to classes in the same
archive. Use the @Priority annotation to specify decorators globally for an application
that consists of multiple modules, as in the following example:
@Decorator
@Priority(Interceptor.Priority.APPLICATION)
public abstract class CoderDecorator implements Coder { ... }
Contexts and Dependency Injection for Java EE: Advanced Topics 25-11
Using Stereotypes in CDI Applications
Decorators with lower priority values are called first. You do not need to specify the
decorator in the beans.xml when you use the @Priority annotation.
25.8 Using Stereotypes in CDI Applications
A stereotype is a kind of annotation, applied to a bean, that incorporates other
annotations. Stereotypes can be particularly useful in large applications in which you
have a number of beans that perform similar functions. A stereotype is a kind of
annotation that specifies the following:
■
A default scope
■
Zero or more interceptor bindings
■
Optionally, a @Named annotation, guaranteeing default EL naming
■
Optionally, an @Alternative annotation, specifying that all beans with this
stereotype are alternatives
A bean annotated with a particular stereotype will always use the specified
annotations, so you do not have to apply the same annotations to many beans.
For example, you might create a stereotype named Action, using the
javax.enterprise.inject.Stereotype annotation:
@RequestScoped
@Secure
@Transactional
@Named
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action {}
All beans annotated @Action will have request scope, use default EL naming, and have
the interceptor bindings @Transactional and @Secure.
You could also create a stereotype named Mock:
@Alternative
@Stereotype
@Target(TYPE)
@Retention(RUNTIME)
public @interface Mock {}
All beans with this annotation are alternatives.
It is possible to apply multiple stereotypes to the same bean, so you can annotate a
bean as follows:
@Action
@Mock
public class MockLoginAction extends LoginAction { ... }
It is also possible to override the scope specified by a stereotype, simply by specifying
a different scope for the bean. The following declaration gives the MockLoginAction
bean session scope instead of request scope:
@SessionScoped
@Action
@Mock
public class MockLoginAction extends LoginAction { ... }
25-12 The Java EE 7 Tutorial
Using Stereotypes in CDI Applications
CDI makes available a built-in stereotype called Model, which is intended for use with
beans that define the model layer of a model-view-controller application architecture.
This stereotype specifies that a bean is both @Named and @RequestScoped:
@Named
@RequestScoped
@Stereotype
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface Model {}
Contexts and Dependency Injection for Java EE: Advanced Topics 25-13
Using Stereotypes in CDI Applications
25-14 The Java EE 7 Tutorial
26
Running the Advanced Contexts and
Dependency Injection Examples
26
This chapter describes in detail how to build and run several advanced examples that
use CDI. The examples are in the tut-install/examples/cdi/ directory.
To build and run the examples, you will do the following.
1.
Use NetBeans IDE or the Maven tool to compile, package, and deploy the
example.
2.
Run the example in a web browser.
See Chapter 2, "Using the Tutorial Examples", for basic information on installing,
building, and running the examples.
The following topics are addressed here:
■
■
The encoder Example: Using Alternatives
The producermethods Example: Using a Producer Method to Choose a Bean
Implementation
■
The producerfields Example: Using Producer Fields to Generate Resources
■
The billpayment Example: Using Events and Interceptors
■
The decorators Example: Decorating a Bean
26.1 The encoder Example: Using Alternatives
The encoder example shows how to use alternatives to choose between two beans at
deployment time, as described in Using Alternatives in CDI Applications. The
example includes an interface and two implementations of it, a managed bean, a
Facelets page, and configuration files.
The source files are located in the
tut-install/examples/cdi/encoder/src/main/java/javaeetutorial/encoder/
directory.
26.1.1 The Coder Interface and Implementations
The Coder interface contains just one method, codeString, that takes two arguments: a
string, and an integer value that specifies how the letters in the string should be
transposed.
public interface Coder {
public String codeString(String s, int tval);
Running the Advanced Contexts and Dependency Injection Examples
26-1
The encoder Example: Using Alternatives
}
The interface has two implementation classes, CoderImpl and TestCoderImpl. The
implementation of codeString in CoderImpl shifts the string argument forward in the
alphabet by the number of letters specified in the second argument; any characters that
are not letters are left unchanged. (This simple shift code is known as a Caesar cipher
because Julius Caesar reportedly used it to communicate with his generals.) The
implementation in TestCoderImpl merely displays the values of the arguments. The
TestCoderImpl implementation is annotated @Alternative:
import javax.enterprise.inject.Alternative;
@Alternative
public class TestCoderImpl implements Coder {
@Override
public String codeString(String s, int tval) {
return ("input string is " + s + ", shift value is " + tval);
}
}
The beans.xml file for the encoder example contains an alternatives element for the
TestCoderImpl class, but by default the element is commented out:
<beans ...>
<!--<alternatives>
<class>javaeetutorial.encoder.TestCoderImpl</class>
</alternatives>-->
</beans>
This means that by default, the TestCoderImpl class, annotated @Alternative, will not
be used. Instead, the CoderImpl class will be used.
26.1.2 The encoder Facelets Page and Managed Bean
The simple Facelets page for the encoder example, index.xhtml, asks the user to enter
the string and integer values and passes them to the managed bean, CoderBean, as
coderBean.inputString and coderBean.transVal:
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<h:outputStylesheet library="css" name="default.css"/>
<title>String Encoder</title>
</h:head>
<h:body>
<h2>String Encoder</h2>
<p>Type a string and an integer, then click Encode.</p>
<p>Depending on which alternative is enabled, the coder bean
will either display the argument values or return a string that
shifts the letters in the original string by the value you
specify. The value must be between 0 and 26.</p>
<h:form id="encodeit">
<p><h:outputLabel value="Enter a string: " for="inputString"/>
<h:inputText id="inputString"
value="#{coderBean.inputString}"/>
<h:outputLabel value="Enter the number of letters to shift by: "
for="transVal"/>
<h:inputText id="transVal" value="#{coderBean.transVal}"/></p>
26-2 The Java EE 7 Tutorial
The encoder Example: Using Alternatives
<p><h:commandButton value="Encode"
action="#{coderBean.encodeString()}"/></p>
<p><h:outputLabel value="Result: " for="outputString"/>
<h:outputText id="outputString"
value="#{coderBean.codedString}"
style="color:blue"/></p>
<p><h:commandButton value="Reset"
action="#{coderBean.reset}"/></p>
</h:form>
...
</h:body>
</html>
When the user clicks the Encode button, the page invokes the managed bean's
encodeString method and displays the result, coderBean.codedString, in blue. The
page also has a Reset button that clears the fields.
The managed bean, CoderBean, is a @RequestScoped bean that declares its input and
output properties. The transVal property has three Bean Validation constraints that
enforce limits on the integer value, so that if the user enters an invalid value, a default
error message appears on the Facelets page. The bean also injects an instance of the
Coder interface:
@Named
@RequestScoped
public class CoderBean {
private String inputString;
private String codedString;
@Max(26)
@Min(0)
@NotNull
private int transVal;
@Inject
Coder coder;
...
In addition to simple getter and setter methods for the three properties, the bean
defines the encodeString action method called by the Facelets page. This method sets
the codedString property to the value returned by a call to the codeString method of
the Coder implementation:
public void encodeString() {
setCodedString(coder.codeString(inputString, transVal));
}
Finally, the bean defines the reset method to empty the fields of the Facelets page:
public void reset() {
setInputString("");
setTransVal(0);
}
26.1.3 Running the encoder Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
encoder application.
Running the Advanced Contexts and Dependency Injection Examples
26-3
The encoder Example: Using Alternatives
26.1.3.1 To Build, Package, and Deploy the encoder Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/cdi
4.
Select the encoder folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the encoder project and select Build.
This command builds and packages the application into a WAR file, encoder.war,
located in the target directory, and then deploys it to GlassFish Server.
26.1.3.2 To Run the encoder Example Using NetBeans IDE
1.
In a web browser, enter the following URL:
http://localhost:8080/encoder
2.
On the String Encoder page, enter a string and the number of letters to shift by,
and then click Encode.
The encoded string appears in blue on the Result line. For example, if you enter
Java and 4, the result is Neze.
3.
Now, edit the beans.xml file to enable the alternative implementation of Coder.
a.
In the Projects tab, under the encoder project, expand the Web Pages node,
then expand the WEB-INF node.
b.
Double-click the beans.xml file to open it.
c.
Remove the comment characters that surround the alternatives element, so
that it looks like this:
<alternatives>
<class>javaeetutorial.encoder.TestCoderImpl</class>
</alternatives>
d.
Save the file.
4.
Right-click the encoder project and select Clean and Build.
5.
In the web browser, reenter the URL to show the String Encoder page for the
redeployed project:
http://localhost:8080/encoder/
6.
Enter a string and the number of letters to shift by, and then click Encode.
This time, the Result line displays your arguments. For example, if you enter Java
and 4, the result is:
Result: input string is Java, shift value is 4
26.1.3.3 To Build, Package, and Deploy the encoder Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
26-4 The Java EE 7 Tutorial
The producermethods Example: Using a Producer Method to Choose a Bean Implementation
2.
In a terminal window, go to:
tut-install/examples/cdi/encoder/
3.
Enter the following command to deploy the application:
mvn install
This command builds and packages the application into a WAR file, encoder.war,
located in the target directory, and then deploys it to GlassFish Server.
26.1.3.4 To Run the encoder Example Using Maven
1.
In a web browser, enter the following URL:
http://localhost:8080/encoder/
The String Encoder page opens.
2.
Enter a string and the number of letters to shift by, and then click Encode.
The encoded string appears in blue on the Result line. For example, if you enter
Java and 4, the result is Neze.
3.
Now, edit the beans.xml file to enable the alternative implementation of Coder.
a.
In a text editor, open the following file:
tut-install/examples/cdi/encoder/src/main/webapp/WEB-INF/beans.xml
b.
Remove the comment characters that surround the alternatives element, so
that it looks like this:
<alternatives>
<class>javaeetutorial.encoder.TestCoderImpl</class>
</alternatives>
c.
4.
Save and close the file.
Enter the following command:
mvn clean install
5.
In the web browser, reenter the URL to show the String Encoder page for the
redeployed project:
http://localhost:8080/encoder
6.
Enter a string and the number of letters to shift by, and then click Encode.
This time, the Result line displays your arguments. For example, if you enter Java
and 4, the result is:
Result: input string is Java, shift value is 4
26.2 The producermethods Example: Using a Producer Method to
Choose a Bean Implementation
The producermethods example shows how to use a producer method to choose
between two beans at runtime, as described in Using Producer Methods, Producer
Fields, and Disposer Methods in CDI Applications. It is very similar to the encoder
example described in The encoder Example: Using Alternatives. The example includes
the same interface and two implementations of it, a managed bean, a Facelets page,
Running the Advanced Contexts and Dependency Injection Examples
26-5
The producermethods Example: Using a Producer Method to Choose a Bean Implementation
and configuration files. It also contains a qualifier type. When you run it, you do not
need to edit the beans.xml file and redeploy the application to change its behavior.
26.2.1 Components of the producermethods Example
The components of producermethods are very much like those for encoder, with some
significant differences.
Neither implementation of the Coder bean is annotated @Alternative, and there is no
beans.xml file, because it is not needed.
The Facelets page and the managed bean, CoderBean, have an additional property,
coderType, that allows the user to specify at runtime which implementation to use. In
addition, the managed bean has a producer method that selects the implementation
using a qualifier type, @Chosen.
The bean declares two constants that specify whether the coder type is the test
implementation or the implementation that actually shifts letters:
private final static int TEST = 1;
private final static int SHIFT = 2;
private int coderType = SHIFT; // default value
The producer method, annotated with @Produces and @Chosen as well as
@RequestScoped (so that it lasts only for the duration of a single request and response),
returns one of the two implementations based on the coderType supplied by the user.
@Produces
@Chosen
@RequestScoped
public Coder getCoder() {
switch (coderType) {
case TEST:
return new TestCoderImpl();
case SHIFT:
return new CoderImpl();
default:
return null;
}
}
Finally, the managed bean injects the chosen implementation, specifying the same
qualifier as that returned by the producer method to resolve ambiguities:
@Inject
@Chosen
@RequestScoped
Coder coder;
The Facelets page contains modified instructions and a pair of options whose selected
value is assigned to the property coderBean.coderType:
<h2>String Encoder</h2>
<p>Select Test or Shift, type a string and an integer, then click
Encode.</p>
<p>If you select Test, the TestCoderImpl bean will display the
argument values.</p>
<p>If you select Shift, the CoderImpl bean will return a string that
shifts the letters in the original string by the value you specify.
The value must be between 0 and 26.</p>
26-6 The Java EE 7 Tutorial
The producermethods Example: Using a Producer Method to Choose a Bean Implementation
<h:form id="encodeit">
<h:selectOneRadio id="coderType"
required="true"
value="#{coderBean.coderType}">
<f:selectItem
itemValue="1"
itemLabel="Test"/>
<f:selectItem
itemValue="2"
itemLabel="Shift Letters"/>
</h:selectOneRadio>
...
26.2.2 Running the producermethods Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
producermethods application.
26.2.2.1 To Build, Package, and Deploy the producermethods Example Using
NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/cdi
4.
Select the producermethods folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the producermethods project and select Build.
This command builds and packages the application into a WAR file,
producermethods.war, located in the target directory, and then deploys it to
GlassFish Server.
26.2.2.2 To Build, Package, and Deploy the producermethods Example Using
Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/cdi/producermethods/
3.
Enter the following command to deploy the application:
mvn install
This command builds and packages the application into a WAR file,
producermethods.war, located in the target directory, and then deploys it to
GlassFish Server.
26.2.2.3 To Run the producermethods Example
1.
In a web browser, enter the following URL:
http://localhost:8080/producermethods
Running the Advanced Contexts and Dependency Injection Examples
26-7
The producerfields Example: Using Producer Fields to Generate Resources
2.
On the String Encoder page, select either the Test or Shift Letters option, enter a
string and the number of letters to shift by, and then click Encode.
Depending on your selection, the Result line displays either the encoded string or
the input values you specified.
26.3 The producerfields Example: Using Producer Fields to Generate
Resources
The producerfields example, which allows you to create a to-do list, shows how to
use a producer field to generate objects that can then be managed by the container.
This example generates an EntityManager object, but resources such as JDBC
connections and datasources can also be generated this way.
The producerfields example is the simplest possible entity example. It also contains a
qualifier and a class that generates the entity manager. It also contains a single entity, a
stateful session bean, a Facelets page, and a managed bean.
The source files are located in the
tut-install/examples/cdi/producerfields/src/main/java/javaeetutorial/producer
fields/ directory.
26.3.1 The Producer Field for the producerfields Example
The most important component of the producerfields example is the smallest, the
db.UserDatabaseEntityManager class, which isolates the generation of the
EntityManager object so it can easily be used by other components in the application.
The class uses a producer field to inject an EntityManager annotated with the
@UserDatabase qualifier, also defined in the db package:
@Singleton
public class UserDatabaseEntityManager {
@Produces
@PersistenceContext
@UserDatabase
private EntityManager em;
...
}
The class does not explicitly produce a persistence unit field, but the application has a
persistence.xml file that specifies a persistence unit. The class is annotated
javax.inject.Singleton to specify that the injector should instantiate it only once.
The db.UserDatabaseEntityManager class also contains commented-out code that
uses create and close methods to generate and remove the producer field:
/* @PersistenceContext
private EntityManager em;
@Produces
@UserDatabase
public EntityManager create() {
return em;
} */
public void close(@Disposes @UserDatabase EntityManager em) {
em.close();
26-8 The Java EE 7 Tutorial
The producerfields Example: Using Producer Fields to Generate Resources
}
You can remove the comment indicators from this code and place them around the
field declaration to test how the methods work. The behavior of the application is the
same with either mechanism.
The advantage of producing the EntityManager in a separate class rather than simply
injecting it into an enterprise bean is that the object can easily be reused in a typesafe
way. Also, a more complex application can create multiple entity managers using
multiple persistence units, and this mechanism isolates this code for easy maintenance,
as in the following example:
@Singleton
public class JPAResourceProducer {
@Produces
@PersistenceUnit(unitName="pu3")
@TestDatabase
EntityManagerFactory customerDatabasePersistenceUnit;
@Produces
@PersistenceContext(unitName="pu3")
@TestDatabase
EntityManager customerDatabasePersistenceContext;
@Produces
@PersistenceUnit(unitName="pu4")
@Documents
EntityManagerFactory customerDatabasePersistenceUnit;
@Produces
@PersistenceContext(unitName="pu4")
@Documents
EntityManager docDatabaseEntityManager;"
}
The EntityManagerFactory declarations also allow applications to use an
application-managed entity manager.
26.3.2 The producerfields Entity and Session Bean
The producerfields example contains a simple entity class, entity.ToDo, and a
stateful session bean, ejb.RequestBean, that uses it.
The entity class contains three fields: an autogenerated id field, a string specifying the
task, and a timestamp. The timestamp field, timeCreated, is annotated with
@Temporal, which is required for persistent Date fields.
@Entity
public class ToDo implements Serializable {
...
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
protected String taskText;
@Temporal(TIMESTAMP)
protected Date timeCreated;
public ToDo() {
}
Running the Advanced Contexts and Dependency Injection Examples
26-9
The producerfields Example: Using Producer Fields to Generate Resources
public ToDo(Long id, String taskText, Date timeCreated) {
this.id = id;
this.taskText = taskText;
this.timeCreated = timeCreated;
}
...
The remainder of the ToDo class contains the usual getters, setters, and other entity
methods.
The RequestBean class injects the EntityManager generated by the producer method,
annotated with the @UserDatabase qualifier:
@ConversationScoped
@Stateful
public class RequestBean {
@Inject
@UserDatabase
EntityManager em;
It then defines two methods, one that creates and persists a single ToDo list item, and
another that retrieves all the ToDo items created so far by creating a query:
public ToDo createToDo(String inputString) {
ToDo toDo = null;
Date currentTime = Calendar.getInstance().getTime();
try {
toDo = new ToDo();
toDo.setTaskText(inputString);
toDo.setTimeCreated(currentTime);
em.persist(toDo);
return toDo;
} catch (Exception e) {
throw new EJBException(e.getMessage());
}
}
public List<ToDo> getToDos() {
try {
List<ToDo> toDos =
(List<ToDo>) em.createQuery(
"SELECT t FROM ToDo t ORDER BY t.timeCreated")
.getResultList();
return toDos;
} catch (Exception e) {
throw new EJBException(e.getMessage());
}
}
}
26.3.3 The producerfields Facelets Pages and Managed Bean
The producerfields example has two Facelets pages, index.xhtml and
todolist.xhtml. The simple form on the index.xhtml page asks the user only for the
task. When the user clicks the Submit button, the listBean.createTask method is
called. When the user clicks the Show Items button, the action specifies that the
todolist.xhtml file should be displayed:
26-10 The Java EE 7 Tutorial
The producerfields Example: Using Producer Fields to Generate Resources
<h:body>
<h2>To Do List</h2>
<p>Enter a task to be completed.</p>
<h:form id="todolist">
<p><h:outputLabel value="Enter a string: " for="inputString"/>
<h:inputText id="inputString"
value="#{listBean.inputString}"/></p>
<p><h:commandButton value="Submit"
action="#{listBean.createTask()}"/></p>
<p><h:commandButton value="Show Items"
action="todolist"/></p>
</h:form>
...
</h:body>
The managed bean, web.ListBean, injects the ejb.RequestBean session bean. It
declares the entity.ToDo entity and a list of the entity along with the input string that
it passes to the session bean. The inputString is annotated with the @NotNull Bean
Validation constraint, so an attempt to submit an empty string results in an error.
@Named
@ConversationScoped
public class ListBean implements Serializable {
...
@EJB
private RequestBean request;
@NotNull
private String inputString;
private ToDo toDo;
private List<ToDo> toDos;
The createTask method called by the Submit button calls the createToDo method of
RequestBean:
public void createTask() {
this.toDo = request.createToDo(inputString);
}
The getToDos method, which is called by the todolist.xhtml page, calls the getToDos
method of RequestBean:
public List<ToDo> getToDos() {
return request.getToDos();
}
To force the Facelets page to recognize an empty string as a null value and return an
error, the web.xml file sets the context parameter javax.faces.INTERPRET_EMPTY_
STRING_SUBMITTED_VALUES_AS_NULL to true:
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_
NULL</param-name>
<param-value>true</param-value>
</context-param>
The todolist.xhtml page is a little more complicated than the index.html page. It
contains a dataTable element that displays the contents of the ToDo list. The body of
the page looks like this:
<body>
Running the Advanced Contexts and Dependency Injection Examples 26-11
The producerfields Example: Using Producer Fields to Generate Resources
<h2>To Do List</h2>
<h:form id="showlist">
<h:dataTable var="toDo"
value="#{listBean.toDos}"
rules="all"
border="1"
cellpadding="5">
<h:column>
<f:facet name="header">
<h:outputText value="Time Stamp" />
</f:facet>
<h:outputText value="#{toDo.timeCreated}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Task" />
</f:facet>
<h:outputText value="#{toDo.taskText}" />
</h:column>
</h:dataTable>
<p><h:commandButton id="back" value="Back" action="index" /></p>
</h:form>
</body>
The value of the dataTable is listBean.toDos, the list returned by the managed bean's
getToDos method, which in turn calls the session bean's getToDos method. Each row of
the table displays the timeCreated and taskText fields of the individual task. Finally,
a Back button returns the user to the index.xhtml page.
26.3.4 Running the producerfields Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
producerfields application.
26.3.4.1 To Build, Package, and Deploy the producerfields Example Using
NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
If the database server is not already running, start it by following the instructions
in Starting and Stopping the Java DB Server.
3.
From the File menu, choose Open Project.
4.
In the Open Project dialog box, navigate to:
tut-install/examples/cdi
5.
Select the producerfields folder.
6.
Click Open Project.
7.
In the Projects tab, right-click the producerfields project and select Build.
This command builds and packages the application into a WAR file,
producerfields.war, located in the target directory, and then deploys it to
GlassFish Server.
26-12 The Java EE 7 Tutorial
The billpayment Example: Using Events and Interceptors
26.3.4.2 To Build, Package, and Deploy the producerfields Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
If the database server is not already running, start it by following the instructions
in Starting and Stopping the Java DB Server.
3.
In a terminal window, go to:
tut-install/examples/cdi/producerfields/
4.
Enter the following command to deploy the application:
mvn install
This command builds and packages the application into a WAR file,
producerfields.war, located in the target directory, and then deploys it to
GlassFish Server.
26.3.4.3 To Run the producerfields Example
1.
In a web browser, enter the following URL:
http://localhost:8080/producerfields
2.
On the Create To Do List page, enter a string in the field and click Submit.
You can enter additional strings and click Submit to create a task list with multiple
items.
3.
Click Show Items.
The To Do List page opens, showing the timestamp and text for each item you
created.
4.
Click Back to return to the Create To Do List page.
On this page, you can enter more items in the list.
26.4 The billpayment Example: Using Events and Interceptors
The billpayment example shows how to use both events and interceptors.
The example simulates paying an amount using a debit card or credit card. When the
user chooses a payment method, the managed bean creates an appropriate event,
supplies its payload, and fires it. A simple event listener handles the event using
observer methods.
The example also defines an interceptor that is set on a class and on two methods of
another class.
The source files are located in the
tut-install/examples/cdi/billpayment/src/main/java/javaeetutorial/billpayment
/ directory.
26.4.1 The PaymentEvent Event Class
The event class, event.PaymentEvent, is a simple bean class that contains a
no-argument constructor. It also has a toString method and getter and setter methods
for the payload components: a String for the payment type, a BigDecimal for the
payment amount, and a Date for the timestamp.
public class PaymentEvent implements Serializable {
Running the Advanced Contexts and Dependency Injection Examples 26-13
The billpayment Example: Using Events and Interceptors
...
public String paymentType;
public BigDecimal value;
public Date datetime;
public PaymentEvent() {
}
@Override
public String toString() {
return this.paymentType
+ " = $" + this.value.toString()
+ " at " + this.datetime.toString();
}
...
The event class is a simple bean that is instantiated by the managed bean using new
and then populated. For this reason, the CDI container cannot intercept the creation of
the bean, and hence it cannot allow interception of its getter and setter methods.
26.4.2 The PaymentHandler Event Listener
The event listener, listener.PaymentHandler, contains two observer methods, one for
each of the two event types:
@Logged
@SessionScoped
public class PaymentHandler implements Serializable {
...
public void creditPayment(@Observes @Credit PaymentEvent event) {
logger.log(Level.INFO, "PaymentHandler - Credit Handler: {0}",
event.toString());
// call a specific Credit handler class...
}
public void debitPayment(@Observes @Debit PaymentEvent event) {
logger.log(Level.INFO, "PaymentHandler - Debit Handler: {0}",
event.toString());
// call a specific Debit handler class...
}
}
Each observer method takes as an argument the event, annotated with @Observes and
with the qualifier for the type of payment. In a real application, the observer methods
would pass the event information on to another component that would perform
business logic on the payment.
The qualifiers are defined in the payment package, described in The billpayment
Facelets Pages and Managed Bean.
The PaymentHandler bean is annotated @Logged so that all its methods can be
intercepted.
26-14 The Java EE 7 Tutorial
The billpayment Example: Using Events and Interceptors
26.4.3 The billpayment Facelets Pages and Managed Bean
The billpayment example contains two Facelets pages, index.xhtml and the very
simple response.xhtml. The body of index.xhtml looks like this:
<h:body>
<h3>Bill Payment Options</h3>
<p>Enter an amount, select Debit Card or Credit Card,
then click Pay.</p>
<h:form>
<p>
<h:outputLabel value="Amount: $" for="amt"/>
<h:inputText id="amt" value="#{paymentBean.value}"
required="true"
requiredMessage="An amount is required."
maxlength="15" />
</p>
<h:outputLabel value="Options:" for="opt"/>
<h:selectOneRadio id="opt" value="#{paymentBean.paymentOption}">
<f:selectItem id="debit" itemLabel="Debit Card"
itemValue="1"/>
<f:selectItem id="credit" itemLabel="Credit Card"
itemValue="2" />
</h:selectOneRadio>
<p><h:commandButton id="submit" value="Pay"
action="#{paymentBean.pay}" /></p>
<p><h:commandButton value="Reset"
action="#{paymentBean.reset}" /></p>
</h:form>
...
</h:body>
The input field takes a payment amount, passed to paymentBean.value. Two options
ask the user to select a Debit Card or Credit Card payment, passing the integer value
to paymentBean.paymentOption. Finally, the Pay command button's action is set to the
method paymentBean.pay, and the Reset button's action is set to the
paymentBean.reset method.
The payment.PaymentBean managed bean uses qualifiers to differentiate between the
two kinds of payment event:
@Named
@SessionScoped
public class PaymentBean implements Serializable {
...
@Inject
@Credit
Event<PaymentEvent> creditEvent;
@Inject
@Debit
Event<PaymentEvent> debitEvent;
The qualifiers, @Credit and @Debit, are defined in the payment package along with
PaymentBean.
Next, the PaymentBean defines the properties it obtains from the Facelets page and will
pass on to the event:
public static final int DEBIT = 1;
public static final int CREDIT = 2;
Running the Advanced Contexts and Dependency Injection Examples 26-15
The billpayment Example: Using Events and Interceptors
private int paymentOption = DEBIT;
@Digits(integer = 10, fraction = 2, message = "Invalid value")
private BigDecimal value;
private Date datetime;
The paymentOption value is an integer passed in from the option component; the
default value is DEBIT. The value is a BigDecimal with a Bean Validation constraint
that enforces a currency value with a maximum number of digits. The timestamp for
the event, datetime, is a Date object initialized when the pay method is called.
The pay method of the bean first sets the timestamp for this payment event. It then
creates and populates the event payload, using the constructor for the PaymentEvent
and calling the event's setter methods, using the bean properties as arguments. It then
fires the event.
@Logged
public String pay() {
this.setDatetime(Calendar.getInstance().getTime());
switch (paymentOption) {
case DEBIT:
PaymentEvent debitPayload = new PaymentEvent();
debitPayload.setPaymentType("Debit");
debitPayload.setValue(value);
debitPayload.setDatetime(datetime);
debitEvent.fire(debitPayload);
break;
case CREDIT:
PaymentEvent creditPayload = new PaymentEvent();
creditPayload.setPaymentType("Credit");
creditPayload.setValue(value);
creditPayload.setDatetime(datetime);
creditEvent.fire(creditPayload);
break;
default:
logger.severe("Invalid payment option!");
}
return "response";
}
The pay method returns the page to which the action is redirected, response.xhtml.
The PaymentBean class also contains a reset method that empties the value field on
the index.xhtml page and sets the payment option to the default:
@Logged
public void reset() {
setPaymentOption(DEBIT);
setValue(BigDecimal.ZERO);
}
In this bean, only the pay and reset methods are intercepted.
The response.xhtml page displays the amount paid. It uses a rendered expression to
display the payment method:
<h:body>
<h:form>
<h2>Bill Payment: Result</h2>
<h3>Amount Paid with
<h:outputText id="debit" value="Debit Card: "
26-16 The Java EE 7 Tutorial
The billpayment Example: Using Events and Interceptors
rendered="#{paymentBean.paymentOption eq 1}" />
<h:outputText id="credit" value="Credit Card: "
rendered="#{paymentBean.paymentOption eq 2}" />
<h:outputText id="result" value="#{paymentBean.value}">
<f:convertNumber type="currency"/>
</h:outputText>
</h3>
<p><h:commandButton id="back" value="Back" action="index" /></p>
</h:form>
</h:body>
26.4.4 The LoggedInterceptor Interceptor Class
The interceptor class, LoggedInterceptor, and its interceptor binding, Logged, are both
defined in the interceptor package. The Logged interceptor binding is defined as
follows:
@Inherited
@InterceptorBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Logged {
}
The LoggedInterceptor class looks like this:
@Logged
@Interceptor
public class LoggedInterceptor implements Serializable {
...
public LoggedInterceptor() {
}
@AroundInvoke
public Object logMethodEntry(InvocationContext invocationContext)
throws Exception {
System.out.println("Entering method: "
+ invocationContext.getMethod().getName() + " in class "
+ invocationContext.getMethod().getDeclaringClass().getName());
return invocationContext.proceed();
}
}
The class is annotated with both the @Logged and the @Interceptor annotations. The
@AroundInvoke method, logMethodEntry, takes the required InvocationContext
argument and calls the required proceed method. When a method is intercepted,
logMethodEntry displays the name of the method being invoked as well as its class.
To enable the interceptor, the beans.xml file defines it as follows:
<interceptors>
<class>javaeetutorial.billpayment.interceptor.LoggedInterceptor</class>
</interceptors>
In this application, the PaymentEvent and PaymentHandler classes are annotated
@Logged, so all their methods are intercepted. In PaymentBean, only the pay and reset
methods are annotated @Logged, so only those methods are intercepted.
Running the Advanced Contexts and Dependency Injection Examples 26-17
The billpayment Example: Using Events and Interceptors
26.4.5 Running the billpayment Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
billpayment application.
26.4.5.1 To Build, Package, and Deploy the billpayment Example Using NetBeans
IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/cdi
4.
Select the billpayment folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the billpayment project and select Build.
This command builds and packages the application into a WAR file,
billpayment.war, located in the target directory, and then deploys it to GlassFish
Server.
26.4.5.2 To Build, Package, and Deploy the billpayment Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/cdi/billpayment/
3.
Enter the following command to deploy the application:
mvn install
This command builds and packages the application into a WAR file,
billpayment.war, located in the target directory, and then deploys it to GlassFish
Server.
26.4.5.3 To Run the billpayment Example
1.
In a web browser, enter the following URL:
http://localhost:8080/billpayment
2.
On the Bill Payment Options page, enter a value in the Amount field.
The amount can contain up to 10 digits and include up to two decimal places. For
example:
9876.54
3.
Select Debit Card or Credit Card and click Pay.
The Bill Payment: Result page opens, displaying the amount paid and the method
of payment:
Amount Paid with Credit Card: $9,876.34
4.
Click Back to return to the Bill Payment Options page.
26-18 The Java EE 7 Tutorial
The decorators Example: Decorating a Bean
You can also click Reset to return to the initial page values.
5.
Examine the server log output.
In NetBeans IDE, the output is visible in the GlassFish Server Output tab.
Otherwise, view domain-dir/logs/server.log.
The output from each interceptor appears in the log, followed by the additional
logger output defined by the constructor and methods:
INFO: Entering method: pay in class billpayment.payment.PaymentBean
INFO: PaymentHandler created.
INFO: Entering method: debitPayment in class
billpayment.listener.PaymentHandler
INFO: PaymentHandler - Debit Handler: Debit = $1234.56 at Tue Dec 14 14:50:28
EST 2010
26.5 The decorators Example: Decorating a Bean
The decorators example, which is yet another variation on the encoder example,
shows how to use a decorator to implement additional business logic for a bean.
Instead of having the user choose between two alternative implementations of an
interface at deployment time or runtime, a decorator adds some additional logic to a
single implementation of the interface.
The example includes an interface, an implementation of it, a decorator, an interceptor,
a managed bean, a Facelets page, and configuration files.
The source files are located in the
tut-install/examples/cdi/decorators/src/main/java/javaeetutorial/decorators/
directory.
26.5.1 Components of the decorators Example
The decorators example is very similar to the encoder example described in The
encoder Example: Using Alternatives. Instead of providing two implementations of
the Coder interface, however, this example provides only the CoderImpl class. The
decorator class, CoderDecorator, rather than simply return the coded string, displays
the input and output strings' values and length.
The CoderDecorator class, like CoderImpl, implements the business method of the
Coder interface, codeString:
@Decorator
public abstract class CoderDecorator implements Coder {
@Inject
@Delegate
@Any
Coder coder;
public String codeString(String s, int tval) {
int len = s.length();
return "\"" + s + "\" becomes " + "\"" + coder.codeString(s, tval)
+ "\", " + len + " characters in length";
}
}
The decorator's codeString method calls the delegate object's codeString method to
perform the actual encoding.
Running the Advanced Contexts and Dependency Injection Examples 26-19
The decorators Example: Decorating a Bean
The decorators example includes the Logged interceptor binding and
LoggedInterceptor class from the billpayment example. For this example, the
interceptor is set on the CoderBean.encodeString method and the
CoderImpl.codeString method. The interceptor code is unchanged; interceptors are
usually reusable for different applications.
Except for the interceptor annotations, the CoderBean and CoderImpl classes are
identical to the versions in the encoder example.
The beans.xml file specifies both the decorator and the interceptor:
<decorators>
<class>javaeetutorial.decorators.CoderDecorator</class>
</decorators>
<interceptors>
<class>javaeetutorial.decorators.LoggedInterceptor</class>
</interceptors>
26.5.2 Running the decorators Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
decorators application.
26.5.2.1 To Build, Package, and Deploy the decorators Example Using NetBeans
IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/cdi
4.
Select the decorators folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the decorators project and select Build.
This command builds and packages the application into a WAR file,
decorators.war, located in the target directory, and then deploys it to GlassFish
Server.
26.5.2.2 To Build, Package, and Deploy the decorators Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/cdi/decorators/
3.
Enter the following command to deploy the application:
mvn install
This command builds and packages the application into a WAR file,
decorators.war, located in the target directory, and then deploys it to GlassFish
Server.
26-20 The Java EE 7 Tutorial
The decorators Example: Decorating a Bean
26.5.2.3 To Run the decorators Example
1.
In a web browser, enter the following URL:
http://localhost:8080/decorators
2.
On the Decorated String Encoder page, enter a string and the number of letters to
shift by, and then click Encode.
The output from the decorator method appears in blue on the Result line. For
example, if you entered Java and 4, you would see the following:
"Java" becomes "Neze", 4 characters in length
3.
Examine the server log output.
In NetBeans IDE, the output is visible in the GlassFish Server Output tab.
Otherwise, view domain-dir/logs/server.log.
The output from the interceptors appears:
INFO: Entering method: encodeString in class
javaeetutorial.decorators.CoderBean
INFO: Entering method: codeString in class javaeetutorial.decorators.CoderImpl
Running the Advanced Contexts and Dependency Injection Examples 26-21
The decorators Example: Decorating a Bean
26-22 The Java EE 7 Tutorial
Part VI
Part VI
Web Services
Part VI explores web services. This part contains the following chapters:
■
Chapter 27, "Introduction to Web Services"
■
Chapter 28, "Building Web Services with JAX-WS"
■
Chapter 29, "Building RESTful Web Services with JAX-RS"
■
Chapter 30, "Accessing REST Resources with the JAX-RS Client API"
■
Chapter 31, "JAX-RS: Advanced Topics and an Example"
27
Introduction to Web Services
27
This part of the tutorial discusses Java EE 7 web services technologies. These
technologies include Java API for XML Web Services (JAX-WS) and Java API for
RESTful Web Services (JAX-RS).
The following topics are addressed here:
■
What Are Web Services?
■
Types of Web Services
■
Deciding Which Type of Web Service to Use
27.1 What Are Web Services?
Web services are client and server applications that communicate over the World Wide
Web's (WWW) HyperText Transfer Protocol (HTTP). As described by the World Wide
Web Consortium (W3C), web services provide a standard means of interoperating
between software applications running on a variety of platforms and frameworks.
Web services are characterized by their great interoperability and extensibility as well
as their machine-processable descriptions, thanks to the use of XML. Web services can
be combined in a loosely coupled way to achieve complex operations. Programs
providing simple services can interact with each other to deliver sophisticated
added-value services.
27.2 Types of Web Services
On the conceptual level, a service is a software component provided through a
network-accessible endpoint. The service consumer and provider use messages to
exchange invocation request and response information in the form of self-containing
documents that make very few assumptions about the technological capabilities of the
receiver.
On a technical level, web services can be implemented in various ways. The two types
of web services discussed in this section can be distinguished as "big" web services and
"RESTful" web services.
27.2.1 "Big" Web Services
In Java EE 7, JAX-WS provides the functionality for "big" web services, which are
described in Chapter 28, "Building Web Services with JAX-WS". Big web services use
XML messages that follow the Simple Object Access Protocol (SOAP) standard, an
XML language defining a message architecture and message formats. Such systems
often contain a machine-readable description of the operations offered by the service,
Introduction to Web Services 27-1
Types of Web Services
written in the Web Services Description Language (WSDL), an XML language for
defining interfaces syntactically.
The SOAP message format and the WSDL interface definition language have gained
widespread adoption. Many development tools, such as NetBeans IDE, can reduce the
complexity of developing web service applications.
A SOAP-based design must include the following elements.
■
■
■
A formal contract must be established to describe the interface that the web service
offers. WSDL can be used to describe the details of the contract, which may
include messages, operations, bindings, and the location of the web service. You
may also process SOAP messages in a JAX-WS service without publishing a
WSDL.
The architecture must address complex nonfunctional requirements. Many web
service specifications address such requirements and establish a common
vocabulary for them. Examples include transactions, security, addressing, trust,
coordination, and so on.
The architecture needs to handle asynchronous processing and invocation. In such
cases, the infrastructure provided by standards, such as Web Services Reliable
Messaging (WSRM), and APIs, such as JAX-WS, with their client-side
asynchronous invocation support, can be leveraged out of the box.
27.2.2 RESTful Web Services
In Java EE 7, JAX-RS provides the functionality for Representational State Transfer
(RESTful) web services. REST is well suited for basic, ad hoc integration scenarios.
RESTful web services, often better integrated with HTTP than SOAP-based services
are, do not require XML messages or WSDL service-API definitions.
Project Jersey is the production-ready reference implementation for the JAX-RS
specification. Jersey implements support for the annotations defined in the JAX-RS
specification, making it easy for developers to build RESTful web services with Java
and the Java Virtual Machine (JVM).
Because RESTful web services use existing well-known W3C and Internet Engineering
Task Force (IETF) standards (HTTP, XML, URI, MIME) and have a lightweight
infrastructure that allows services to be built with minimal tooling, developing
RESTful web services is inexpensive and thus has a very low barrier for adoption. You
can use a development tool such as NetBeans IDE to further reduce the complexity of
developing RESTful web services.
A RESTful design may be appropriate when the following conditions are met.
■
■
■
The web services are completely stateless. A good test is to consider whether the
interaction can survive a restart of the server.
A caching infrastructure can be leveraged for performance. If the data that the web
service returns is not dynamically generated and can be cached, the caching
infrastructure that web servers and other intermediaries inherently provide can be
leveraged to improve performance. However, the developer must take care
because such caches are limited to the HTTP GET method for most servers.
The service producer and service consumer have a mutual understanding of the
context and content being passed along. Because there is no formal way to
describe the web services interface, both parties must agree out of band on the
schemas that describe the data being exchanged and on ways to process it
meaningfully. In the real world, most commercial applications that expose services
27-2 The Java EE 7 Tutorial
Deciding Which Type of Web Service to Use
as RESTful implementations also distribute so-called value-added toolkits that
describe the interfaces to developers in popular programming languages.
■
■
Bandwidth is particularly important and needs to be limited. REST is particularly
useful for limited-profile devices, such as PDAs and mobile phones, for which the
overhead of headers and additional layers of SOAP elements on the XML payload
must be restricted.
Web service delivery or aggregation into existing websites can be enabled easily
with a RESTful style. Developers can use such technologies as JAX-RS and
Asynchronous JavaScript with XML (Ajax) and such toolkits as Direct Web
Remoting (DWR) to consume the services in their web applications. Rather than
starting from scratch, services can be exposed with XML and consumed by HTML
pages without significantly refactoring the existing website architecture. Existing
developers will be more productive because they are adding to something they are
already familiar with rather than having to start from scratch with new
technology.
RESTful web services are discussed in Chapter 29, "Building RESTful Web Services
with JAX-RS". This chapter contains information about generating the skeleton of a
RESTful web service using both NetBeans IDE and the Maven project-management
tool.
27.3 Deciding Which Type of Web Service to Use
Basically, you want to use RESTful web services for integration over the web and big
web services in enterprise application–integration scenarios that have advanced
quality-of-service (QoS) requirements.
■
■
JAX-WS: Addresses advanced QoS requirements that commonly occur in
enterprise computing. When compared to JAX-RS, JAX-WS makes it easier to
support the WS-* set of protocols, which provide standards for security and
reliability, among other things, and interoperate with other WS-* conforming
clients and servers.
JAX-RS: Makes it easier to write web applications that apply some or all of the
constraints of the REST style to induce desirable properties in the application, such
as loose coupling (evolving the server is easier without breaking existing clients),
scalability (start small and grow), and architectural simplicity (use off-the-shelf
components, such as proxies or HTTP routers). You would choose to use JAX-RS
for your web application because it is easier for many types of clients to consume
RESTful web services while enabling the server side to evolve and scale. Clients
can choose to consume some or all aspects of the service and mash it up with other
web-based services.
Introduction to Web Services 27-3
Deciding Which Type of Web Service to Use
27-4 The Java EE 7 Tutorial
28
Building Web Services with JAX-WS
28
Java API for XML Web Services (JAX-WS) is a technology for building web services
and clients that communicate using XML. JAX-WS allows developers to write
message-oriented as well as Remote Procedure Call–oriented (RPC-oriented) web
services.
In JAX-WS, a web service operation invocation is represented by an XML-based
protocol, such as SOAP. The SOAP specification defines the envelope structure,
encoding rules, and conventions for representing web service invocations and
responses. These calls and responses are transmitted as SOAP messages (XML files)
over HTTP.
Although SOAP messages are complex, the JAX-WS API hides this complexity from
the application developer. On the server side, the developer specifies the web service
operations by defining methods in an interface written in the Java programming
language. The developer also codes one or more classes that implement those
methods. Client programs are also easy to code. A client creates a proxy (a local object
representing the service) and then simply invokes methods on the proxy. With
JAX-WS, the developer does not generate or parse SOAP messages. It is the JAX-WS
runtime system that converts the API calls and responses to and from SOAP messages.
With JAX-WS, clients and web services have a big advantage: the platform
independence of the Java programming language. In addition, JAX-WS is not
restrictive: A JAX-WS client can access a web service that is not running on the Java
platform and vice versa. This flexibility is possible because JAX-WS uses technologies
defined by the W3C: HTTP, SOAP, and WSDL. WSDL specifies an XML format for
describing a service as a set of endpoints operating on messages.
Several files in the JAX-WS examples depend on the port
that you specified when you installed GlassFish Server. These
tutorial examples assume that the server runs on the default port,
8080. They do not run with a nondefault port setting.
Note:
The following topics are addressed here:
■
Creating a Simple Web Service and Clients with JAX-WS
■
Types Supported by JAX-WS
■
Web Services Interoperability and JAX-WS
■
Further Information about JAX-WS
Building Web Services with JAX-WS 28-1
Creating a Simple Web Service and Clients with JAX-WS
28.1 Creating a Simple Web Service and Clients with JAX-WS
This section shows how to build and deploy a simple web service and two clients: an
application client and a web client. The source code for the service is in the
tut-install/examples/jaxws/helloservice-war/ directory, and the clients are in the
tut-install/examples/jaxws/hello-appclient/ and
tut-install/examples/jaxws/hello-webclient/ directories.
Figure 28–1 illustrates how JAX-WS technology manages communication between a
web service and a client.
Figure 28–1 Communication between a JAX-WS Web Service and a Client
Client
JAX-WS Runtime
SOAP
Message
Web Service
JAX-WS Runtime
The starting point for developing a JAX-WS web service is a Java class annotated with
the javax.jws.WebService annotation. The @WebService annotation defines the class
as a web service endpoint.
A service endpoint interface or service endpoint implementation (SEI) is a Java
interface or class, respectively, that declares the methods that a client can invoke on the
service. An interface is not required when building a JAX-WS endpoint. The web
service implementation class implicitly defines an SEI.
You may specify an explicit interface by adding the endpointInterface element to the
@WebService annotation in the implementation class. You must then provide an
interface that defines the public methods made available in the endpoint
implementation class.
The basic steps for creating a web service and client are as follows.
1.
Code the implementation class.
2.
Compile the implementation class.
3.
Package the files into a WAR file.
4.
Deploy the WAR file. The web service artifacts, which are used to communicate
with clients, are generated by GlassFish Server during deployment.
5.
Code the client class.
6.
Use the wsimport Maven goal to generate and compile the web service artifacts
needed to connect to the service.
7.
Compile the client class.
8.
Run the client.
If you use NetBeans IDE to create a service and client, the IDE performs the wsimport
task for you.
The sections that follow cover these steps in greater detail.
28.1.1 Requirements of a JAX-WS Endpoint
JAX-WS endpoints must follow these requirements.
■
The implementing class must be annotated with either the javax.jws.WebService
or the javax.jws.WebServiceProvider annotation.
28-2 The Java EE 7 Tutorial
Creating a Simple Web Service and Clients with JAX-WS
■
■
■
■
The implementing class may explicitly reference an SEI through the
endpointInterface element of the @WebService annotation but is not required to
do so. If no endpointInterface is specified in @WebService, an SEI is implicitly
defined for the implementing class.
The business methods of the implementing class must be public and must not be
declared static or final.
Business methods that are exposed to web service clients must be annotated with
javax.jws.WebMethod.
Business methods that are exposed to web service clients must have
JAXB-compatible parameters and return types. See the list of JAXB default data
type bindings in Types Supported by JAX-WS.
■
The implementing class must not be declared final and must not be abstract.
■
The implementing class must have a default public constructor.
■
The implementing class must not define the finalize method.
■
The implementing class may use the javax.annotation.PostConstruct or the
javax.annotation.PreDestroy annotations on its methods for lifecycle event
callbacks.
The @PostConstruct method is called by the container before the implementing
class begins responding to web service clients.
The @PreDestroy method is called by the container before the endpoint is removed
from operation.
28.1.2 Coding the Service Endpoint Implementation Class
In this example, the implementation class, Hello, is annotated as a web service
endpoint using the @WebService annotation. Hello declares a single method named
sayHello, annotated with the @WebMethod annotation, which exposes the annotated
method to web service clients. The sayHello method returns a greeting to the client,
using the name passed to it to compose the greeting. The implementation class also
must define a default, public, no-argument constructor.
package javaeetutorial.helloservice;
import javax.jws.WebService;
import javax.jws.WebMethod;
@WebService
public class Hello {
private final String message = "Hello, ";
public void Hello() {
}
@WebMethod
public String sayHello(String name) {
return message + name + ".";
}
}
28.1.3 Building, Packaging, and Deploying the Service
You can use either NetBeans IDE or Maven to build, package, and deploy the
helloservice-war application.
Building Web Services with JAX-WS 28-3
Creating a Simple Web Service and Clients with JAX-WS
28.1.3.1 To Build, Package, and Deploy the Service Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/jaxws
4.
Select the helloservice-war folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the helloservice-war project and select Run.
This command builds and packages the application into a WAR file,
helloservice-war.war, located in
tut-install/examples/jaxws/helloservice-war/target/, and deploys this WAR
file to your GlassFish Server instance. It also opens the web service test interface at
the URL shown in To Test the Service without a Client.
Next Steps
You can view the WSDL file of the deployed service by requesting the URL
http://localhost:8080/helloservice-war/HelloService?wsdl in a web browser.
Now you are ready to create a client that accesses this service.
28.1.3.2 To Build, Package, and Deploy the Service Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/jaxws/helloservice-war/
3.
Enter the following command:
mvn install
This command builds and packages the application into a WAR file,
helloservice-war.war, located in the target directory, and then deploys the
WAR to GlassFish Server.
Next Steps
You can view the WSDL file of the deployed service by requesting the URL
http://localhost:8080/helloservice-war/HelloService?wsdl in a web browser.
Now you are ready to create a client that accesses this service.
28.1.4 Testing the Methods of a Web Service Endpoint
GlassFish Server allows you to test the methods of a web service endpoint.
28.1.4.1 To Test the Service without a Client
To test the sayHello method of HelloService, follow these steps.
1.
Open the web service test interface by entering the following URL in a web
browser:
http://localhost:8080/helloservice-war/HelloService?Tester
28-4 The Java EE 7 Tutorial
Creating a Simple Web Service and Clients with JAX-WS
2.
Under Methods, enter a name as the parameter to the sayHello method.
3.
Click sayHello.
This takes you to the sayHello Method invocation page.
Under Method returned, you'll see the response from the endpoint.
28.1.5 A Simple JAX-WS Application Client
The HelloAppClient class is a stand-alone application client that accesses the sayHello
method of HelloService. This call is made through a port, a local object that acts as a
proxy for the remote service. The port is created at development time by the wsimport
Maven goal, which generates JAX-WS portable artifacts based on a WSDL file.
28.1.5.1 Coding the Application Client
When invoking the remote methods on the port, the client performs these steps.
1.
It uses the generated helloservice.endpoint.HelloService class, which
represents the service at the URI of the deployed service's WSDL file:
import javaeetutorial.helloservice.endpoint.HelloService;
import javax.xml.ws.WebServiceRef;
public class HelloAppClient {
@WebServiceRef(wsdlLocation =
"http://localhost:8080/helloservice-war/HelloService?WSDL")
private static HelloService service;
2.
It retrieves a proxy to the service, also known as a port, by invoking getHelloPort
on the service:
javaeetutorial.helloservice.endpoint.Hello port = service.getHelloPort();
The port implements the SEI defined by the service.
3.
It invokes the port's sayHello method, passing a string to the service:
return port.sayHello(arg0);
Here is the full source of HelloAppClient.java, which is located in the
tut-install/examples/jaxws/hello-appclient/src/main/java/javaeetutorial/hello
/appclient/ directory:
package javaeetutorial.hello.appclient;
import javaeetutorial.helloservice.endpoint.HelloService;
import javax.xml.ws.WebServiceRef;
public class HelloAppClient {
@WebServiceRef(wsdlLocation =
"http://localhost:8080/helloservice-war/HelloService?WSDL")
private static HelloService service;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
System.out.println(sayHello("world"));
}
Building Web Services with JAX-WS 28-5
Creating a Simple Web Service and Clients with JAX-WS
private static String sayHello(java.lang.String arg0) {
javaeetutorial.helloservice.endpoint.Hello port =
service.getHelloPort();
return port.sayHello(arg0);
}
}
28.1.5.2 Running the Application Client
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
hello-appclient application. To build the client, you must first have deployed
helloservice-war, as described in Building, Packaging, and Deploying the Service.
To Run the Application Client Using NetBeans IDE
1.
From the File menu, choose Open Project.
2.
In the Open Project dialog box, navigate to:
tut-install/examples/jaxws
3.
Select the hello-appclient folder.
4.
Click Open Project.
5.
In the Projects tab, right-click the hello-appclient project and select Build.
This command runs the wsimport goal, then builds, packages, and runs the client.
You will see the output of the application client in the hello-appclient output tab:
--- exec-maven-plugin:1.2.1:exec (run-appclient) @ hello-appclient --Hello, world.
To Run the Application Client Using Maven
1.
In a terminal window, go to:
tut-install/examples/jaxws/hello-appclient/
2.
Enter the following command:
mvn install
This command runs the wsimport goal, then builds, packages, and runs the client.
The application client output looks like this:
--- exec-maven-plugin:1.2.1:exec (run-appclient) @ hello-appclient --Hello, world.
28.1.6 A Simple JAX-WS Web Client
HelloServlet is a servlet that, like the Java client, calls the sayHello method of the
web service. Like the application client, it makes this call through a port.
28.1.6.1 Coding the Servlet
To invoke the method on the port, the client performs these steps.
1.
It imports the HelloService endpoint and the WebServiceRef annotation:
import javaeetutorial.helloservice.endpoint.HelloService;
...
import javax.xml.ws.WebServiceRef;
2.
It defines a reference to the web service by specifying the WSDL location:
28-6 The Java EE 7 Tutorial
Creating a Simple Web Service and Clients with JAX-WS
@WebServiceRef(wsdlLocation =
"http://localhost:8080/helloservice-war/HelloService?WSDL")
3.
It declares the web service, then defines a private method that calls the sayHello
method on the port:
private HelloService service;
...
private String sayHello(java.lang.String arg0) {
javaeetutorial.helloservice.endpoint.Hello port =
service.getHelloPort();
return port.sayHello(arg0);
}
4.
In the servlet, it calls this private method:
out.println("<p>" + sayHello("world") + "</p>");
The significant parts of the HelloServlet code follow. The code is located in the
tut-install/examples/jaxws/hello-webclient/src/java/javaeetutorial/hello/
webclient/ directory.
package javaeetutorial.hello.webclient;
import
import
import
import
import
import
import
import
import
javaeetutorial.helloservice.endpoint.HelloService;
java.io.IOException;
java.io.PrintWriter;
javax.servlet.ServletException;
javax.servlet.annotation.WebServlet;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.xml.ws.WebServiceRef;
@WebServlet(name="HelloServlet", urlPatterns={"/HelloServlet"})
public class HelloServlet extends HttpServlet {
@WebServiceRef(wsdlLocation =
"http://localhost:8080/helloservice-war/HelloService?WSDL")
private HelloService service;
/**
* Processes requests for both HTTP <code>GET</code>
*
and <code>POST</code> methods.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
out.println("<html lang=\"en\">");
out.println("<head>");
out.println("<title>Servlet HelloServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet HelloServlet at " +
request.getContextPath () + "</h1>");
Building Web Services with JAX-WS 28-7
Creating a Simple Web Service and Clients with JAX-WS
out.println("<p>" + sayHello("world") + "</p>");
out.println("</body>");
out.println("</html>");
}
}
// doGet and doPost methods, which call processRequest, and
//
getServletInfo method
private String sayHello(java.lang.String arg0) {
javaeetutorial.helloservice.endpoint.Hello port =
service.getHelloPort();
return port.sayHello(arg0);
}
}
28.1.6.2 Running the Web Client
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
hello-webclient application. To build the client, you must first have deployed
helloservice-war, as described in Building, Packaging, and Deploying the Service.
To Run the Web Client Using NetBeans IDE
1.
From the File menu, choose Open Project.
2.
In the Open Project dialog box, navigate to:
tut-install/examples/jaxws
3.
Select the hello-webclient folder.
4.
Click Open Project.
5.
In the Projects tab, right-click the hello-webclient project and select Build.
This task runs the wsimport goal, builds and packages the application into a WAR
file, hello-webclient.war, located in the target directory, and deploys it to
GlassFish Server.
6.
In a web browser, enter the following URL:
http://localhost:8080/hello-webclient/HelloServlet
The output of the sayHello method appears in the window.
To Run the Web Client Using Maven
1.
In a terminal window, go to:
tut-install/examples/jaxws/hello-webclient/
2.
Enter the following command:
mvn install
This command runs the wsimport goal, then build and packages the application
into a WAR file, hello-webclient.war, located in the target directory. The WAR
file is then deployed to GlassFish Server.
3.
In a web browser, enter the following URL:
http://localhost:8080/hello-webclient/HelloServlet
The output of the sayHello method appears in the window.
28-8 The Java EE 7 Tutorial
Types Supported by JAX-WS
28.2 Types Supported by JAX-WS
JAX-WS delegates the mapping of Java programming language types to and from
XML definitions to JAXB. Application developers don't need to know the details of
these mappings but should be aware that not every class in the Java language can be
used as a method parameter or return type in JAX-WS.
The following sections explain the default schema-to-Java and Java-to-schema data
type bindings.
28.2.1 Schema-to-Java Mapping
The Java language provides a richer set of data types than XML schema. Table 28–1
lists the mapping of XML data types to Java data types in JAXB.
Table 28–1
Mapping of XML Data Types to Java Data Types in JAXB
XML Schema Type
Java Data Type
xsd:string
java.lang.String
xsd:integer
java.math.BigInteger
xsd:int
int
xsd.long
long
xsd:short
short
xsd:decimal
java.math.BigDecimal
xsd:float
float
xsd:double
double
xsd:boolean
boolean
xsd:byte
byte
xsd:QName
javax.xml.namespace.QName
xsd:dateTime
javax.xml.datatype.XMLGregorianCalendar
xsd:base64Binary
byte[]
xsd:hexBinary
byte[]
xsd:unsignedInt
long
xsd:unsignedShort
int
xsd:unsignedByte
short
xsd:time
javax.xml.datatype.XMLGregorianCalendar
xsd:date
javax.xml.datatype.XMLGregorianCalendar
xsd:g
javax.xml.datatype.XMLGregorianCalendar
xsd:anySimpleType
java.lang.Object
xsd:anySimpleType
java.lang.String
xsd:duration
javax.xml.datatype.Duration
xsd:NOTATION
javax.xml.namespace.QName
28.2.2 Java-to-Schema Mapping
Table 28–2 shows the default mapping of Java classes to XML data types.
Building Web Services with JAX-WS 28-9
Web Services Interoperability and JAX-WS
Table 28–2
Mapping of Java Classes to XML Data Types in JAXB
Java Class
XML Data Type
java.lang.String
xs:string
java.math.BigInteger
xs:integer
java.math.BigDecimal
xs:decimal
java.util.Calendar
xs:dateTime
java.util.Date
xs:dateTime
javax.xml.namespace.QName
xs:QName
java.net.URI
xs:string
javax.xml.datatype.XMLGregorianCalendar
xs:anySimpleType
javax.xml.datatype.Duration
xs:duration
java.lang.Object
xs:anyType
java.awt.Image
xs:base64Binary
javax.activation.DataHandler
xs:base64Binary
javax.xml.transform.Source
xs:base64Binary
java.util.UUID
xs:string
28.3 Web Services Interoperability and JAX-WS
JAX-WS supports the Web Services Interoperability (WS-I) Basic Profile Version 1.1.
The WS-I Basic Profile is a document that clarifies the SOAP 1.1 and WSDL 1.1
specifications to promote SOAP interoperability. For links related to WS-I, see Further
Information about JAX-WS.
To support WS-I Basic Profile Version 1.1, the JAX-WS runtime supports doc/literal
and rpc/literal encodings for services, static ports, dynamic proxies, and the Dynamic
Invocation Interface (DII).
28.4 Further Information about JAX-WS
For more information about JAX-WS and related technologies, see
■
Java API for XML Web Services 2.2 specification:
http://jcp.org/en/jsr/detail?id=224
■
JAX-WS home:
https://jax-ws.java.net/
■
Simple Object Access Protocol (SOAP) 1.2 W3C Note:
http://www.w3.org/TR/soap/
■
Web Services Description Language (WSDL) 1.1 W3C Note:
http://www.w3.org/TR/wsdl
■
WS-I Basic Profile 1.2 and 2.0:
http://www.ws-i.org
28-10 The Java EE 7 Tutorial
29
Building RESTful Web Services with JAX-RS
29
This chapter describes the REST architecture, RESTful web services, and the Java API
for RESTful Web Services (JAX-RS, defined in JSR 339).
JAX-RS makes it easy for developers to build RESTful web services using the Java
programming language.
The following topics are addressed here:
■
What Are RESTful Web Services?
■
Creating a RESTful Root Resource Class
■
Example Applications for JAX-RS
■
Further Information about JAX-RS
29.1 What Are RESTful Web Services?
RESTful web services are loosely coupled, lightweight web services that are
particularly well suited for creating APIs for clients spread out across the internet.
Representational State Transfer (REST) is an architectural style of client-server
application centered around the transfer of representations of resources through
requests and responses. In the REST architectural style, data and functionality are
considered resources and are accessed using Uniform Resource Identifiers (URIs),
typically links on the Web. The resources are represented by documents and are acted
upon by using a set of simple, well-defined operations.
For example, a REST resource might be the current weather conditions for a city. The
representation of that resource might be an XML document, an image file, or an HTML
page. A client might retrieve a particular representation, modify the resource by
updating its data, or delete the resource entirely.
The REST architectural style is designed to use a stateless communication protocol,
typically HTTP. In the REST architecture style, clients and servers exchange
representations of resources by using a standardized interface and protocol.
The following principles encourage RESTful applications to be simple, lightweight,
and fast:
■
■
Resource identification through URI: A RESTful web service exposes a set of
resources that identify the targets of the interaction with its clients. Resources are
identified by URIs, which provide a global addressing space for resource and
service discovery. See The @Path Annotation and URI Path Templates for more
information.
Uniform interface: Resources are manipulated using a fixed set of four create,
read, update, delete operations: PUT, GET, POST, and DELETE. PUT creates a new
Building RESTful Web Services with JAX-RS 29-1
Creating a RESTful Root Resource Class
resource, which can be then deleted by using DELETE. GET retrieves the current
state of a resource in some representation. POST transfers a new state onto a
resource. See Responding to HTTP Methods and Requests for more information.
■
■
Self-descriptive messages: Resources are decoupled from their representation so
that their content can be accessed in a variety of formats, such as HTML, XML,
plain text, PDF, JPEG, JSON, and other document formats. Metadata about the
resource is available and used, for example, to control caching, detect transmission
errors, negotiate the appropriate representation format, and perform
authentication or access control. See Responding to HTTP Methods and Requests
and Using Entity Providers to Map HTTP Response and Request Entity Bodies for
more information.
Stateful interactions through links: Every interaction with a resource is stateless;
that is, request messages are self-contained. Stateful interactions are based on the
concept of explicit state transfer. Several techniques exist to exchange state, such as
URI rewriting, cookies, and hidden form fields. State can be embedded in response
messages to point to valid future states of the interaction. See Using Entity
Providers to Map HTTP Response and Request Entity Bodies and "Building URIs"
in the JAX-RS Overview document for more information.
29.2 Creating a RESTful Root Resource Class
Root resource classes are "plain old Java objects" (POJOs) that are either annotated
with @Path or have at least one method annotated with @Path or a request method
designator, such as @GET, @PUT, @POST, or @DELETE. Resource methods are methods of a
resource class annotated with a request method designator. This section explains how
to use JAX-RS to annotate Java classes to create RESTful web services.
29.2.1 Developing RESTful Web Services with JAX-RS
JAX-RS is a Java programming language API designed to make it easy to develop
applications that use the REST architecture.
The JAX-RS API uses Java programming language annotations to simplify the
development of RESTful web services. Developers decorate Java programming
language class files with JAX-RS annotations to define resources and the actions that
can be performed on those resources. JAX-RS annotations are runtime annotations;
therefore, runtime reflection will generate the helper classes and artifacts for the
resource. A Java EE application archive containing JAX-RS resource classes will have
the resources configured, the helper classes and artifacts generated, and the resource
exposed to clients by deploying the archive to a Java EE server.
Table 29–1 lists some of the Java programming annotations that are defined by JAX-RS,
with a brief description of how each is used. Further information on the JAX-RS APIs
can be viewed at http://docs.oracle.com/javaee/7/api/.
Table 29–1
Summary of JAX-RS Annotations
Annotation
Description
@Path
The @Path annotation's value is a relative URI path indicating where the
Java class will be hosted: for example, /helloworld. You can also embed
variables in the URIs to make a URI path template. For example, you
could ask for the name of a user and pass it to the application as a
variable in the URI: /helloworld/{username}.
29-2 The Java EE 7 Tutorial
Creating a RESTful Root Resource Class
Table 29–1 (Cont.) Summary of JAX-RS Annotations
Annotation
Description
@GET
The @GET annotation is a request method designator and corresponds to
the similarly named HTTP method. The Java method annotated with this
request method designator will process HTTP GET requests. The
behavior of a resource is determined by the HTTP method to which the
resource is responding.
@POST
The @POST annotation is a request method designator and corresponds to
the similarly named HTTP method. The Java method annotated with this
request method designator will process HTTP POST requests. The
behavior of a resource is determined by the HTTP method to which the
resource is responding.
@PUT
The @PUT annotation is a request method designator and corresponds to
the similarly named HTTP method. The Java method annotated with this
request method designator will process HTTP PUT requests. The
behavior of a resource is determined by the HTTP method to which the
resource is responding.
@DELETE
The @DELETE annotation is a request method designator and corresponds
to the similarly named HTTP method. The Java method annotated with
this request method designator will process HTTP DELETE requests. The
behavior of a resource is determined by the HTTP method to which the
resource is responding.
@HEAD
The @HEAD annotation is a request method designator and corresponds to
the similarly named HTTP method. The Java method annotated with this
request method designator will process HTTP HEAD requests. The
behavior of a resource is determined by the HTTP method to which the
resource is responding.
@PathParam
The @PathParam annotation is a type of parameter that you can extract for
use in your resource class. URI path parameters are extracted from the
request URI, and the parameter names correspond to the URI path
template variable names specified in the @Path class-level annotation.
@QueryParam
The @QueryParam annotation is a type of parameter that you can extract
for use in your resource class. Query parameters are extracted from the
request URI query parameters.
@Consumes
The @Consumes annotation is used to specify the MIME media types of
representations a resource can consume that were sent by the client.
@Produces
The @Produces annotation is used to specify the MIME media types of
representations a resource can produce and send back to the client: for
example, "text/plain".
@Provider
The @Provider annotation is used for anything that is of interest to the
JAX-RS runtime, such as MessageBodyReader and MessageBodyWriter.
For HTTP requests, the MessageBodyReader is used to map an HTTP
request entity body to method parameters. On the response side, a return
value is mapped to an HTTP response entity body by using a
MessageBodyWriter. If the application needs to supply additional
metadata, such as HTTP headers or a different status code, a method can
return a Response that wraps the entity and that can be built using
Response.ResponseBuilder.
@ApplicationPath
The @ApplicationPath annotation is used to define the URL mapping for
the application. The path specified by @ApplicationPath is the base URI
for all resource URIs specified by @Path annotations in the resource class.
You may only apply @ApplicationPath to a subclass of
javax.ws.rs.core.Application.
Building RESTful Web Services with JAX-RS 29-3
Creating a RESTful Root Resource Class
29.2.2 Overview of a JAX-RS Application
The following code sample is a very simple example of a root resource class that uses
JAX-RS annotations:
package javaeetutorial.hello;
import
import
import
import
import
import
import
javax.ws.rs.Consumes;
javax.ws.rs.GET;
javax.ws.rs.PUT;
javax.ws.rs.Path;
javax.ws.rs.Produces;
javax.ws.rs.core.Context;
javax.ws.rs.core.UriInfo;
/**
* Root resource (exposed at "helloworld" path)
*/
@Path("helloworld")
public class HelloWorld {
@Context
private UriInfo context;
/** Creates a new instance of HelloWorld */
public HelloWorld() {
}
/**
* Retrieves representation of an instance of helloWorld.HelloWorld
* @return an instance of java.lang.String
*/
@GET
@Produces("text/html")
public String getHtml() {
return "<html lang=\"en\"><body><h1>Hello, World!!</h1></body></html>";
}
}
The following sections describe the annotations used in this example.
■
■
■
■
The @Path annotation's value is a relative URI path. In the preceding example, the
Java class will be hosted at the URI path /helloworld. This is an extremely simple
use of the @Path annotation, with a static URI path. Variables can be embedded in
the URIs. URI path templates are URIs with variables embedded within the URI
syntax.
The @GET annotation is a request method designator, along with @POST, @PUT,
@DELETE, and @HEAD, defined by JAX-RS and corresponding to the similarly named
HTTP methods. In the example, the annotated Java method will process HTTP
GET requests. The behavior of a resource is determined by the HTTP method to
which the resource is responding.
The @Produces annotation is used to specify the MIME media types a resource can
produce and send back to the client. In this example, the Java method will produce
representations identified by the MIME media type "text/html".
The @Consumes annotation is used to specify the MIME media types a resource can
consume that were sent by the client. The example could be modified to set the
message returned by the getHtml method, as shown in this code example:
@POST
@Consumes("text/plain")
29-4 The Java EE 7 Tutorial
Creating a RESTful Root Resource Class
public void postHtml(String message) {
// Store the message
}
29.2.3 The @Path Annotation and URI Path Templates
The @Path annotation identifies the URI path template to which the resource responds
and is specified at the class or method level of a resource. The @Path annotation's value
is a partial URI path template relative to the base URI of the server on which the
resource is deployed, the context root of the application, and the URL pattern to which
the JAX-RS runtime responds.
URI path templates are URIs with variables embedded within the URI syntax. These
variables are substituted at runtime in order for a resource to respond to a request
based on the substituted URI. Variables are denoted by braces ({ and }). For example,
look at the following @Path annotation:
@Path("/users/{username}")
In this kind of example, a user is prompted to type his or her name, and then a JAX-RS
web service configured to respond to requests to this URI path template responds. For
example, if the user types the user name "Galileo," the web service responds to the
following URL:
http://example.com/users/Galileo
To obtain the value of the user name, the @PathParam annotation may be used on the
method parameter of a request method, as shown in the following code example:
@Path("/users/{username}")
public class UserResource {
@GET
@Produces("text/xml")
public String getUser(@PathParam("username") String userName) {
...
}
}
By default, the URI variable must match the regular expression "[^/]+?". This
variable may be customized by specifying a different regular expression after the
variable name. For example, if a user name must consist only of lowercase and
uppercase alphanumeric characters, override the default regular expression in the
variable definition:
@Path("users/{username: [a-zA-Z][a-zA-Z_0-9]*}")
In this example, the username variable will match only user names that begin with one
uppercase or lowercase letter and zero or more alphanumeric characters and the
underscore character. If a user name does not match that template, a 404 (Not Found)
response will be sent to the client.
A @Path value isn't required to have leading or trailing slashes (/). The JAX-RS
runtime parses URI path templates the same way, whether or not they have leading or
trailing slashes.
A URI path template has one or more variables, with each variable name surrounded
by braces: { to begin the variable name and } to end it. In the preceding example,
username is the variable name. At runtime, a resource configured to respond to the
Building RESTful Web Services with JAX-RS 29-5
Creating a RESTful Root Resource Class
preceding URI path template will attempt to process the URI data that corresponds to
the location of {username} in the URI as the variable data for username.
For example, if you want to deploy a resource that responds to the URI path template
http://example.com/myContextRoot/resources/{name1}/{name2}/, you must first
deploy the application to a Java EE server that responds to requests to the
http://example.com/myContextRoot URI and then decorate your resource with the
following @Path annotation:
@Path("/{name1}/{name2}/")
public class SomeResource {
...
}
In this example, the URL pattern for the JAX-RS helper servlet, specified in web.xml, is
the default:
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
A variable name can be used more than once in the URI path template.
If a character in the value of a variable would conflict with the reserved characters of a
URI, the conflicting character should be substituted with percent encoding. For
example, spaces in the value of a variable should be substituted with %20.
When defining URI path templates, be careful that the resulting URI after substitution
is valid.
Table 29–2 lists some examples of URI path template variables and how the URIs are
resolved after substitution. The following variable names and values are used in the
examples:
■
name1: james
■
name2: gatz
■
name3:
■
location: Main%20Street
■
question: why
Note:
Table 29–2
The value of the name3 variable is an empty string.
Examples of URI Path Templates
URI Path Template
URI After Substitution
http://example.com/{name1}/{name2}/
http://example.com/james/gatz/
http://example.com/{question}/{question}/{question}/
http://example.com/why/why/why/
http://example.com/maps/{location}
http://example.com/maps/Main%20Street
http://example.com/{name3}/home/
http://example.com//home/
29.2.4 Responding to HTTP Methods and Requests
The behavior of a resource is determined by the HTTP methods (typically, GET, POST,
PUT, or DELETE) to which the resource is responding.
29-6 The Java EE 7 Tutorial
Creating a RESTful Root Resource Class
29.2.4.1 The Request Method Designator Annotations
Request method designator annotations are runtime annotations, defined by JAX-RS,
that correspond to the similarly named HTTP methods. Within a resource class file,
HTTP methods are mapped to Java programming language methods by using the
request method designator annotations. The behavior of a resource is determined by
which HTTP method the resource is responding to. JAX-RS defines a set of request
method designators for the common HTTP methods GET, POST, PUT, DELETE, and
HEAD; you can also create your own custom request method designators. Creating
custom request method designators is outside the scope of this document.
The following example shows the use of the PUT method to create or update a storage
container:
@PUT
public Response putContainer() {
System.out.println("PUT CONTAINER " + container);
URI uri = uriInfo.getAbsolutePath();
Container c = new Container(container, uri.toString());
Response r;
if (!MemoryStore.MS.hasContainer(c)) {
r = Response.created(uri).build();
} else {
r = Response.noContent().build();
}
MemoryStore.MS.createContainer(c);
return r;
}
By default, the JAX-RS runtime will automatically support the methods HEAD and
OPTIONS if not explicitly implemented. For HEAD, the runtime will invoke the
implemented GET method, if present, and ignore the response entity, if set. For
OPTIONS, the Allow response header will be set to the set of HTTP methods
supported by the resource. In addition, the JAX-RS runtime will return a Web
Application Definition Language (WADL) document describing the resource; see
http://www.w3.org/Submission/wadl/ for more information.
Methods decorated with request method designators must return void, a Java
programming language type, or a javax.ws.rs.core.Response object. Multiple
parameters may be extracted from the URI by using the @PathParam or @QueryParam
annotations, as described in Extracting Request Parameters. Conversion between Java
types and an entity body is the responsibility of an entity provider, such as
MessageBodyReader or MessageBodyWriter. Methods that need to provide additional
metadata with a response should return an instance of the Response class. The
ResponseBuilder class provides a convenient way to create a Response instance using
a builder pattern. The HTTP PUT and POST methods expect an HTTP request body, so
you should use a MessageBodyReader for methods that respond to PUT and POST
requests.
Both @PUT and @POST can be used to create or update a resource. POST can mean
anything, so when using POST, it is up to the application to define the semantics. PUT
has well-defined semantics. When using PUT for creation, the client declares the URI
for the newly created resource.
PUT has very clear semantics for creating and updating a resource. The representation
the client sends must be the same representation that is received using a GET, given
the same media type. PUT does not allow a resource to be partially updated, a
Building RESTful Web Services with JAX-RS 29-7
Creating a RESTful Root Resource Class
common mistake when attempting to use the PUT method. A common application
pattern is to use POST to create a resource and return a 201 response with a location
header whose value is the URI to the newly created resource. In this pattern, the web
service declares the URI for the newly created resource.
29.2.4.2 Using Entity Providers to Map HTTP Response and Request Entity Bodies
Entity providers supply mapping services between representations and their
associated Java types. The two types of entity providers are MessageBodyReader and
MessageBodyWriter. For HTTP requests, the MessageBodyReader is used to map an
HTTP request entity body to method parameters. On the response side, a return value
is mapped to an HTTP response entity body by using a MessageBodyWriter. If the
application needs to supply additional metadata, such as HTTP headers or a different
status code, a method can return a Response that wraps the entity and that can be built
by using Response.ResponseBuilder.
Table 29–3 shows the standard types that are supported automatically for HTTP
request and response entity bodies. You need to write an entity provider only if you
are not choosing one of these standard types.
Table 29–3
Types Supported for HTTP Request and Response Entity Bodies
Java Type
Supported Media Types
byte[]
All media types (*/*)
java.lang.String
All text media types (text/*)
java.io.InputStream
All media types (*/*)
java.io.Reader
All media types (*/*)
java.io.File
All media types (*/*)
javax.activation.DataSource
All media types (*/*)
javax.xml.transform.Source
XML media types (text/xml,
application/xml, and application/*+xml)
javax.xml.bind.JAXBElement and
application-supplied JAXB classes
XML media types (text/xml,
application/xml, and application/*+xml)
MultivaluedMap<String, String>
Form content
(application/x-www-form-urlencoded)
StreamingOutput
All media types (*/*), MessageBodyWriter
only
The following example shows how to use MessageBodyReader with the @Consumes and
@Provider annotations:
@Consumes("application/x-www-form-urlencoded")
@Provider
public class FormReader implements MessageBodyReader<NameValuePair> {
The following example shows how to use MessageBodyWriter with the @Produces and
@Provider annotations:
@Produces("text/html")
@Provider
public class FormWriter implements
MessageBodyWriter<Hashtable<String, String>> {
The following example shows how to use ResponseBuilder:
29-8 The Java EE 7 Tutorial
Creating a RESTful Root Resource Class
@GET
public Response getItem() {
System.out.println("GET ITEM " + container + " " + item);
Item i = MemoryStore.MS.getItem(container, item);
if (i == null)
throw new NotFoundException("Item not found");
Date lastModified = i.getLastModified().getTime();
EntityTag et = new EntityTag(i.getDigest());
ResponseBuilder rb = request.evaluatePreconditions(lastModified, et);
if (rb != null)
return rb.build();
byte[] b = MemoryStore.MS.getItemData(container, item);
return Response.ok(b, i.getMimeType()).
lastModified(lastModified).tag(et).build();
}
29.2.5 Using @Consumes and @Produces to Customize Requests and Responses
The information sent to a resource and then passed back to the client is specified as a
MIME media type in the headers of an HTTP request or response. You can specify
which MIME media types of representations a resource can respond to or produce by
using the following annotations:
■
javax.ws.rs.Consumes
■
javax.ws.rs.Produces
By default, a resource class can respond to and produce all MIME media types of
representations specified in the HTTP request and response headers.
29.2.5.1 The @Produces Annotation
The @Produces annotation is used to specify the MIME media types or representations
a resource can produce and send back to the client. If @Produces is applied at the class
level, all the methods in a resource can produce the specified MIME types by default.
If applied at the method level, the annotation overrides any @Produces annotations
applied at the class level.
If no methods in a resource are able to produce the MIME type in a client request, the
JAX-RS runtime sends back an HTTP "406 Not Acceptable" error.
The value of @Produces is an array of String of MIME types or a comma-separated list
of MediaType constants. For example:
@Produces({"image/jpeg,image/png"})
The following example shows how to apply @Produces at both the class and method
levels:
@Path("/myResource")
@Produces("text/plain")
public class SomeResource {
@GET
public String doGetAsPlainText() {
...
}
@GET
@Produces("text/html")
public String doGetAsHtml() {
Building RESTful Web Services with JAX-RS 29-9
Creating a RESTful Root Resource Class
...
}
}
The doGetAsPlainText method defaults to the MIME media type of the @Produces
annotation at the class level. The doGetAsHtml method's @Produces annotation
overrides the class-level @Produces setting and specifies that the method can produce
HTML rather than plain text.
@Produces can also use the constants defined in the javax.ws.rs.core.MediaType
class to specify the media type. For example, specifying MediaType.APPLICATION_XML
is equivalent to specifying "application/xml".
@Produces(MediaType.APPLICATION_XML)
@GET
public Customer getCustomer() { ... }
If a resource class is capable of producing more than one MIME media type, the
resource method chosen will correspond to the most acceptable media type as
declared by the client. More specifically, the Accept header of the HTTP request
declares what is most acceptable. For example, if the Accept header is Accept:
text/plain, the doGetAsPlainText method will be invoked. Alternatively, if the
Accept header is Accept: text/plain;q=0.9, text/html, which declares that the
client can accept media types of text/plain and text/html but prefers the latter, the
doGetAsHtml method will be invoked.
More than one media type may be declared in the same @Produces declaration. The
following code example shows how this is done:
@Produces({"application/xml", "application/json"})
public String doGetAsXmlOrJson() {
...
}
The doGetAsXmlOrJson method will get invoked if either of the media types
application/xml or application/json is acceptable. If both are equally acceptable,
the former will be chosen because it occurs first. The preceding examples refer
explicitly to MIME media types for clarity. It is possible to refer to constant values,
which may reduce typographical errors. For more information, see the API
documentation for the constant field values of javax.ws.rs.core.MediaType.
29.2.5.2 The @Consumes Annotation
The @Consumes annotation is used to specify which MIME media types of
representations a resource can accept, or consume, from the client. If @Consumes is
applied at the class level, all the response methods accept the specified MIME types by
default. If applied at the method level, @Consumes overrides any @Consumes
annotations applied at the class level.
If a resource is unable to consume the MIME type of a client request, the JAX-RS
runtime sends back an HTTP 415 ("Unsupported Media Type") error.
The value of @Consumes is an array of String of acceptable MIME types, or a
comma-separated list of MediaType constants. For example:
@Consumes({"text/plain,text/html"})
This is the equivalent of:
@Consumes({MediaType.TEXT_PLAIN,MediaType.TEXT_HTML})
29-10 The Java EE 7 Tutorial
Creating a RESTful Root Resource Class
The following example shows how to apply @Consumes at both the class and method
levels:
@Path("/myResource")
@Consumes("multipart/related")
public class SomeResource {
@POST
public String doPost(MimeMultipart mimeMultipartData) {
...
}
@POST
@Consumes("application/x-www-form-urlencoded")
public String doPost2(FormURLEncodedProperties formData) {
...
}
}
The doPost method defaults to the MIME media type of the @Consumes annotation at
the class level. The doPost2 method overrides the class level @Consumes annotation to
specify that it can accept URL-encoded form data.
If no resource methods can respond to the requested MIME type, an HTTP 415
("Unsupported Media Type") error is returned to the client.
The HelloWorld example discussed previously in this section can be modified to set
the message by using @Consumes, as shown in the following code example:
@POST
@Consumes("text/html")
public void postHtml(String message) {
// Store the message
}
In this example, the Java method will consume representations identified by the MIME
media type text/plain. Note that the resource method returns void. This means that
no representation is returned and that a response with a status code of HTTP 204 ("No
Content") will be returned.
29.2.6 Extracting Request Parameters
Parameters of a resource method may be annotated with parameter-based annotations
to extract information from a request. A previous example presented the use of the
@PathParam parameter to extract a path parameter from the path component of the
request URL that matched the path declared in @Path.
You can extract the following types of parameters for use in your resource class:
■
Query
■
URI path
■
Form
■
Cookie
■
Header
■
Matrix
Query parameters are extracted from the request URI query parameters and are
specified by using the javax.ws.rs.QueryParam annotation in the method parameter
Building RESTful Web Services with JAX-RS 29-11
Creating a RESTful Root Resource Class
arguments. The following example demonstrates using @QueryParam to extract query
parameters from the Query component of the request URL:
@Path("smooth")
@GET
public Response smooth(
@DefaultValue("2") @QueryParam("step") int step,
@DefaultValue("true") @QueryParam("min-m") boolean hasMin,
@DefaultValue("true") @QueryParam("max-m") boolean hasMax,
@DefaultValue("true") @QueryParam("last-m") boolean hasLast,
@DefaultValue("blue") @QueryParam("min-color") ColorParam minColor,
@DefaultValue("green") @QueryParam("max-color") ColorParam maxColor,
@DefaultValue("red") @QueryParam("last-color") ColorParam lastColor
) { ... }
If the query parameter step exists in the query component of the request URI, the
value of step will be extracted and parsed as a 32-bit signed integer and assigned to
the step method parameter. If step does not exist, a default value of 2, as declared in
the @DefaultValue annotation, will be assigned to the step method parameter. If the
step value cannot be parsed as a 32-bit signed integer, an HTTP 400 ("Client Error")
response is returned.
User-defined Java programming language types may be used as query parameters.
The following code example shows the ColorParam class used in the preceding query
parameter example:
public class ColorParam extends Color {
public ColorParam(String s) {
super(getRGB(s));
}
private static int getRGB(String s) {
if (s.charAt(0) == '#') {
try {
Color c = Color.decode("0x" + s.substring(1));
return c.getRGB();
} catch (NumberFormatException e) {
throw new WebApplicationException(400);
}
} else {
try {
Field f = Color.class.getField(s);
return ((Color)f.get(null)).getRGB();
} catch (Exception e) {
throw new WebApplicationException(400);
}
}
}
}
The constructor for ColorParam takes a single String parameter.
Both @QueryParam and @PathParam can be used only on the following Java types.
■
All primitive types except char.
■
All wrapper classes of primitive types except Character.
■
Any class with a constructor that accepts a single String argument.
■
Any class with the static method named valueOf(String) that accepts a single
String argument.
29-12 The Java EE 7 Tutorial
Creating a RESTful Root Resource Class
■
List<T>, Set<T>, or SortedSet<T>, where T matches the already listed criteria.
Sometimes, parameters may contain more than one value for the same name. If
this is the case, these types may be used to obtain all values.
If @DefaultValue is not used in conjunction with @QueryParam, and the query
parameter is not present in the request, the value will be an empty collection for List,
Set, or SortedSet; null for other object types; and the default for primitive types.
URI path parameters are extracted from the request URI, and the parameter names
correspond to the URI path template variable names specified in the @Path class-level
annotation. URI parameters are specified using the javax.ws.rs.PathParam
annotation in the method parameter arguments. The following example shows how to
use @Path variables and the @PathParam annotation in a method:
@Path("/{username}")
public class MyResourceBean {
...
@GET
public String printUsername(@PathParam("username") String userId) {
...
}
}
In the preceding snippet, the URI path template variable name username is specified as
a parameter to the printUsername method. The @PathParam annotation is set to the
variable name username. At runtime, before printUsername is called, the value of
username is extracted from the URI and cast to a String. The resulting String is then
available to the method as the userId variable.
If the URI path template variable cannot be cast to the specified type, the JAX-RS
runtime returns an HTTP 400 ("Bad Request") error to the client. If the @PathParam
annotation cannot be cast to the specified type, the JAX-RS runtime returns an HTTP
404 ("Not Found") error to the client.
The @PathParam parameter and the other parameter-based annotations (@MatrixParam,
@HeaderParam, @CookieParam, and @FormParam) obey the same rules as @QueryParam.
Cookie parameters, indicated by decorating the parameter with
javax.ws.rs.CookieParam, extract information from the cookies declared in
cookie-related HTTP headers. Header parameters, indicated by decorating the
parameter with javax.ws.rs.HeaderParam, extract information from the HTTP
headers. Matrix parameters, indicated by decorating the parameter with
javax.ws.rs.MatrixParam, extract information from URL path segments.
Form parameters, indicated by decorating the parameter with
javax.ws.rs.FormParam, extract information from a request representation that is of
the MIME media type application/x-www-form-urlencoded and conforms to the
encoding specified by HTML forms, as described in
http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1. This
parameter is very useful for extracting information sent by POST in HTML forms.
The following example extracts the name form parameter from the POST form data:
@POST
@Consumes("application/x-www-form-urlencoded")
public void post(@FormParam("name") String name) {
// Store the message
}
To obtain a general map of parameter names and values for query and path
parameters, use the following code:
Building RESTful Web Services with JAX-RS 29-13
Creating a RESTful Root Resource Class
@GET
public String get(@Context UriInfo ui) {
MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
MultivaluedMap<String, String> pathParams = ui.getPathParameters();
}
The following method extracts header and cookie parameter names and values into a
map:
@GET
public String get(@Context HttpHeaders hh) {
MultivaluedMap<String, String> headerParams = hh.getRequestHeaders();
Map<String, Cookie> pathParams = hh.getCookies();
}
In general, @Context can be used to obtain contextual Java types related to the request
or response.
For form parameters, it is possible to do the following:
@POST
@Consumes("application/x-www-form-urlencoded")
public void post(MultivaluedMap<String, String> formParams) {
// Store the message
}
29.2.7 Configuring JAX-RS Applications
A JAX-RS application consists of at least one resource class packaged within a WAR
file. The base URI from which an application's resources respond to requests can be set
one of two ways:
■
■
Using the @ApplicationPath annotation in a subclass of
javax.ws.rs.core.Application packaged within the WAR
Using the servlet-mapping tag within the WAR's web.xml deployment descriptor
29.2.7.1 Configuring a JAX-RS Application Using a Subclass of Application
Create a subclass of javax.ws.rs.core.Application to manually configure the
environment in which the REST resources defined in your resource classes are run,
including the base URI. Add a class-level @ApplicationPath annotation to set the base
URI.
@ApplicationPath("/webapi")
public class MyApplication extends Application { ... }
In the preceding example, the base URI is set to /webapi, which means that all
resources defined within the application are relative to /webapi.
By default, all the resources in an archive will be processed for resources. Override the
getClasses method to manually register the resource classes in the application with
the JAX-RS runtime.
@Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>();
// register root resource
classes.add(MyResource.class);
return classes;
}
29-14 The Java EE 7 Tutorial
Example Applications for JAX-RS
29.2.7.2 Configuring the Base URI in web.xml
The base URI for a JAX-RS application can be set using a servlet-mapping tag in the
web.xml deployment descriptor, using the Application class name as the servlet.
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/webapi/*</url-pattern>
</servlet-mapping>
This setting will also override the path set by @ApplicationPath when using an
Application subclass.
<servlet-mapping>
<servlet-name>com.example.rest.MyApplication</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
29.3 Example Applications for JAX-RS
This section provides an introduction to creating, deploying, and running your own
JAX-RS applications. This section demonstrates the steps that are needed to create,
build, deploy, and test a very simple web application that uses JAX-RS annotations.
29.3.1 Creating a Simple RESTful Web Service
This section explains how to use NetBeans IDE to create a RESTful web service using a
Maven archetype. The archetype generates a skeleton for the application, and you
simply need to implement the appropriate method.
You can find a version of this application at tut-install/examples/jaxrs/hello/.
29.3.1.1 To Create a RESTful Web Service Using NetBeans IDE
1.
Ensure you have installed the tutorial archetypes as described in Installing the
Tutorial Archetypes.
2.
In NetBeans IDE, create a simple web application using the
jaxrs-service-archetype Maven archetype. This archetype creates a very simple
"Hello, World" web application.
a.
From the File menu, choose New Project.
b.
From Categories, select Maven. From Projects, select Project From Archetype.
Click Next.
c.
Under Search enter jaxrs-service, select the jaxrs-service-archetype, and
click Next.
d.
Under Project Name enter HelloWorldApplication, set the Project Location,
and set the Package name to javaeetutorial.hello, and click Finish.
The project is created.
3.
In HelloWorld.java, find the getHtml() method. Replace the //TODO comment
with the following text, so that the finished product resembles the following
method:
@GET
@Produces("text/html")
public String getHtml() {
return "<html lang=\"en\"><body><h1>Hello, World!!</body></h1></html>";
}
Building RESTful Web Services with JAX-RS 29-15
Example Applications for JAX-RS
Because the MIME type produced is HTML, you can use
HTML tags in your return statement.
Note:
4.
Right-click the HelloWorldApplication project in the Projects pane and select
Run.
This will build and deploy the application to GlassFish Server.
5.
In a browser, open the following URL:
http://localhost:8080/HelloWorldApplication/HelloWorldApplication
A browser window opens and displays the return value of Hello, World!!
For other sample applications that demonstrate deploying and running JAX-RS
applications using NetBeans IDE, see The rsvp Example Application and Your First
Cup: An Introduction to the Java EE Platform at
http://docs.oracle.com/javaee/7/firstcup/doc/. You may also look at the
tutorials on the NetBeans IDE tutorial site, such as the one titled "Getting Started with
RESTful Web Services" at
https://netbeans.org/kb/docs/websvc/rest.html. This tutorial includes a
section on creating a CRUD application from a database. Create, read, update, and
delete (CRUD) are the four basic functions of persistent storage and relational
databases.
29.3.2 The rsvp Example Application
The rsvp example application, located in the tut-install/examples/jaxrs/rsvp/
directory, allows invitees to an event to indicate whether they will attend. The events,
people invited to the event, and the responses to the invite are stored in a Java DB
database using the Java Persistence API. The JAX-RS resources in rsvp are exposed in
a stateless session enterprise bean.
29.3.2.1 Components of the rsvp Example Application
The three enterprise beans in the rsvp example application are rsvp.ejb.ConfigBean,
rsvp.ejb.StatusBean, and rsvp.ejb.ResponseBean.
ConfigBean is a singleton session bean that initializes the data in the database.
StatusBean exposes a JAX-RS resource for displaying the current status of all invitees
to an event. The URI path template is declared first on the class and then on the
getEvent method:
@Stateless
@Named
@Path("/status")
public class StatusBean {
...
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Path("{eventId}/")
public Event getEvent(@PathParam("eventId") Long eventId) {
...
The combination of the two @Path annotations results in the following URI path
template:
@Path("/status/{eventId}/")
29-16 The Java EE 7 Tutorial
Example Applications for JAX-RS
The URI path variable eventId is a @PathParam variable in the getEvent method,
which responds to HTTP GET requests and has been annotated with @GET. The
eventId variable is used to look up all the current responses in the database for that
particular event.
ResponseBean exposes a JAX-RS resource for setting an invitee's response to a
particular event. The URI path template for ResponseBean is declared as follows:
@Path("/{eventId}/{inviteId}")
Two URI path variables are declared in the path template: eventId and inviteId. As
in StatusBean, eventId is the unique ID for a particular event. Each invitee to that
event has a unique ID for the invitation, and that is the inviteId. Both of these path
variables are used in two JAX-RS methods in ResponseBean: getResponse and
putResponse. The getResponse method responds to HTTP GET requests and displays
the invitee's current response and a form to change the response.
The javaeetutorial.rsvp.rest.RsvpApplication class defines the root application
path for the resources by applying the javax.ws.rs.ApplicationPath annotation at
the class level.
@ApplicationPath("/webapi")
public class RsvpApplication extends Application {
}
An invitee who wants to change his or her response selects the new response and
submits the form data, which is processed as an HTTP POST request by the
putResponse method. The new response is extracted from the HTTP POST request and
stored as the userResponse string. The putResponse method uses userResponse,
eventId, and inviteId to update the invitee's response in the database.
The events, people, and responses in rsvp are encapsulated in Java Persistence API
entities. The rsvp.entity.Event, rsvp.entity.Person, and rsvp.entity.Response
entities respectively represent events, invitees, and responses to an event.
The rsvp.util.ResponseEnum class declares an enumerated type that represents all the
possible response statuses an invitee may have.
The web application also includes two CDI managed beans, StatusManager and
EventManager, which use the JAX-RS Client API to call the resources exposed in
StatusBean and ResponseBean. For information on how the Client API is used in rsvp,
see "The Client API in the rsvp Example Application" on page 30-4.
29.3.2.2 Running the rsvp Example Application
Both NetBeans IDE and Maven can be used to deploy and run the rsvp example
application.
To Run the rsvp Example Application Using NetBeans IDE
1.
If the database server is not already running, start it by following the instructions
in Starting and Stopping the Java DB Server.
2.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
3.
From the File menu, choose Open Project.
4.
In the Open Project dialog box, navigate to:
tut-install/examples/jaxrs
Building RESTful Web Services with JAX-RS 29-17
Example Applications for JAX-RS
5.
Select the rsvp folder.
6.
Click Open Project.
7.
In the Projects tab, right-click the rsvp project and select Run.
The project will be compiled, assembled, and deployed to GlassFish Server. A web
browser window will open to the following URL:
http://localhost:8080/rsvp/index.xhtml
8.
In the web browser window, click the Event status link for the Duke's Birthday
event.
You'll see the current invitees and their responses.
9.
Click the current response of one of the invitees in the Status column of the table,
select a new response, and click Update your status.
The invitee's new status should now be displayed in the table of invitees and their
response statuses.
To Run the rsvp Example Application Using Maven
1.
If the database server is not already running, start it by following the instructions
in Starting and Stopping the Java DB Server.
2.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
3.
In a terminal window, go to:
tut-install/examples/jaxrs/rsvp/
4.
Enter the following command:
mvn install
This command builds, assembles, and deploys rsvp to GlassFish Server.
5.
Open a web browser window to the following URL:
http://localhost:8080/rsvp/
6.
In the web browser window, click the Event status link for the Duke's Birthday
event.
You'll see the current invitees and their responses.
7.
Click the current response of one of the invitees in the Status column of the table,
select a new response, and click Update your status.
The invitee's new status should now be displayed in the table of invitees and their
response statuses.
29.3.3 Real-World Examples
Most blog sites use RESTful web services. These sites involve downloading XML files,
in RSS or Atom format, that contain lists of links to other resources. Other websites
and web applications that use REST-like developer interfaces to data include Twitter
and Amazon S3 (Simple Storage Service). With Amazon S3, buckets and objects can be
created, listed, and retrieved using either a REST-style HTTP interface or a SOAP
interface. The examples that ship with Jersey include a storage service example with a
RESTful interface.
29-18 The Java EE 7 Tutorial
Further Information about JAX-RS
29.4 Further Information about JAX-RS
For more information about RESTful web services and JAX-RS, see
■
"Fielding Dissertation: Chapter 5: Representational State Transfer (REST)":
http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_
style.htm
■
■
RESTful Web Services, by Leonard Richardson and Sam Ruby, available from
O'Reilly Media at
http://shop.oreilly.com/product/9780596529260.do
JSR 339: JAX-RS 2.0: The Java API for RESTful Web Services:
http://jcp.org/en/jsr/detail?id=339
■
Jersey project:
https://jersey.java.net/
Building RESTful Web Services with JAX-RS 29-19
Further Information about JAX-RS
29-20 The Java EE 7 Tutorial
30
Accessing REST Resources with the JAX-RS
Client API
30
This chapter describes the JAX-RS Client API and includes examples of how to access
REST resources using the Java programming language.
JAX-RS provides a client API for accessing REST resources from other Java
applications.
The following topics are addressed here:
■
Overview of the Client API
■
Using the Client API in the JAX-RS Example Applications
■
Advanced Features of the Client API
30.1 Overview of the Client API
The JAX-RS Client API provides a high-level API for accessing any REST resources,
not just JAX-RS services. The Client API is defined in the javax.ws.rs.client
package.
30.1.1 Creating a Basic Client Request Using the Client API
The following steps are needed to access a REST resource using the Client API.
1.
Obtain an instance of the javax.ws.rs.client.Client interface.
2.
Configure the Client instance with a target.
3.
Create a request based on the target.
4.
Invoke the request.
The Client API is designed to be fluent, with method invocations chained together to
configure and submit a request to a REST resource in only a few lines of code.
Client client = ClientBuilder.newClient();
String name = client.target("http://example.com/webapi/hello")
.request(MediaType.TEXT_PLAIN)
.get(String.class);
In this example, the client instance is first created by calling the
javax.ws.rs.client.ClientBuilder.newClient method. Then, the request is
configured and invoked by chaining method calls together in one line of code. The
Client.target method sets the target based on a URI. The
javax.ws.rs.client.WebTarget.request method sets the media type for the returned
Accessing REST Resources with the JAX-RS Client API 30-1
Overview of the Client API
entity. The javax.ws.rs.client.Invocation.Builder.get method invokes the service
using an HTTP GET request, setting the type of the returned entity to String.
30.1.1.1 Obtaining the Client Instance
The Client interface defines the actions and infrastructure a REST client requires to
consume a RESTful web service. Instances of Client are obtained by calling the
ClientBuilder.newClient method.
Client client = ClientBuilder.newClient();
Use the close method to close Client instances after all the invocations for the target
resource have been performed:
Client client = ClientBuilder.newClient();
...
client.close();
Client instances are heavyweight objects. For performance reasons, limit the number
of Client instances in your application, as the initialization and destruction of these
instances may be expensive in your runtime environment.
30.1.1.2 Setting the Client Target
The target of a client, the REST resource at a particular URI, is represented by an
instance of the javax.ws.rs.client.WebTarget interface. You obtain a WebTarget
instance by calling the Client.target method and passing in the URI of the target
REST resource.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi");
For complex REST resources, it may be beneficial to create several instances of
WebTarget. In the following example, a base target is used to construct several other
targets that represent different services provided by a REST resource.
Client client = ClientBuilder.newClient();
WebTarget base = client.target("http://example.com/webapi");
// WebTarget at http://example.com/webapi/read
WebTarget read = base.path("read");
// WebTarget at http://example.com/webapi/write
WebTarget write = base.path("write");
The WebTarget.path method creates a new WebTarget instance by appending the
current target URI with the path that was passed in.
30.1.1.3 Setting Path Parameters in Targets
Path parameters in client requests can be specified as URI template parameters, similar
to the template parameters used when defining a resource URI in a JAX-RS service.
Template parameters are specified by surrounding the template variable with braces
({}). Call the resolveTemplate method to substitute the {username}, and then call the
queryParam method to add another variable to pass.
WebTarget myResource = client.target("http://example.com/webapi/read")
.path("{userName}")
.resolveTemplate("userName", "janedoe")
.queryParam("chapter", "1");
// http://example.com/webapi/read/janedoe?chapter=1
30-2 The Java EE 7 Tutorial
Overview of the Client API
Response response = myResource.request(...)
.get();
30.1.1.4 Invoking the Request
After setting and applying any configuration options to the target, call one of the
WebTarget.request methods to begin creating the request. This is usually
accomplished by passing to WebTarget.request the accepted media response type for
the request either as a string of the MIME type or using one of the constants in
javax.ws.rs.core.MediaType. The WebTarget.request method returns an instance of
javax.ws.rs.client.Invocation.Builder, a helper object that provides methods for
preparing the client request.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
Invocation.Builder builder = myResource.request(MediaType.TEXT_PLAIN);
Using a MediaType constant is equivalent to using the string defining the MIME type.
Invocation.Builder builder = myResource.request("text/plain");
After setting the media type, invoke the request by calling one of the methods of the
Invocation.Builder instance that corresponds to the type of HTTP request the target
REST resource expects. These methods are:
■
get()
■
post()
■
delete()
■
put()
■
head()
■
options()
For example, if the target REST resource is for an HTTP GET request, call the
Invocation.Builder.get method. The return type should correspond to the entity
returned by the target REST resource.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
String response = myResource.request(MediaType.TEXT_PLAIN)
.get(String.class);
If the target REST resource is expecting an HTTP POST request, call the
Invocation.Builder.post method.
Client client = ClientBuilder.newClient();
StoreOrder order = new StoreOrder(...);
WebTarget myResource = client.target("http://example.com/webapi/write");
TrackingNumber trackingNumber = myResource.request(MediaType.APPLICATION_XML)
.post(Entity.xml(order), TrackingNumber.class);
In the preceding example, the return type is a custom class and is retrieved by setting
the type in the Invocation.Builder.post(Entity<?> entity, Class<T>
responseType) method as a parameter.
If the return type is a collection, use javax.ws.rs.core.GenericType<T> as the
response type parameter, where T is the collection type:
List<StoreOrder> orders = client.target("http://example.com/webapi/read")
Accessing REST Resources with the JAX-RS Client API 30-3
Using the Client API in the JAX-RS Example Applications
.path("allOrders")
.request(MediaType.APPLICATION_XML)
.get(new GenericType<List<StoreOrder>>() {});
This preceding example shows how methods are chained together in the Client API to
simplify how requests are configured and invoked.
30.2 Using the Client API in the JAX-RS Example Applications
The rsvp and customer examples use the Client API to call JAX-RS services. This
section describes how each example application uses the Client API.
30.2.1 The Client API in the rsvp Example Application
The rsvp application allows users to respond to event invitations using JAX-RS
resources, as explained in Chapter 29.3.2, "The rsvp Example Application". The web
application uses the Client API in CDI backing beans to interact with the service
resources, and the Facelets web interface displays the results.
The StatusManager CDI backing bean retrieves all the current events in the system.
The client instance used in the backing bean is obtained in the constructor:
public StatusManager() {
this.client = ClientBuilder.newClient();
}
The StatusManager.getEvents method returns a collection of all the current events in
the system by calling the resource at
http://localhost:8080/rsvp/webapi/status/all, which returns an XML document
with entries for each event. The Client API automatically unmarshals the XML and
creates a List<Event> instance.
public List<Event> getEvents() {
List<Event> returnedEvents = null;
try {
returnedEvents = client.target(baseUri)
.path("all")
.request(MediaType.APPLICATION_XML)
.get(new GenericType<List<Event>>() {
});
if (returnedEvents == null) {
logger.log(Level.SEVERE, "Returned events null.");
} else {
logger.log(Level.INFO, "Events have been returned.");
}
} catch (WebApplicationException ex) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
...
return returnedEvents;
}
The StatusManager.changeStatus method is used to update the attendee's response.
It creates an HTTP POST request to the service with the new response. The body of the
request is an XML document.
public String changeStatus(ResponseEnum userResponse,
Person person, Event event) {
String navigation;
try {
30-4 The Java EE 7 Tutorial
Using the Client API in the JAX-RS Example Applications
logger.log(Level.INFO,
"changing status to {0} for {1} {2} for event ID {3}.",
new Object[]{userResponse,
person.getFirstName(),
person.getLastName(),
event.getId().toString()});
client.target(baseUri)
.path(event.getId().toString())
.path(person.getId().toString())
.request(MediaType.APPLICATION_XML)
.post(Entity.xml(userResponse.getLabel()));
navigation = "changedStatus";
} catch (ResponseProcessingException ex) {
logger.log(Level.WARNING, "couldn''t change status for {0} {1}",
new Object[]{person.getFirstName(),
person.getLastName()});
logger.log(Level.WARNING, ex.getMessage());
navigation = "error";
}
return navigation;
}
30.2.2 The Client API in the customer Example Application
The customer example application stores customer data in a database and exposes the
resource as XML, as explained in Chapter 31.8, "The customer Example Application".
The service resource exposes methods that create customers and retrieve all the
customers. A Facelets web application acts as a client for the service resource, with a
form for creating customers and displaying the list of customers in a table.
The CustomerBean stateless session bean uses the JAX-RS Client API to interface with
the service resource. The CustomerBean.createCustomer method takes the Customer
entity instance created by the Facelets form and makes a POST call to the service URI.
public String createCustomer(Customer customer) {
if (customer == null) {
logger.log(Level.WARNING, "customer is null.");
return "customerError";
}
String navigation;
Response response =
client.target("http://localhost:8080/customer/webapi/Customer")
.request(MediaType.APPLICATION_XML)
.post(Entity.entity(customer, MediaType.APPLICATION_XML),
Response.class);
if (response.getStatus() == Status.CREATED.getStatusCode()) {
navigation = "customerCreated";
} else {
logger.log(Level.WARNING,
"couldn''t create customer with id {0}. Status returned was {1}",
new Object[]{customer.getId(), response.getStatus()});
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null,
new FacesMessage("Could not create customer."));
navigation = "customerError";
}
return navigation;
}
Accessing REST Resources with the JAX-RS Client API 30-5
Advanced Features of the Client API
The XML request entity is created by calling the Invocation.Builder.post method,
passing in a new Entity instance from the Customer instance, and specifying the
media type as MediaType.APPLICATION_XML.
The CustomerBean.retrieveCustomer method retrieves a Customer entity instance
from the service by appending the customer's ID to the service URI.
public String retrieveCustomer(String id) {
String navigation;
Customer customer =
client.target("http://localhost:8080/customer/webapi/Customer")
.path(id)
.request(MediaType.APPLICATION_XML)
.get(Customer.class);
if (customer == null) {
navigation = "customerError";
} else {
navigation = "customerRetrieved";
}
return navigation;
}
The CustomerBean.retrieveAllCustomers method retrieves a collection of customers
as a List<Customer> instance. This list is then displayed as a table in the Facelets web
application.
public List<Customer> retrieveAllCustomers() {
List<Customer> customers =
client.target("http://localhost:8080/customer/webapi/Customer")
.path("all")
.request(MediaType.APPLICATION_XML)
.get(new GenericType<List<Customer>>() {
});
return customers;
}
Because the response type is a collection, the Invocation.Builder.get method is
called by passing in a new instance of GenericType<List<Customer>>.
30.3 Advanced Features of the Client API
This section describes some of the advanced features of the JAX-RS Client API.
30.3.1 Configuring the Client Request
Additional configuration options may be added to the client request after it is created
but before it is invoked.
30.3.1.1 Setting Message Headers in the Client Request
You can set HTTP headers on the request by calling the Invocation.Builder.header
method.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
String response = myResource.request(MediaType.TEXT_PLAIN)
.header("myHeader", "The header value")
.get(String.class);
30-6 The Java EE 7 Tutorial
Advanced Features of the Client API
If you need to set multiple headers on the request, call the
Invocation.Builder.headers method and pass in a
javax.ws.rs.core.MultivaluedMap instance with the name-value pairs of the HTTP
headers. Calling the headers method replaces all the existing headers with the headers
supplied in the MultivaluedMap instance.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
MultivaluedMap<String, Object> myHeaders =
new MultivaluedMap<>("myHeader", "The header value");
myHeaders.add(...);
String response = myResource.request(MediaType.TEXT_PLAIN)
.headers(myHeaders)
.get(String.class);
The MultivaluedMap interface allows you to specify multiple values for a given key.
MultivaluedMap<String, Object> myHeaders =
new MultivaluedMap<String, Object>();
List<String> values = new ArrayList<>();
values.add(...)
myHeaders.add("myHeader", values
30.3.1.2 Setting Cookies in the Client Request
You can add HTTP cookies to the request by calling the Invocation.Builder.cookie
method, which takes a name-value pair as parameters.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
String response = myResource.request(MediaType.TEXT_PLAIN)
.cookie("myCookie", "The cookie value")
.get(String.class);
The javax.ws.rs.core.Cookie class encapsulates the attributes of an HTTP cookie,
including the name, value, path, domain, and RFC specification version of the cookie.
In the following example, the Cookie object is configured with a name-value pair, a
path, and a domain.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
Cookie myCookie = new Cookie("myCookie", "The cookie value",
"/webapi/read", "example.com");
String response = myResource.request(MediaType.TEXT_PLAIN)
.cookie(myCookie)
.get(String.class);
30.3.1.3 Adding Filters to the Client
You can register custom filters with the client request or the response received from the
target resource. To register filter classes when the Client instance is created, call the
Client.register method.
Client client = ClientBuilder.newClient().register(MyLoggingFilter.class);
In the preceding example, all invocations that use this Client instance have the
MyLoggingFilter filter registered with them.
You can also register the filter classes on the target by calling WebTarget.register.
Client client = ClientBuilder.newClient().register(MyLoggingFilter.class);
WebTarget target = client.target("http://example.com/webapi/secure")
Accessing REST Resources with the JAX-RS Client API 30-7
Advanced Features of the Client API
.register(MyAuthenticationFilter.class);
In the preceding example, both the MyLoggingFilter and MyAuthenticationFilter
filters are attached to the invocation.
Request and response filter classes implement the
javax.ws.rs.client.ClientRequestFilter and
javax.ws.rs.client.ClientResponseFilter interfaces, respectively. Both of these
interfaces define a single method, filter. All filters must be annotated with
javax.ws.rs.ext.Provider.
The following class is a logging filter for both client requests and client responses.
@Provider
public class MyLoggingFilter implements ClientRequestFilter,
ClientResponseFilter {
static final Logger logger = Logger.getLogger(...);
// implement the ClientRequestFilter.filter method
@Override
public void filter(ClientRequestContext requestContext)
throws IOException {
logger.log(...);
...
}
// implement the ClientResponseFilter.filter method
@Override
public void filter(ClientRequestContext requestContext,
ClientResponseContext responseContext) throws IOException {
logger.log(...);
...
}
}
If the invocation must be stopped while the filter is active, call the context object's
abortWith method, and pass in a javax.ws.rs.core.Response instance from within
the filter.
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
...
Response response = new Response();
response.status(500);
requestContext.abortWith(response);
}
30.3.2 Asynchronous Invocations in the Client API
In networked applications, network issues can affect the perceived performance of the
application, particularly in long-running or complicated network calls. Asynchronous
processing helps prevent blocking and makes better use of an application's resources.
In the JAX-RS Client API, the Invocation.Builder.async method is used when
constructing a client request to indicate that the call to the service should be performed
asynchronously. An asynchronous invocation returns control to the caller immediately,
with a return type of java.util.concurrent.Future<T> (part of the Java SE
concurrency API) and with the type set to the return type of the service call. Future<T>
objects have methods to check if the asynchronous call has been completed, to retrieve
30-8 The Java EE 7 Tutorial
Advanced Features of the Client API
the final result, to cancel the invocation, and to check if the invocation has been
cancelled.
The following example shows how to invoke an asynchronous request on a resource.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
Future<String> response = myResource.request(MediaType.TEXT_PLAIN)
.async()
.get(String.class);
30.3.2.1 Using Custom Callbacks in Asynchronous Invocations
The InvocationCallback interface defines two methods, completed and failed, that
are called when an asynchronous invocation either completes successfully or fails,
respectively. You may register an InvocationCallback instance on your request by
creating a new instance when specifying the request method.
The following example shows how to register a callback object on an asynchronous
invocation.
Client client = ClientBuilder.newClient();
WebTarget myResource = client.target("http://example.com/webapi/read");
Future<Customer> fCustomer = myResource.request(MediaType.TEXT_PLAIN)
.async()
.get(new InvocationCallback<Customer>() {
@Override
public void completed(Customer customer) {
// Do something with the customer object
}
@Override
public void failed(Throwable throwable) {
// handle the error
}
});
Accessing REST Resources with the JAX-RS Client API 30-9
Advanced Features of the Client API
30-10 The Java EE 7 Tutorial
31
JAX-RS: Advanced Topics and an Example
31
The Java API for RESTful Web Services (JAX-RS, defined in JSR 339) is designed to
make it easy to develop applications that use the REST architecture. This chapter
describes advanced features of JAX-RS. If you are new to JAX-RS, see Chapter 29,
"Building RESTful Web Services with JAX-RS" before you proceed with this chapter.
JAX-RS is integrated with Contexts and Dependency Injection for Java EE (CDI),
Enterprise JavaBeans (EJB) technology, and Java Servlet technology.
The following topics are addressed here:
■
Annotations for Field and Bean Properties of Resource Classes
■
Validating Resource Data with Bean Validation
■
Subresources and Runtime Resource Resolution
■
Integrating JAX-RS with EJB Technology and CDI
■
Conditional HTTP Requests
■
Runtime Content Negotiation
■
Using JAX-RS with JAXB
■
The customer Example Application
31.1 Annotations for Field and Bean Properties of Resource Classes
JAX-RS annotations for resource classes let you extract specific parts or values from a
Uniform Resource Identifier (URI) or request header.
JAX-RS provides the annotations listed in Table 31–1.
Table 31–1
Advanced JAX-RS Annotations
Annotation
Description
@Context
Injects information into a class field, bean property, or method parameter
@CookieParam
Extracts information from cookies declared in the cookie request header
@FormParam
Extracts information from a request representation whose content type is
application/x-www-form-urlencoded
@HeaderParam
Extracts the value of a header
@MatrixParam
Extracts the value of a URI matrix parameter
@PathParam
Extracts the value of a URI template parameter
@QueryParam
Extracts the value of a URI query parameter
JAX-RS: Advanced Topics and an Example
31-1
Annotations for Field and Bean Properties of Resource Classes
31.1.1 Extracting Path Parameters
URI path templates are URIs with variables embedded within the URI syntax. The
@PathParam annotation lets you use variable URI path fragments when you call a
method.
The following code snippet shows how to extract the last name of an employee when
the employee's email address is provided:
@Path("/employees/{firstname}.{lastname}@{domain}.com")
public class EmpResource {
@GET
@Produces("text/xml")
public String getEmployeelastname(@PathParam("lastname") String lastName) {
...
}
}
In this example, the @Path annotation defines the URI variables (or path parameters)
{firstname}, {lastname}, and {domain}. The @PathParam in the method parameter of
the request method extracts the last name from the email address.
If your HTTP request is GET /employees/john.doe@example.com, the value "doe" is
injected into {lastname}.
You can specify several path parameters in one URI.
You can declare a regular expression with a URI variable. For example, if it is required
that the last name must consist only of lowercase and uppercase characters, you can
declare the following regular expression:
@Path("/employees/{firstname}.{lastname[a-zA-Z]*}@{domain}.com")
If the last name does not match the regular expression, a 404 response is returned.
31.1.2 Extracting Query Parameters
Use the @QueryParam annotation to extract query parameters from the query
component of the request URI.
For instance, to query all employees who have joined within a specific range of years,
use a method signature like the following:
@Path("/employees/")
@GET
public Response getEmployees(
@DefaultValue("2003") @QueryParam("minyear") int minyear,
@DefaultValue("2013") @QueryParam("maxyear") int maxyear)
{...}
This code snippet defines two query parameters, minyear and maxyear. The following
HTTP request would query for all employees who have joined between 2003 and 2013:
GET /employees?maxyear=2013&minyear=2003
The @DefaultValue annotation defines a default value, which is to be used if no values
are provided for the query parameters. By default, JAX-RS assigns a null value for
Object values and zero for primitive data types. You can use the @DefaultValue
annotation to eliminate null or zero values and define your own default values for a
parameter.
31-2 The Java EE 7 Tutorial
Annotations for Field and Bean Properties of Resource Classes
31.1.3 Extracting Form Data
Use the @FormParam annotation to extract form parameters from HTML forms. For
example, the following form accepts the name, address, and manager's name of an
employee:
<FORM action="http://example.com/employees/" method="post">
<p>
<fieldset>
Employee name: <INPUT type="text" name="empname" tabindex="1">
Employee address: <INPUT type="text" name="empaddress" tabindex="2">
Manager name: <INPUT type="text" name="managername" tabindex="3">
</fieldset>
</p>
</FORM>
Use the following code snippet to extract the manager name from this HTML form:
@POST
@Consumes("application/x-www-form-urlencoded")
public void post(@FormParam("managername") String managername) {
// Store the value
...
}
To obtain a map of form parameter names to values, use a code snippet like the
following:
@POST
@Consumes("application/x-www-form-urlencoded")
public void post(MultivaluedMap<String, String> formParams) {
// Store the message
}
31.1.4 Extracting the Java Type of a Request or Response
The javax.ws.rs.core.Context annotation retrieves the Java types related to a
request or response.
The javax.ws.rs.core.UriInfo interface provides information about the components
of a request URI. The following code snippet shows how to obtain a map of query and
path parameter names to values:
@GET
public String getParams(@Context UriInfo ui) {
MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
MultivaluedMap<String, String> pathParams = ui.getPathParameters();
}
The javax.ws.rs.core.HttpHeaders interface provides information about request
headers and cookies. The following code snippet shows how to obtain a map of header
and cookie parameter names to values:
@GET
public String getHeaders(@Context HttpHeaders hh) {
MultivaluedMap<String, String> headerParams = hh.getRequestHeaders();
MultivaluedMap<String, Cookie> pathParams = hh.getCookies();
}
JAX-RS: Advanced Topics and an Example
31-3
Validating Resource Data with Bean Validation
31.2 Validating Resource Data with Bean Validation
JAX-RS supports the Bean Validation to verify JAX-RS resource classes. This support
consists of:
■
Adding constraint annotations to resource method parameters
■
Ensuring entity data is valid when the entity is passed in as a parameter
31.2.1 Using Constraint Annotations on Resource Methods
Bean Validation constraint annotations may be applied to parameters for a resource.
The server will validate the parameters and either pass or throw a
javax.validation.ValidationException.
@POST
@Path("/createUser")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void createUser(@NotNull @FormParam("username") String username,
@NotNull @FormParam("firstName") String firstName,
@NotNull @FormParam("lastName") String lastName,
@Email @FormParam("email") String email) {
...
}
In the preceding example, the built-in constraint @NotNull is applied to the username,
firstName, and lastName form fields. The user-defined @Email constraint validates
that the email address supplied by the email form field is correctly formatted.
The constraints may also be applied to fields within a resource class.
@Path("/createUser")
public class CreateUserResource {
@NotNull
@FormParam("username")
private String username;
@NotNull
@FormParam("firstName")
private String firstName;
@NotNull
@FormParam("lastName")
private String lastName;
@Email
@FormParam("email")
private String email;
...
}
In the preceding example, the same constraints that were applied to the method
parameters in the previous example are applied to the class fields. The behavior is the
same in both examples.
Constraints may also be applied to a resource class's JavaBeans properties by adding
the constraint annotations to the getter method.
@Path("/createuser")
public class CreateUserResource {
private String username;
31-4 The Java EE 7 Tutorial
Validating Resource Data with Bean Validation
@FormParam("username")
public void setUsername(String username) {
this.username = username;
}
@NotNull
public String getUsername() {
return username;
}
...
}
Constraints may also be applied at the resource class level. In the following example,
@PhoneRequired is a user-defined constraint that ensures that a user enters at least one
phone number. That is, either homePhone or mobilePhone can be null, but not both.
@Path("/createUser")
@PhoneRequired
public class CreateUserResource {
@FormParam("homePhone")
private Phone homePhone;
@FormParam("mobilePhone")
private Phone mobilePhone;
...
}
31.2.2 Validating Entity Data
Classes that contain validation constraint annotations may be used in method
parameters in a resource class. To validate these entity classes, use the @Valid
annotation on the method parameter. For example, the following class is a
user-defined class containing both standard and user-defined validation constraints.
@PhoneRequired
public class User {
@NotNull
private String username;
private Phone homePhone;
private Phone mobilePhone;
...
}
This entity class is used as a parameter to a resource method.
@Path("/createUser")
public class CreateUserResource {
...
@POST
@Consumers(MediaType.APPLICATION_XML)
public void createUser(@Valid User user) {
...
}
...
}
JAX-RS: Advanced Topics and an Example
31-5
Subresources and Runtime Resource Resolution
The @Valid annotation ensures that the entity class is validated at runtime. Additional
user-defined constraints can also trigger validation of an entity.
@Path("/createUser")
public class CreateUserResource {
...
@POST
@Consumers(MediaType.APPLICATION_XML)
public void createUser(@ActiveUser User user) {
...
}
...
}
In the preceding example, the user-defined @ActiveUser constraint is applied to the
User class in addition to the @PhoneRequired and @NotNull constraints defined within
the entity class.
If a resource method returns an entity class, validation may be triggered by applying
the @Valid or any other user-defined constraint annotation to the resource method.
@Path("/getUser")
public class GetUserResource {
...
@GET
@Path("{username}")
@Produces(MediaType.APPLICATION_XML)
@ActiveUser
@Valid
public User getUser(@PathParam("username") String username) {
// find the User
return user;
}
...
}
As in the previous example, the @ActiveUser constraint is applied to the returned
entity class as well as the @PhoneRequired and @NotNull constraints defined within the
entity class.
31.2.3 Validation Exception Handling and Response Codes
If a javax.validation.ValidationException or any subclass of ValidationException
except ConstraintValidationException is thrown, the JAX-RS runtime will respond
to the client request with a 500 (Internal Server Error) HTTP status code.
If a ConstraintValidationException is thrown, the JAX-RS runtime will respond to
the client with one of the following HTTP status codes:
■
■
500 (Internal Server Error) if the exception was thrown while validating a method
return type
400 (Bad Request) in all other cases
31.3 Subresources and Runtime Resource Resolution
You can use a resource class to process only a part of the URI request. A root resource
can then implement subresources that can process the remainder of the URI path.
A resource class method that is annotated with @Path is either a subresource method
or a subresource locator.
31-6 The Java EE 7 Tutorial
Subresources and Runtime Resource Resolution
■
■
A subresource method is used to handle requests on a subresource of the
corresponding resource.
A subresource locator is used to locate subresources of the corresponding resource.
31.3.1 Subresource Methods
A subresource method handles an HTTP request directly. The method must be
annotated with a request method designator, such as @GET or @POST, in addition to
@Path. The method is invoked for request URIs that match a URI template created by
concatenating the URI template of the resource class with the URI template of the
method.
The following code snippet shows how a subresource method can be used to extract
the last name of an employee when the employee's email address is provided:
@Path("/employeeinfo")
public class EmployeeInfo {
public employeeinfo() {}
@GET
@Path("/employees/{firstname}.{lastname}@{domain}.com")
@Produces("text/xml")
public String getEmployeeLastName(@PathParam("lastname") String lastName) {
...
}
}
The getEmployeeLastName method returns doe for the following GET request:
GET /employeeinfo/employees/john.doe@example.com
31.3.2 Subresource Locators
A subresource locator returns an object that will handle an HTTP request. The method
must not be annotated with a request method designator. You must declare a
subresource locator within a subresource class, and only subresource locators are used
for runtime resource resolution.
The following code snippet shows a subresource locator:
// Root resource class
@Path("/employeeinfo")
public class EmployeeInfo {
// Subresource locator: obtains the subresource Employee
// from the path /employeeinfo/employees/{empid}
@Path("/employees/{empid}")
public Employee getEmployee(@PathParam("empid") String id) {
// Find the Employee based on the id path parameter
Employee emp = ...;
...
return emp;
}
}
// Subresource class
public class Employee {
// Subresource method: returns the employee's last name
JAX-RS: Advanced Topics and an Example
31-7
Integrating JAX-RS with EJB Technology and CDI
@GET
@Path("/lastname")
public String getEmployeeLastName() {
...
return lastName;
}
}
In this code snippet, the getEmployee method is the subresource locator that provides
the Employee object, which services requests for lastname.
If your HTTP request is GET /employeeinfo/employees/as209/, the getEmployee
method returns an Employee object whose id is as209. At runtime, JAX-RS sends a GET
/employeeinfo/employees/as209/lastname request to the getEmployeeLastName
method. The getEmployeeLastName method retrieves and returns the last name of the
employee whose id is as209.
31.4 Integrating JAX-RS with EJB Technology and CDI
JAX-RS works with Enterprise JavaBeans technology (enterprise beans) and Contexts
and Dependency Injection for Java EE (CDI).
In general, for JAX-RS to work with enterprise beans, you need to annotate the class of
a bean with @Path to convert it to a root resource class. You can use the @Path
annotation with stateless session beans and singleton POJO beans.
The following code snippet shows a stateless session bean and a singleton bean that
have been converted to JAX-RS root resource classes.
@Stateless
@Path("stateless-bean")
public class StatelessResource {...}
@Singleton
@Path("singleton-bean")
public class SingletonResource {...}
Session beans can also be used for subresources.
JAX-RS and CDI have slightly different component models. By default, JAX-RS root
resource classes are managed in the request scope, and no annotations are required for
specifying the scope. CDI managed beans annotated with @RequestScoped or
@ApplicationScoped can be converted to JAX-RS resource classes.
The following code snippet shows a JAX-RS resource class.
@Path("/employee/{id}")
public class Employee {
public Employee(@PathParam("id") String id) {...}
}
@Path("{lastname}")
public final class EmpDetails {...}
The following code snippet shows this JAX-RS resource class converted to a CDI bean.
The beans must be proxyable, so the Employee class requires a nonprivate constructor
with no parameters, and the EmpDetails class must not be final.
@Path("/employee/{id}")
@RequestScoped
public class Employee {
31-8 The Java EE 7 Tutorial
Runtime Content Negotiation
public Employee() {...}
@Inject
public Employee(@PathParam("id") String id) {...}
}
@Path("{lastname}")
@RequestScoped
public class EmpDetails {...}
31.5 Conditional HTTP Requests
JAX-RS provides support for conditional GET and PUT HTTP requests. Conditional GET
requests help save bandwidth by improving the efficiency of client processing.
A GET request can return a Not Modified (304) response if the representation has not
changed since the previous request. For example, a website can return 304 responses
for all its static images that have not changed since the previous request.
A PUT request can return a Precondition Failed (412) response if the representation has
been modified since the last request. The conditional PUT can help avoid the lost
update problem.
Conditional HTTP requests can be used with the Last-Modified and ETag headers.
The Last-Modified header can represent dates with granularity of one second.
@Path("/employee/{joiningdate}")
public class Employee {
Date joiningdate;
@GET
@Produces("application/xml")
public Employee(@PathParam("joiningdate") Date joiningdate,
@Context Request req,
@Context UriInfo ui) {
this.joiningdate = joiningdate;
...
this.tag = computeEntityTag(ui.getRequestUri());
if (req.getMethod().equals("GET")) {
Response.ResponseBuilder rb = req.evaluatePreconditions(tag);
if (rb != null) {
throw new WebApplicationException(rb.build());
}
}
}
}
In this code snippet, the constructor of the Employee class computes the entity tag from
the request URI and calls the request.evaluatePreconditions method with that tag.
If a client request returns an If-none-match header with a value that has the same
entity tag that was computed, evaluate.Preconditions returns a pre-filled-out
response with a 304 status code and an entity tag set that may be built and returned.
31.6 Runtime Content Negotiation
The @Produces and @Consumes annotations handle static content negotiation in
JAX-RS. These annotations specify the content preferences of the server. HTTP headers
JAX-RS: Advanced Topics and an Example
31-9
Runtime Content Negotiation
such as Accept, Content-Type, and Accept-Language define the content negotiation
preferences of the client.
For more details on the HTTP headers for content negotiation, see HTTP /1.1 Content Negotiation
(http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html).
The following code snippet shows the server content preferences:
@Produces("text/plain")
@Path("/employee")
public class Employee {
@GET
public String getEmployeeAddressText(String address) {...}
@Produces("text/xml")
@GET
public String getEmployeeAddressXml(Address address) {...}
}
The getEmployeeAddressText method is called for an HTTP request that looks like the
following:
GET /employee
Accept: text/plain
This will produce the following response:
500 Oracle Parkway, Redwood Shores, CA
The getEmployeeAddressXml method is called for an HTTP request that looks like the
following:
GET /employee
Accept: text/xml
This will produce the following response:
<address street="500 Oracle Parkway, Redwood Shores, CA" country="USA"/>
With static content negotiation, you can also define multiple content and media types
for the client and server.
@Produces("text/plain", "text/xml")
In addition to supporting static content negotiation, JAX-RS also supports runtime
content negotiation using the javax.ws.rs.core.Variant class and Request objects.
The Variant class specifies the resource representation of content negotiation. Each
instance of the Variant class may contain a media type, a language, and an encoding.
The Variant object defines the resource representation that is supported by the server.
The Variant.VariantListBuilder class is used to build a list of representation
variants.
The following code snippet shows how to create a list of resource representation
variants:
List<Variant> vs = Variant.mediatypes("application/xml", "application/json")
.languages("en", "fr").build();
This code snippet calls the build method of the VariantListBuilder class. The
VariantListBuilder class is invoked when you call the mediatypes, languages, or
31-10 The Java EE 7 Tutorial
Using JAX-RS with JAXB
encodings methods. The build method builds a series of resource representations. The
Variant list created by the build method has all possible combinations of items
specified in the mediatypes, languages, and encodings methods.
In this example, the size of the vs object as defined in this code snippet is 4, and the
contents are as follows:
[["application/xml","en"], ["application/json","en"],
["application/xml","fr"],["application/json","fr"]]
The javax.ws.rs.core.Request.selectVariant method accepts a list of Variant
objects and chooses the Variant object that matches the HTTP request. This method
compares its list of Variant objects with the Accept, Accept-Encoding,
Accept-Language, and Accept-Charset headers of the HTTP request.
The following code snippet shows how to use the selectVariant method to select the
most acceptable Variant from the values in the client request:
@GET
public Response get(@Context Request r) {
List<Variant> vs = ...;
Variant v = r.selectVariant(vs);
if (v == null) {
return Response.notAcceptable(vs).build();
} else {
Object rep = selectRepresentation(v);
return Response.ok(rep, v);
}
}
The selectVariant method returns the Variant object that matches the request or null
if no matches are found. In this code snippet, if the method returns null, a Response
object for a nonacceptable response is built. Otherwise, a Response object with an OK
status and containing a representation in the form of an Object entity and a Variant is
returned.
31.7 Using JAX-RS with JAXB
Java Architecture for XML Binding (JAXB) is an XML-to-Java binding technology that
simplifies the development of web services by enabling transformations between
schema and Java objects and between XML instance documents and Java object
instances. An XML schema defines the data elements and structure of an XML
document. You can use JAXB APIs and tools to establish mappings between Java
classes and XML schema. JAXB technology provides the tools that enable you to
convert your XML documents to and from Java objects.
By using JAXB, you can manipulate data objects in the following ways.
■
■
■
You can start with an XML schema definition (XSD) and use xjc, the JAXB schema
compiler tool, to create a set of JAXB-annotated Java classes that map to the
elements and types defined in the XSD schema.
You can start with a set of Java classes and use schemagen, the JAXB schema
generator tool, to generate an XML schema.
Once a mapping between the XML schema and the Java classes exists, you can use
the JAXB binding runtime to marshal and unmarshal your XML documents to and
from Java objects and use the resulting Java classes to assemble a web services
application.
JAX-RS: Advanced Topics and an Example 31-11
Using JAX-RS with JAXB
XML is a common media format that RESTful services consume and produce. To
deserialize and serialize XML, you can represent requests and responses by JAXB
annotated objects. Your JAX-RS application can use the JAXB objects to manipulate
XML data. JAXB objects can be used as request entity parameters and response
entities. The JAX-RS runtime environment includes standard MessageBodyReader and
MessageBodyWriter provider interfaces for reading and writing JAXB objects as
entities.
With JAX-RS, you enable access to your services by publishing resources. Resources
are just simple Java classes with some additional JAX-RS annotations. These
annotations express the following:
■
■
■
The path of the resource (the URL you use to access it)
The HTTP method you use to call a certain method (for example, the GET or POST
method)
The MIME type with which a method accepts or responds
As you define the resources for your application, consider the type of data you want to
expose. You may already have a relational database that contains information you
want to expose to users, or you may have static content that does not reside in a
database but does need to be distributed as resources. Using JAX-RS, you can
distribute content from multiple sources. RESTful web services can use various types
of input/output formats for request and response. The customer example, described in
The customer Example Application, uses XML.
Resources have representations. A resource representation is the content in the HTTP
message that is sent to, or returned from, the resource using the URI. Each
representation a resource supports has a corresponding media type. For example, if a
resource is going to return content formatted as XML, you can use application/xml as
the associated media type in the HTTP message.Depending on the requirements of
your application, resources can return representations in a preferred single format or
in multiple formats. JAX-RS provides @Consumes and @Produces annotations to declare
the media types that are acceptable for a resource method to read and write.
JAX-RS also maps Java types to and from resource representations using entity
providers. A MessageBodyReader entity provider reads a request entity and
deserializes the request entity into a Java type. A MessageBodyWriter entity provider
serializes from a Java type into a response entity. For example, if a String value is used
as the request entity parameter, the MessageBodyReader entity provider deserializes
the request body into a new String. If a JAXB type is used as the return type on a
resource method, the MessageBodyWriter serializes the JAXB object into a response
body.
By default, the JAX-RS runtime environment attempts to create and use a default
JAXBContext class for JAXB classes.However, if the default JAXBContext class is not
suitable, then you can supply a JAXBContext class for the application using a JAX-RS
ContextResolver provider interface.
The following sections explain how to use JAXB with JAX-RS resource methods.
31.7.1 Using Java Objects to Model Your Data
If you do not have an XML schema definition for the data you want to expose, you can
model your data as Java classes, add JAXB annotations to these classes, and use JAXB
to generate an XML schema for your data. For example, if the data you want to expose
is a collection of products and each product has an ID, a name, a description, and a
price, you can model it as a Java class as follows:
31-12 The Java EE 7 Tutorial
Using JAX-RS with JAXB
@XmlRootElement(name="product")
@XmlAccessorType(XmlAccessType.FIELD)
public class Product {
@XmlElement(required=true)
protected int id;
@XmlElement(required=true)
protected String name;
@XmlElement(required=true)
protected String description;
@XmlElement(required=true)
protected int price;
public Product() {}
// Getter and setter methods
// ...
}
Run the JAXB schema generator on the command line to generate the corresponding
XML schema definition:
schemagen Product.java
This command produces the XML schema as an .xsd file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="product" type="product"/>
<xs:complexType name="product">
<xs:sequence>
<xs:element name="id" type="xs:int"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="description" type="xs:string"/>
<xs:element name="price" type="xs:int"/>
</xs:sequence>
<xs:complexType>
</xs:schema>
Once you have this mapping, you can create Product objects in your application,
return them, and use them as parameters in JAX-RS resource methods. The JAX-RS
runtime uses JAXB to convert the XML data from the request into a Product object and
to convert a Product object into XML data for the response. The following resource
class provides a simple example:
@Path("/product")
public class ProductService {
@GET
@Path("/get")
@Produces("application/xml")
public Product getProduct() {
Product prod = new Product();
prod.setId(1);
prod.setName("Mattress");
prod.setDescription("Queen size mattress");
prod.setPrice(500);
return prod;
}
JAX-RS: Advanced Topics and an Example 31-13
Using JAX-RS with JAXB
@POST
@Path("/create")
@Consumes("application/xml")
public Response createProduct(Product prod) {
// Process or store the product and return a response
// ...
}
}
Some IDEs, such as NetBeans IDE, will run the schema generator tool automatically
during the build process if you add Java classes that have JAXB annotations to your
project. For a detailed example, see The customer Example Application. The customer
example contains a more complex relationship between the Java classes that model the
data, which results in a more hierarchical XML representation.
31.7.2 Starting from an Existing XML Schema Definition
If you already have an XML schema definition in an .xsd file for the data you want to
expose, use the JAXB schema compiler tool. Consider this simple example of an .xsd
file:
<xs:schema targetNamespace="http://xml.product"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
xmlns:myco="http://xml.product">
<xs:element name="product" type="myco:Product"/>
<xs:complexType name="Product">
<xs:sequence>
<xs:element name="id" type="xs:int"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="description" type="xs:string"/>
<xs:element name="price" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Run the schema compiler tool on the command line as follows:
xjc Product.xsd
This command generates the source code for Java classes that correspond to the types
defined in the .xsd file. The schema compiler tool generates a Java class for each
complexType defined in the .xsd file. The fields of each generated Java class are the
same as the elements inside the corresponding complexType, and the class contains
getter and setter methods for these fields.
In this case, the schema compiler tool generates the classes product.xml.Product and
product.xml.ObjectFactory. The Product class contains JAXB annotations, and its
fields correspond to those in the .xsd definition:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Product", propOrder = {
"id",
"name",
"description",
"price"
})
public class Product {
protected int id;
@XmlElement(required = true)
31-14 The Java EE 7 Tutorial
Using JAX-RS with JAXB
protected String name;
@XmlElement(required = true)
protected String description;
protected int price;
// Setter and getter methods
// ...
}
You can create instances of the Product class from your application (for example, from
a database). The generated class product.xml.ObjectFactory contains a method that
allows you to convert these objects to JAXB elements that can be returned as XML
inside JAX-RS resource methods:
@XmlElementDecl(namespace = "http://xml.product", name = "product")
public JAXBElement<Product> createProduct(Product value) {
return new JAXBElement<Product>(_Product_QNAME, Product.class, null, value);
}
The following code shows how to use the generated classes to return a JAXB element
as XML in a JAX-RS resource method:
@Path("/product")
public class ProductService {
@GET
@Path("/get")
@Produces("application/xml")
public JAXBElement<Product> getProduct() {
Product prod = new Product();
prod.setId(1);
prod.setName("Mattress");
prod.setDescription("Queen size mattress");
prod.setPrice(500);
return new ObjectFactory().createProduct(prod);
}
}
For @POST and @PUT resource methods, you can use a Product object directly as a
parameter. JAX-RS maps the XML data from the request into a Product object.
@Path("/product")
public class ProductService {
@GET
// ...
@POST
@Path("/create")
@Consumes("application/xml")
public Response createProduct(Product prod) {
// Process or store the product and return a response
// ...
}
}
31.7.3 Using JSON with JAX-RS and JAXB
JAX-RS can automatically read and write XML using JAXB, but it can also work with
JSON data. JSON is a simple text-based format for data exchange derived from
JavaScript. For the preceding examples, the XML representation of a product is
<?xml version="1.0" encoding="UTF-8"?>
JAX-RS: Advanced Topics and an Example 31-15
The customer Example Application
<product>
<id>1</id>
<name>Mattress</name>
<description>Queen size mattress</description>
<price>500</price>
</product>
The equivalent JSON representation is
{
"id":"1",
"name":"Mattress",
"description":"Queen size mattress",
"price":500
}
You can add the format application/json or MediaType.APPLICATION_JSON to the
@Produces annotation in resource methods to produce responses with JSON data:
@GET
@Path("/get")
@Produces({"application/xml","application/json"})
public Product getProduct() { ... }
In this example, the default response is XML, but the response is a JSON object if the
client makes a GET request that includes this header:
Accept: application/json
The resource methods can also accept JSON data for JAXB annotated classes:
@POST
@Path("/create")
@Consumes({"application/xml","application/json"})
public Response createProduct(Product prod) { ... }
The client should include the following header when submitting JSON data with a
POST request:
Content-Type: application/json
31.8 The customer Example Application
This section describes how to build and run the customer example application. This
application is a RESTful web service that uses JAXB to perform the create, read,
update, delete (CRUD) operations for a specific entity.
The customer sample application is in the tut-install/examples/jaxrs/customer/
directory. See Chapter 2, "Using the Tutorial Examples," for basic information on
building and running sample applications.
31.8.1 Overview of the customer Example Application
The source files of this application are at
tut-install/examples/jaxrs/customer/src/main/java/. The application has three
parts.
■
The Customer and Address entity classes. These classes model the data of the
application and contain JAXB annotations.
31-16 The Java EE 7 Tutorial
The customer Example Application
■
■
The CustomerService resource class. This class contains JAX-RS resource methods
that perform operations on Customer instances represented as XML or JSON data
using JAXB. See The CustomerService Class for details.
The CustomerBean session bean that acts as a backing bean for the web client.
CustomerBean uses the JAX-RS client API to call the methods of CustomerService.
The customer example application shows you how to model your data entities as Java
classes with JAXB annotations.
31.8.2 The Customer and Address Entity Classes
The following class represents a customer's address:
@Entity
@Table(name="CUSTOMER_ADDRESS")
@XmlRootElement(name="address")
@XmlAccessorType(XmlAccessType.FIELD)
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@XmlElement(required=true)
protected int number;
@XmlElement(required=true)
protected String street;
@XmlElement(required=true)
protected String city;
@XmlElement(required=true)
protected String province;
@XmlElement(required=true)
protected String zip;
@XmlElement(required=true)
protected String country;
public Address() { }
// Getter and setter methods
// ...
}
The @XmlRootElement(name="address") annotation maps this class to the address
XML element. The @XmlAccessorType(XmlAccessType.FIELD) annotation specifies
that all the fields of this class are bound to XML by default. The
@XmlElement(required=true) annotation specifies that an element must be present in
the XML representation.
The following class represents a customer:
@Entity
@Table(name="CUSTOMER_CUSTOMER")
@NamedQuery(
name="findAllCustomers",
query="SELECT c FROM Customer c " +
"ORDER BY c.id"
JAX-RS: Advanced Topics and an Example 31-17
The customer Example Application
)
@XmlRootElement(name="customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@XmlAttribute(required=true)
protected int id;
@XmlElement(required=true)
protected String firstname;
@XmlElement(required=true)
protected String lastname;
@XmlElement(required=true)
@OneToOne
protected Address address;
@XmlElement(required=true)
protected String email;
@XmlElement (required=true)
protected String phone;
public Customer() {...}
// Getter and setter methods
// ...
}
The Customer class contains the same JAXB annotations as the previous class, except
for the @XmlAttribute(required=true) annotation, which maps a property to an
attribute of the XML element representing the class.
The Customer class contains a property whose type is another entity, the Address class.
This mechanism allows you to define in Java code the hierarchical relationships
between entities without having to write an .xsd file yourself.
JAXB generates the following XML schema definition for the two preceding classes:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="address" type="address"/>
<xs:element name="customer" type="customer"/>
<xs:complexType name="address">
<xs:sequence>
<xs:element name="id" type="xs:long" minOccurs="0"/>
<xs:element name="number" type="xs:int"/>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="province" type="xs:string"/>
<xs:element name="zip" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="customer">
<xs:sequence>
31-18 The Java EE 7 Tutorial
The customer Example Application
<xs:element name="firstname" type="xs:string"/>
<xs:element name="lastname" type="xs:string"/>
<xs:element ref="address"/>
<xs:element name="email" type="xs:string"/>
<xs:element name="phone" type="xs:string"/>
</xs:sequence>
<xs:attribute name="id" type="xs:int" use="required"/>
</xs:complexType>
</xs:schema>
31.8.3 The CustomerService Class
The CustomerService class has a createCustomer method that creates a customer
resource based on the Customer class and returns a URI for the new resource.
@Stateless
@Path("/Customer")
public class CustomerService {
public static final Logger logger =
Logger.getLogger(CustomerService.class.getCanonicalName());
@PersistenceContext
private EntityManager em;
private CriteriaBuilder cb;
@PostConstruct
private void init() {
cb = em.getCriteriaBuilder();
}
...
@POST
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response createCustomer(Customer customer) {
try {
long customerId = persist(customer);
return Response.created(URI.create("/" + customerId)).build();
} catch (Exception e) {
logger.log(Level.SEVERE,
"Error creating customer for customerId {0}. {1}",
new Object[]{customer.getId(), e.getMessage()});
throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
}
}
...
private long persist(Customer customer) {
try {
Address address = customer.getAddress();
em.persist(address);
em.persist(customer);
} catch (Exception ex) {
logger.warning("Something went wrong when persisting the customer");
}
return customer.getId();
}
The response returned to the client has a URI to the newly created resource. The return
type is an entity body mapped from the property of the response with the status code
specified by the status property of the response. The WebApplicationException is a
JAX-RS: Advanced Topics and an Example 31-19
The customer Example Application
RuntimeException that is used to wrap the appropriate HTTP error status code, such
as 404, 406, 415, or 500.
The @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) and
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
annotations set the request and response media types to use the appropriate MIME
client. These annotations can be applied to a resource method, a resource class, or even
an entity provider. If you do not use these annotations, JAX-RS allows the use of any
media type ("*/*").
The following code snippet shows the implementation of the getCustomer and
findbyId methods. The getCustomer method uses the @Produces annotation and
returns a Customer object, which is converted to an XML or JSON representation
depending on the Accept: header specified by the client.
@GET
@Path("{id}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Customer getCustomer(@PathParam("id") String customerId) {
Customer customer = null;
try {
customer = findById(customerId);
} catch (Exception ex) {
logger.log(Level.SEVERE,
"Error calling findCustomer() for customerId {0}. {1}",
new Object[]{customerId, ex.getMessage()});
}
return customer;
}
...
private Customer findById(String customerId) {
Customer customer = null;
try {
customer = em.find(Customer.class, customerId);
return customer;
} catch (Exception ex) {
logger.log(Level.WARNING,
"Couldn't find customer with ID of {0}", customerId);
}
return customer;
}
31.8.4 Using the JAX-RS Client in the CustomerBean Classes
Use the JAX-RS Client API to write a client for the customer example application.
The CustomerBean enterprise bean class calls the JAX-RS Client API to test the
CustomerService web service:
@Named
@Stateless
public class CustomerBean {
protected Client client;
private static final Logger logger =
Logger.getLogger(CustomerBean.class.getName());
@PostConstruct
private void init() {
client = ClientBuilder.newClient();
}
31-20 The Java EE 7 Tutorial
The customer Example Application
@PreDestroy
private void clean() {
client.close();
}
public String createCustomer(Customer customer) {
if (customer == null) {
logger.log(Level.WARNING, "customer is null.");
return "customerError";
}
String navigation;
Response response =
client.target("http://localhost:8080/customer/webapi/Customer")
.request(MediaType.APPLICATION_XML)
.post(Entity.entity(customer, MediaType.APPLICATION_XML),
Response.class);
if (response.getStatus() == Status.CREATED.getStatusCode()) {
navigation = "customerCreated";
} else {
logger.log(Level.WARNING, "couldn''t create customer with " +
"id {0}. Status returned was {1}",
new Object[]{customer.getId(), response.getStatus()});
navigation = "customerError";
}
return navigation;
}
public String retrieveCustomer(String id) {
String navigation;
Customer customer =
client.target("http://localhost:8080/customer/webapi/Customer")
.path(id)
.request(MediaType.APPLICATION_XML)
.get(Customer.class);
if (customer == null) {
navigation = "customerError";
} else {
navigation = "customerRetrieved";
}
return navigation;
}
public List<Customer> retrieveAllCustomers() {
List<Customer> customers =
client.target("http://localhost:8080/customer/webapi/Customer")
.path("all")
.request(MediaType.APPLICATION_XML)
.get(new GenericType<List<Customer>>() {});
return customers;
}
}
This client uses the POST and GET methods.
All of these HTTP status codes indicate success: 201 for POST, 200 for GET, and 204 for
DELETE. For details about the meanings of HTTP status codes, see
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.
JAX-RS: Advanced Topics and an Example 31-21
The customer Example Application
31.8.5 Running the customer Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
customer application.
31.8.5.1 To Build, Package, and Deploy the customer Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/jaxrs
4.
Select the customer folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the customer project and select Build.
This command builds and packages the application into a WAR file,
customer.war, located in the target directory. Then, the WAR file is deployed to
GlassFish Server.
7.
Open the web client in a browser at the following URL:
http://localhost:8080/customer/
The web client allows you to create and view customers.
31.8.5.2 To Build, Package, and Deploy the customer Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/jaxrs/customer/
3.
Enter the following command:
mvn install
This command builds and packages the application into a WAR file,
customer.war, located in the target directory. Then, the WAR file is deployed to
GlassFish Server.
4.
Open the web client in a browser at the following URL:
http://localhost:8080/customer/
The web client allows you to create and view customers.
31-22 The Java EE 7 Tutorial
Part VII
Part VII
Enterprise Beans
Part VII explores Enterprise JavaBeans components. This part contains the following
chapters:
■
Chapter 32, "Enterprise Beans"
■
Chapter 33, "Getting Started with Enterprise Beans"
■
Chapter 34, "Running the Enterprise Bean Examples"
■
Chapter 35, "Using the Embedded Enterprise Bean Container"
■
Chapter 36, "Using Asynchronous Method Invocation in Session Beans"
32
Enterprise Beans
32
Enterprise beans are Java EE components that implement Enterprise JavaBeans (EJB)
technology. Enterprise beans run in the EJB container, a runtime environment within
GlassFish Server (see Container Types). Although transparent to the application
developer, the EJB container provides system-level services, such as transactions and
security, to its enterprise beans. These services enable you to quickly build and deploy
enterprise beans, which form the core of transactional Java EE applications.
The following topics are addressed here:
■
What Is an Enterprise Bean?
■
What Is a Session Bean?
■
What Is a Message-Driven Bean?
■
Accessing Enterprise Beans
■
The Contents of an Enterprise Bean
■
Naming Conventions for Enterprise Beans
■
The Lifecycles of Enterprise Beans
■
Further Information about Enterprise Beans
32.1 What Is an Enterprise Bean?
Written in the Java programming language, an enterprise bean is a server-side
component that encapsulates the business logic of an application. The business logic
is the code that fulfills the purpose of the application. In an inventory control
application, for example, the enterprise beans might implement the business logic in
methods called checkInventoryLevel and orderProduct. By invoking these methods,
clients can access the inventory services provided by the application.
32.1.1 Benefits of Enterprise Beans
For several reasons, enterprise beans simplify the development of large, distributed
applications. First, because the EJB container provides system-level services to
enterprise beans, the bean developer can concentrate on solving business problems.
The EJB container, rather than the bean developer, is responsible for system-level
services, such as transaction management and security authorization.
Second, because the beans rather than the clients contain the application's business
logic, the client developer can focus on the presentation of the client. The client
developer does not have to code the routines that implement business rules or access
Enterprise Beans 32-1
What Is a Session Bean?
databases. As a result, the clients are thinner, a benefit that is particularly important for
clients that run on small devices.
Third, because enterprise beans are portable components, the application assembler
can build new applications from existing beans. Provided that they use the standard
APIs, these applications can run on any compliant Java EE server.
32.1.2 When to Use Enterprise Beans
You should consider using enterprise beans if your application has any of the
following requirements.
■
■
■
The application must be scalable. To accommodate a growing number of users,
you may need to distribute an application's components across multiple machines.
Not only can the enterprise beans of an application run on different machines, but
also their location will remain transparent to the clients.
Transactions must ensure data integrity. Enterprise beans support transactions, the
mechanisms that manage the concurrent access of shared objects.
The application will have a variety of clients. With only a few lines of code, remote
clients can easily locate enterprise beans. These clients can be thin, various, and
numerous.
32.1.3 Types of Enterprise Beans
Table 32–1 summarizes the two types of enterprise beans. The following sections
discuss each type in more detail.
Table 32–1
Enterprise Bean Types
Enterprise Bean Type
Purpose
Session
Performs a task for a client; optionally, may implement a web
service
Message-driven
Acts as a listener for a particular messaging type, such as the Java
Message Service API
32.2 What Is a Session Bean?
A session bean encapsulates business logic that can be invoked programmatically by a
client over local, remote, or web service client views. To access an application that is
deployed on the server, the client invokes the session bean's methods. The session
bean performs work for its client, shielding it from complexity by executing business
tasks inside the server.
A session bean is not persistent. (That is, its data is not saved to a database.)
For code samples, see Chapter 34, "Running the Enterprise Bean Examples".
32.2.1 Types of Session Beans
Session beans are of three types: stateful, stateless, and singleton.
32.2.1.1 Stateful Session Beans
The state of an object consists of the values of its instance variables. In a stateful
session bean, the instance variables represent the state of a unique client/bean
session. Because the client interacts ("talks") with its bean, this state is often called the
conversational state.
32-2 The Java EE 7 Tutorial
What Is a Session Bean?
As its name suggests, a session bean is similar to an interactive session. A session bean
is not shared; it can have only one client, in the same way that an interactive session
can have only one user. When the client terminates, its session bean appears to
terminate and is no longer associated with the client.
The state is retained for the duration of the client/bean session. If the client removes
the bean, the session ends and the state disappears. This transient nature of the state is
not a problem, however, because when the conversation between the client and the
bean ends, there is no need to retain the state.
32.2.1.2 Stateless Session Beans
A stateless session bean does not maintain a conversational state with the client.
When a client invokes the methods of a stateless bean, the bean's instance variables
may contain a state specific to that client but only for the duration of the invocation.
When the method is finished, the client-specific state should not be retained. Clients
may, however, change the state of instance variables in pooled stateless beans, and this
state is held over to the next invocation of the pooled stateless bean. Except during
method invocation, all instances of a stateless bean are equivalent, allowing the EJB
container to assign an instance to any client. That is, the state of a stateless session
bean should apply across all clients.
Because they can support multiple clients, stateless session beans can offer better
scalability for applications that require large numbers of clients. Typically, an
application requires fewer stateless session beans than stateful session beans to
support the same number of clients.
A stateless session bean can implement a web service, but a stateful session bean
cannot.
32.2.1.3 Singleton Session Beans
A singleton session bean is instantiated once per application and exists for the
lifecycle of the application. Singleton session beans are designed for circumstances in
which a single enterprise bean instance is shared across and concurrently accessed by
clients.
Singleton session beans offer similar functionality to stateless session beans but differ
from them in that there is only one singleton session bean per application, as opposed
to a pool of stateless session beans, any of which may respond to a client request. Like
stateless session beans, singleton session beans can implement web service endpoints.
Singleton session beans maintain their state between client invocations but are not
required to maintain their state across server crashes or shutdowns.
Applications that use a singleton session bean may specify that the singleton should be
instantiated upon application startup, which allows the singleton to perform
initialization tasks for the application. The singleton may perform cleanup tasks on
application shutdown as well, because the singleton will operate throughout the
lifecycle of the application.
32.2.2 When to Use Session Beans
Stateful session beans are appropriate if any of the following conditions are true.
■
The bean's state represents the interaction between the bean and a specific client.
■
The bean needs to hold information about the client across method invocations.
■
The bean mediates between the client and the other components of the
application, presenting a simplified view to the client.
Enterprise Beans 32-3
What Is a Message-Driven Bean?
■
Behind the scenes, the bean manages the work flow of several enterprise beans.
To improve performance, you might choose a stateless session bean if it has any of
these traits.
■
■
■
The bean's state has no data for a specific client.
In a single method invocation, the bean performs a generic task for all clients. For
example, you might use a stateless session bean to send an email that confirms an
online order.
The bean implements a web service.
Singleton session beans are appropriate in the following circumstances.
■
State needs to be shared across the application.
■
A single enterprise bean needs to be accessed by multiple threads concurrently.
■
■
The application needs an enterprise bean to perform tasks upon application
startup and shutdown.
The bean implements a web service.
32.3 What Is a Message-Driven Bean?
A message-driven bean is an enterprise bean that allows Java EE applications to
process messages asynchronously. This type of bean normally acts as a JMS message
listener, which is similar to an event listener but receives JMS messages instead of
events. The messages can be sent by any Java EE component (an application client,
another enterprise bean, or a web component) or by a JMS application or system that
does not use Java EE technology. Message-driven beans can process JMS messages or
other kinds of messages.
32.3.1 What Makes Message-Driven Beans Different from Session Beans?
The most visible difference between message-driven beans and session beans is that
clients do not access message-driven beans through interfaces. Interfaces are described
in the section Accessing Enterprise Beans. Unlike a session bean, a message-driven
bean has only a bean class.
In several respects, a message-driven bean resembles a stateless session bean.
■
■
■
A message-driven bean's instances retain no data or conversational state for a
specific client.
All instances of a message-driven bean are equivalent, allowing the EJB container
to assign a message to any message-driven bean instance. The container can pool
these instances to allow streams of messages to be processed concurrently.
A single message-driven bean can process messages from multiple clients.
The instance variables of the message-driven bean instance can contain some state
across the handling of client messages, such as a JMS API connection, an open
database connection, or an object reference to an enterprise bean object.
Client components do not locate message-driven beans and invoke methods directly
on them. Instead, a client accesses a message-driven bean through, for example, JMS
by sending messages to the message destination for which the message-driven bean
class is the MessageListener. You assign a message-driven bean's destination during
deployment by using GlassFish Server resources.
Message-driven beans have the following characteristics.
32-4 The Java EE 7 Tutorial
Accessing Enterprise Beans
■
They execute upon receipt of a single client message.
■
They are invoked asynchronously.
■
They are relatively short-lived.
■
They do not represent directly shared data in the database, but they can access and
update this data.
■
They can be transaction-aware.
■
They are stateless.
When a message arrives, the container calls the message-driven bean's onMessage
method to process the message. The onMessage method normally casts the message to
one of the five JMS message types and handles it in accordance with the application's
business logic. The onMessage method can call helper methods or can invoke a session
bean to process the information in the message or to store it in a database.
A message can be delivered to a message-driven bean within a transaction context, so
all operations within the onMessage method are part of a single transaction. If message
processing is rolled back, the message will be redelivered. For more information, see
Receiving Messages Asynchronously Using a Message-Driven Bean and Chapter 51,
"Transactions".
32.3.2 When to Use Message-Driven Beans
Session beans allow you to send JMS messages and to receive them synchronously but
not asynchronously. To avoid tying up server resources, do not to use blocking
synchronous receives in a server-side component; in general, JMS messages should not
be sent or received synchronously. To receive messages asynchronously, use a
message-driven bean.
32.4 Accessing Enterprise Beans
The material in this section applies only to session beans
and not to message-driven beans. Because they have a different
programming model, message-driven beans do not have interfaces
or no-interface views that define client access.
Note:
Clients access enterprise beans either through a no-interface view or through a
business interface. A no-interface view of an enterprise bean exposes the public
methods of the enterprise bean implementation class to clients. Clients using the
no-interface view of an enterprise bean may invoke any public methods in the
enterprise bean implementation class or any superclasses of the implementation class.
A business interface is a standard Java programming language interface that contains
the business methods of the enterprise bean.
A client can access a session bean only through the methods defined in the bean's
business interface or through the public methods of an enterprise bean that has a
no-interface view. The business interface or no-interface view defines the client's view
of an enterprise bean. All other aspects of the enterprise bean (method
implementations and deployment settings) are hidden from the client.
Well-designed interfaces and no-interface views simplify the development and
maintenance of Java EE applications. Not only do clean interfaces and no-interface
views shield the clients from any complexities in the EJB tier, but they also allow the
Enterprise Beans 32-5
Accessing Enterprise Beans
enterprise beans to change internally without affecting the clients. For example, if you
change the implementation of a session bean business method, you won't have to alter
the client code. But if you were to change the method definitions in the interfaces, you
might have to modify the client code as well. Therefore, it is important that you design
the interfaces and no-interface views carefully to isolate your clients from possible
changes in the enterprise beans.
Session beans can have more than one business interface. Session beans should, but are
not required to, implement their business interface or interfaces.
32.4.1 Using Enterprise Beans in Clients
The client of an enterprise bean obtains a reference to an instance of an enterprise bean
through either dependency injection, using Java programming language annotations,
or JNDI lookup, using the Java Naming and Directory Interface syntax to find the
enterprise bean instance.
Dependency injection is the simplest way of obtaining an enterprise bean reference.
Clients that run within a Java EE server-managed environment, JavaServer Faces web
applications, JAX-RS web services, other enterprise beans, or Java EE application
clients support dependency injection using the javax.ejb.EJB annotation.
Applications that run outside a Java EE server-managed environment, such as Java SE
applications, must perform an explicit lookup. JNDI supports a global syntax for
identifying Java EE components to simplify this explicit lookup.
32.4.1.1 Portable JNDI Syntax
Three JNDI namespaces are used for portable JNDI lookups: java:global,
java:module, and java:app.
■
The java:global JNDI namespace is the portable way of finding remote enterprise
beans using JNDI lookups. JNDI addresses are of the following form:
java:global[/application name]/module name /enterprise bean name[/interface
name ]
Application name and module name default to the name of the application and
module minus the file extension. Application names are required only if the
application is packaged within an EAR. The interface name is required only if the
enterprise bean implements more than one business interface.
■
The java:module namespace is used to look up local enterprise beans within the
same module. JNDI addresses using the java:module namespace are of the
following form:
java:module/enterprise bean name/[interface name]
The interface name is required only if the enterprise bean implements more than
one business interface.
■
The java:app namespace is used to look up local enterprise beans packaged
within the same application. That is, the enterprise bean is packaged within an
EAR file containing multiple Java EE modules. JNDI addresses using the java:app
namespace are of the following form:
java:app[/module name]/enterprise bean name [/interface name]
The module name is optional. The interface name is required only if the enterprise
bean implements more than one business interface.
32-6 The Java EE 7 Tutorial
Accessing Enterprise Beans
For example, if an enterprise bean, MyBean, is packaged within the web application
archive myApp.war, the module name is myApp. The portable JNDI name is
java:module/MyBean. An equivalent JNDI name using the java:global namespace is
java:global/myApp/MyBean.
32.4.2 Deciding on Remote or Local Access
When you design a Java EE application, one of the first decisions you make is the type
of client access allowed by the enterprise beans: remote, local, or web service.
Whether to allow local or remote access depends on the following factors.
■
■
■
■
Tight or loose coupling of related beans: Tightly coupled beans depend on one
another. For example, if a session bean that processes sales orders calls a session
bean that emails a confirmation message to the customer, these beans are tightly
coupled. Tightly coupled beans are good candidates for local access. Because they
fit together as a logical unit, they typically call each other often and would benefit
from the increased performance that is possible with local access.
Type of client: If an enterprise bean is accessed by application clients, it should
allow remote access. In a production environment, these clients almost always run
on machines other than those on which GlassFish Server is running. If an
enterprise bean's clients are web components or other enterprise beans, the type of
access depends on how you want to distribute your components.
Component distribution: Java EE applications are scalable because their
server-side components can be distributed across multiple machines. In a
distributed application, for example, the server that the web components run on
may not be the one on which the enterprise beans they access are deployed. In this
distributed scenario, the enterprise beans should allow remote access.
Performance: Owing to such factors as network latency, remote calls may be
slower than local calls. On the other hand, if you distribute components among
different servers, you may improve the application's overall performance. Both of
these statements are generalizations; performance can vary in different operational
environments. Nevertheless, you should keep in mind how your application
design might affect performance.
If you aren't sure which type of access an enterprise bean should have, choose remote
access. This decision gives you more flexibility. In the future, you can distribute your
components to accommodate the growing demands on your application.
Although it is uncommon, it is possible for an enterprise bean to allow both remote
and local access. If this is the case, either the business interface of the bean must be
explicitly designated as a business interface by being decorated with the @Remote or
@Local annotations, or the bean class must explicitly designate the business interfaces
by using the @Remote and @Local annotations. The same business interface cannot be
both a local and a remote business interface.
32.4.3 Local Clients
A local client has these characteristics.
■
It must run in the same application as the enterprise bean it accesses.
■
It can be a web component or another enterprise bean.
■
To the local client, the location of the enterprise bean it accesses is not transparent.
The no-interface view of an enterprise bean is a local view. The public methods of the
enterprise bean implementation class are exposed to local clients that access the
Enterprise Beans 32-7
Accessing Enterprise Beans
no-interface view of the enterprise bean. Enterprise beans that use the no-interface
view do not implement a business interface.
The local business interface defines the bean's business and lifecycle methods. If the
bean's business interface is not decorated with @Local or @Remote, and if the bean class
does not specify the interface using @Local or @Remote, the business interface is by
default a local interface.
To build an enterprise bean that allows only local access, you may, but are not required
to, do one of the following.
■
Create an enterprise bean implementation class that does not implement a
business interface, indicating that the bean exposes a no-interface view to clients.
For example:
@Session
public class MyBean { ... }
■
Annotate the business interface of the enterprise bean as a @Local interface. For
example:
@Local
public interface InterfaceName { ... }
■
Specify the interface by decorating the bean class with @Local and specify the
interface name. For example:
@Local(InterfaceName.class)
public class BeanName implements InterfaceName
{ ... }
32.4.3.1 Accessing Local Enterprise Beans Using the No-Interface View
Client access to an enterprise bean that exposes a local, no-interface view is
accomplished through either dependency injection or JNDI lookup.
■
To obtain a reference to the no-interface view of an enterprise bean through
dependency injection, use the javax.ejb.EJB annotation and specify the
enterprise bean's implementation class:
@EJB
ExampleBean exampleBean;
■
To obtain a reference to the no-interface view of an enterprise bean through JNDI
lookup, use the javax.naming.InitialContext interface's lookup method:
ExampleBean exampleBean = (ExampleBean)
InitialContext.lookup("java:module/ExampleBean");
Clients do not use the new operator to obtain a new instance of an enterprise bean that
uses a no-interface view.
32.4.3.2 Accessing Local Enterprise Beans That Implement Business Interfaces
Client access to enterprise beans that implement local business interfaces is
accomplished through either dependency injection or JNDI lookup.
■
To obtain a reference to the local business interface of an enterprise bean through
dependency injection, use the javax.ejb.EJB annotation and specify the
enterprise bean's local business interface name:
@EJB
Example example;
32-8 The Java EE 7 Tutorial
Accessing Enterprise Beans
■
To obtain a reference to a local business interface of an enterprise bean through
JNDI lookup, use the javax.naming.InitialContext interface's lookup method:
ExampleLocal example = (ExampleLocal)
InitialContext.lookup("java:module/ExampleLocal");
32.4.4 Remote Clients
A remote client of an enterprise bean has the following traits.
■
It can run on a different machine and a different JVM from the enterprise bean it
accesses. (It is not required to run on a different JVM.)
■
It can be a web component, an application client, or another enterprise bean.
■
To a remote client, the location of the enterprise bean is transparent.
■
The enterprise bean must implement a business interface. That is, remote clients
may not access an enterprise bean through a no-interface view.
To create an enterprise bean that allows remote access, you must either
■
Decorate the business interface of the enterprise bean with the @Remote annotation:
@Remote
public interface InterfaceName { ... }
■
Or decorate the bean class with @Remote, specifying the business interface or
interfaces:
@Remote(InterfaceName.class)
public class BeanName implements InterfaceName { ... }
The remote interface defines the business and lifecycle methods that are specific to the
bean. For example, the remote interface of a bean named BankAccountBean might have
business methods named deposit and credit. Figure 32–1 shows how the interface
controls the client's view of an enterprise bean.
Figure 32–1 Interfaces for an Enterprise Bean with Remote Access
Remote Client
Remote Interface
BankAccountBean
deposit()
credit()
Client access to an enterprise bean that implements a remote business interface is
accomplished through either dependency injection or JNDI lookup.
■
To obtain a reference to the remote business interface of an enterprise bean
through dependency injection, use the javax.ejb.EJB annotation and specify the
enterprise bean's remote business interface name:
@EJB
Example example;
■
To obtain a reference to a remote business interface of an enterprise bean through
JNDI lookup, use the javax.naming.InitialContext interface's lookup method:
ExampleRemote example = (ExampleRemote)
Enterprise Beans 32-9
The Contents of an Enterprise Bean
InitialContext.lookup("java:global/myApp/ExampleRemote");
32.4.5 Web Service Clients
A web service client can access a Java EE application in two ways. First, the client can
access a web service created with JAX-WS. (For more information on JAX-WS, see
Chapter 28, "Building Web Services with JAX-WS".) Second, a web service client can
invoke the business methods of a stateless session bean. Message beans cannot be
accessed by web service clients.
Provided that it uses the correct protocols (SOAP, HTTP, WSDL), any web service
client can access a stateless session bean, whether or not the client is written in the Java
programming language. The client doesn't even "know" what technology implements
the service: stateless session bean, JAX-WS, or some other technology. In addition,
enterprise beans and web components can be clients of web services. This flexibility
enables you to integrate Java EE applications with web services.
A web service client accesses a stateless session bean through the bean's web service
endpoint implementation class. By default, all public methods in the bean class are
accessible to web service clients. The @WebMethod annotation may be used to customize
the behavior of web service methods. If the @WebMethod annotation is used to decorate
the bean class's methods, only those methods decorated with @WebMethod are exposed
to web service clients.
For a code sample, see A Web Service Example: helloservice.
32.4.6 Method Parameters and Access
The type of access affects the parameters of the bean methods that are called by clients.
The following sections apply not only to method parameters but also to method return
values.
32.4.6.1 Isolation
The parameters of remote calls are more isolated than those of local calls. With remote
calls, the client and the bean operate on different copies of a parameter object. If the
client changes the value of the object, the value of the copy in the bean does not
change. This layer of isolation can help protect the bean if the client accidentally
modifies the data.
In a local call, both the client and the bean can modify the same parameter object. In
general, you should not rely on this side effect of local calls. Perhaps someday you will
want to distribute your components, replacing the local calls with remote ones.
As with remote clients, web service clients operate on different copies of parameters
than does the bean that implements the web service.
32.4.6.2 Granularity of Accessed Data
Because remote calls are likely to be slower than local calls, the parameters in remote
methods should be relatively coarse-grained. A coarse-grained object contains more
data than a fine-grained one, so fewer access calls are required. For the same reason,
the parameters of the methods called by web service clients should also be
coarse-grained.
32.5 The Contents of an Enterprise Bean
To develop an enterprise bean, you must provide the following files.
32-10 The Java EE 7 Tutorial
The Lifecycles of Enterprise Beans
■
■
■
Enterprise bean class: Implements the business methods of the enterprise bean
and any lifecycle callback methods.
Business interfaces: Define the business methods implemented by the enterprise
bean class. A business interface is not required if the enterprise bean exposes a
local, no-interface view.
Helper classes: Other classes needed by the enterprise bean class, such as
exception and utility classes.
Package the programming artifacts in the preceding list either into an EJB JAR file (a
stand-alone module that stores the enterprise bean) or within a web application
archive (WAR) module. See Packaging Enterprise Beans in EJB JAR Modules and
Packaging Enterprise Beans in WAR Modules for more information.
32.6 Naming Conventions for Enterprise Beans
Because enterprise beans are composed of multiple parts, it's useful to follow a naming
convention for your applications. Table 32–2 summarizes the conventions for the
example beans in this tutorial.
Table 32–2
Naming Conventions for Enterprise Beans
Item
Syntax
Example
Enterprise bean name
nameBean
AccountBean
Enterprise bean class
nameBean
AccountBean
Business interface
name
Account
32.7 The Lifecycles of Enterprise Beans
An enterprise bean goes through various stages during its lifetime, or lifecycle. Each
type of enterprise bean (stateful session, stateless session, singleton session, or
message-driven) has a different lifecycle.
The descriptions that follow refer to methods that are explained along with the code
examples in the next two chapters. If you are new to enterprise beans, you should skip
this section and run the code examples first.
32.7.1 The Lifecycle of a Stateful Session Bean
Figure 32–2 illustrates the stages that a stateful session bean passes through during its
lifetime. The client initiates the lifecycle by obtaining a reference to a stateful session
bean. The container performs any dependency injection and then invokes the method
annotated with @PostConstruct, if any. The bean is now ready to have its business
methods invoked by the client.
Enterprise Beans 32-11
The Lifecycles of Enterprise Beans
Figure 32–2 Lifecycle of a Stateful Session Bean
1 Create
2 Dependency injection, if any
3 PostConstruct callback, if any
4 Init method, or ejbCreate<METHOD>, if any
PrePassivate
callback, if any
Does Not Exist
Ready
Passive
PostActivate
callback, if any
1 Remove
2 PreDestroy callback, if any
While in the ready stage, the EJB container may decide to deactivate, or passivate, the
bean by moving it from memory to secondary storage. (Typically, the EJB container
uses a least-recently-used algorithm to select a bean for passivation.) The EJB container
invokes the method annotated @PrePassivate, if any, immediately before passivating
it. If a client invokes a business method on the bean while it is in the passive stage, the
EJB container activates the bean, calls the method annotated @PostActivate, if any,
and then moves it to the ready stage.
At the end of the lifecycle, the client invokes a method annotated @Remove, and the EJB
container calls the method annotated @PreDestroy, if any. The bean's instance is then
ready for garbage collection.
Your code controls the invocation of only one lifecycle method: the method annotated
@Remove. All other methods in Figure 32–2 are invoked by the EJB container. See
Chapter 52, "Resource Adapters and Contracts" for more information.
32.7.2 The Lifecycle of a Stateless Session Bean
Because a stateless session bean is never passivated, its lifecycle has only two stages:
nonexistent and ready for the invocation of business methods. Figure 32–3 illustrates
the stages of a stateless session bean.
Figure 32–3 Lifecycle of a Stateless or Singleton Session Bean
1 Dependency injection, if any
2 PostConstruct callback, if any
Does Not Exist
Ready
PreDestroy callback, if any
The EJB container typically creates and maintains a pool of stateless session beans,
beginning the stateless session bean's lifecycle. The container performs any
dependency injection and then invokes the method annotated @PostConstruct, if it
exists. The bean is now ready to have its business methods invoked by a client.
At the end of the lifecycle, the EJB container calls the method annotated @PreDestroy,
if it exists. The bean's instance is then ready for garbage collection.
32.7.3 The Lifecycle of a Singleton Session Bean
Like a stateless session bean, a singleton session bean is never passivated and has only
two stages, nonexistent and ready for the invocation of business methods, as shown in
32-12 The Java EE 7 Tutorial
Further Information about Enterprise Beans
Figure 32–3.
The EJB container initiates the singleton session bean lifecycle by creating the singleton
instance. This occurs upon application deployment if the singleton is annotated with
the @Startup annotation. The container performs any dependency injection and then
invokes the method annotated @PostConstruct, if it exists. The singleton session bean
is now ready to have its business methods invoked by the client.
At the end of the lifecycle, the EJB container calls the method annotated @PreDestroy,
if it exists. The singleton session bean is now ready for garbage collection.
32.7.4 The Lifecycle of a Message-Driven Bean
Figure 32–4 illustrates the stages in the lifecycle of a message-driven bean.
Figure 32–4 Lifecycle of a Message-Driven Bean
1 Dependency injection, if any
2 PostConstruct callback, if any
Does Not Exist
onMessage
Ready
PreDestroy callback, if any
The EJB container usually creates a pool of message-driven bean instances. For each
instance, the EJB container performs these tasks.
1.
If the message-driven bean uses dependency injection, the container injects these
references before instantiating the instance.
2.
The container calls the method annotated @PostConstruct, if any.
Like a stateless session bean, a message-driven bean is never passivated and has only
two states: nonexistent and ready to receive messages.
At the end of the lifecycle, the container calls the method annotated @PreDestroy, if
any. The bean's instance is then ready for garbage collection.
32.8 Further Information about Enterprise Beans
For more information on Enterprise JavaBeans technology, see
■
Enterprise JavaBeans 3.2 specification:
http://www.jcp.org/en/jsr/detail?id=345
■
Enterprise JavaBeans 3.2 specification project:
https://java.net/projects/ejb-spec/
Enterprise Beans 32-13
Further Information about Enterprise Beans
32-14 The Java EE 7 Tutorial
33
Getting Started with Enterprise Beans
33
This chapter shows how to develop, deploy, and run a simple Java EE application
named converter that uses an EJB for its business logic. The purpose of converter is
to calculate currency conversions among Japanese yen, euros, and US dollars. The
converter application consists of an enterprise bean, which performs the calculations,
and a web client.
Here's an overview of the steps you'll follow in this chapter.
1.
Create the enterprise bean: ConverterBean.
2.
Create the web client.
3.
Deploy converter onto the server.
4.
Using a browser, run the web client.
Before proceeding, make sure that you've done the following:
■
Read Chapter 1, "Overview"
■
Become familiar with enterprise beans (see Chapter 32, "Enterprise Beans")
■
Started the server (see Starting and Stopping GlassFish Server)
The following topics are addressed here:
■
Creating the Enterprise Bean
■
Modifying the Java EE Application
33.1 Creating the Enterprise Bean
The enterprise bean in our example is a stateless session bean called ConverterBean.
The source code for ConverterBean is in the
tut-install/examples/ejb/converter/src/main/java/ directory.
Creating ConverterBean requires these steps:
1.
Coding the bean's implementation class (the source code is provided)
2.
Compiling the source code
33.1.1 Coding the Enterprise Bean Class
The enterprise bean class for this example is called ConverterBean. This class
implements two business methods: dollarToYen and yenToEuro. Because the
enterprise bean class doesn't implement a business interface, the enterprise bean
exposes a local, no-interface view. The public methods in the enterprise bean class are
Getting Started with Enterprise Beans 33-1
Creating the Enterprise Bean
available to clients that obtain a reference to ConverterBean. The source code for the
ConverterBean class is as follows:
package javaeetutorial.converter.ejb;
import java.math.BigDecimal;
import javax.ejb.*;
@Stateless
public class ConverterBean {
private BigDecimal yenRate = new BigDecimal("83.0602");
private BigDecimal euroRate = new BigDecimal("0.0093016");
public BigDecimal dollarToYen(BigDecimal dollars) {
BigDecimal result = dollars.multiply(yenRate);
return result.setScale(2, BigDecimal.ROUND_UP);
}
public BigDecimal yenToEuro(BigDecimal yen) {
BigDecimal result = yen.multiply(euroRate);
return result.setScale(2, BigDecimal.ROUND_UP);
}
}
Note the @Stateless annotation decorating the enterprise bean class. This annotation
lets the container know that ConverterBean is a stateless session bean.
33.1.2 Creating the converter Web Client
The web client is contained in the following servlet class under the
tut-install/examples/ejb/converter/src/main/java/ directory:
converter/web/ConverterServlet.java
A Java servlet is a web component that responds to HTTP requests.
The ConverterServlet class uses dependency injection to obtain a reference to
ConverterBean. The javax.ejb.EJB annotation is added to the declaration of the
private member variable converter, which is of type ConverterBean. ConverterBean
exposes a local, no-interface view, so the enterprise bean implementation class is the
variable type:
@WebServlet(urlPatterns="/")
public class ConverterServlet extends HttpServlet {
@EJB
ConverterBean converter;
...
}
When the user enters an amount to be converted to yen and euro, the amount is
retrieved from the request parameters; then the ConverterBean.dollarToYen and the
ConverterBean.yenToEuro methods are called:
...
try {
String amount = request.getParameter("amount");
if (amount != null && amount.length()> 0) {
// convert the amount to a BigDecimal from the request parameter
BigDecimal d = new BigDecimal(amount);
// call the ConverterBean.dollarToYen() method to get the amount
// in Yen
33-2 The Java EE 7 Tutorial
Creating the Enterprise Bean
BigDecimal yenAmount = converter.dollarToYen(d);
// call the ConverterBean.yenToEuro() method to get the amount
// in Euros
BigDecimal euroAmount = converter.yenToEuro(yenAmount);
...
}
...
}
The results are displayed to the user.
33.1.3 Running the converter Example
Now you are ready to compile the enterprise bean class (ConverterBean.java) and the
servlet class (ConverterServlet.java) and to package the compiled classes into a
WAR file. You can use either NetBeans IDE or Maven to build, package, deploy, and
run the converter example.
33.1.3.1 To Run the converter Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/ejb
4.
Select the converter folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the converter project and select Build.
7.
Open a web browser to the following URL:
http://localhost:8080/converter
8.
On the Servlet ConverterServlet page, enter 100 in the field and click Submit.
A second page opens, showing the converted values.
33.1.3.2 To Run the converter Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/ejb/converter/
3.
Enter the following command:
mvn install
This command compiles the source files for the enterprise bean and the servlet,
packages the project into a WAR module (converter.war), and deploys the WAR
to the server. For more information about Maven, see Building the Examples.
4.
Open a web browser to the following URL:
http://localhost:8080/converter
Getting Started with Enterprise Beans 33-3
Modifying the Java EE Application
5.
On the Servlet ConverterServlet page, enter 100 in the field and click Submit.
A second page opens, showing the converted values.
33.2 Modifying the Java EE Application
GlassFish Server supports iterative development. Whenever you make a change to a
Java EE application, you must redeploy the application.
33.2.1 To Modify a Class File
To modify a class file in an enterprise bean, you change the source code, recompile it,
and redeploy the application. For example, to update the exchange rate in the
dollarToYen business method of the ConverterBean class, you would follow these
steps.
To modify ConverterServlet, the procedure is the same.
1.
Edit ConverterBean.java and save the file.
2.
Recompile the source file.
■
To recompile ConverterBean.java in NetBeans IDE, right-click the converter
project and select Run.
This recompiles the ConverterBean.java file, replaces the old class file in the
build directory, and redeploys the application to GlassFish Server.
■
Recompile ConverterBean.java using Maven.
a.
In a terminal window, go to the tut-install/examples/ejb/converter/
directory.
b.
Enter the following command:
mvn install
This command repackages and deploys the application.
33-4 The Java EE 7 Tutorial
34
Running the Enterprise Bean Examples
34
This chapter describes the EJB examples. Session beans provide a simple but powerful
way to encapsulate business logic within an application. They can be accessed from
remote Java clients, web service clients, and components running in the same server.
In Chapter 33, "Getting Started with Enterprise Beans", you built a stateless session
bean named ConverterBean. This chapter examines the source code of four more
session beans:
■
CartBean: a stateful session bean that is accessed by a remote client
■
CounterBean: a singleton session bean
■
HelloServiceBean: a stateless session bean that implements a web service
■
TimerSessionBean: a stateless session bean that sets a timer
The following topics are addressed here:
■
The cart Example
■
A Singleton Session Bean Example: counter
■
A Web Service Example: helloservice
■
Using the Timer Service
■
Handling Exceptions
34.1 The cart Example
The cart example represents a shopping cart in an online bookstore and uses a stateful
session bean to manage the operations of the shopping cart. The bean's client can add
a book to the cart, remove a book, or retrieve the cart's contents. To assemble cart, you
need the following code:
■
Session bean class (CartBean)
■
Remote business interface (Cart)
All session beans require a session bean class. All enterprise beans that permit remote
access must have a remote business interface. To meet the needs of a specific
application, an enterprise bean may also need some helper classes. The CartBean
session bean uses two helper classes, BookException and IdVerifier, which are
discussed in the section Helper Classes.
The source code for this example is in the tut-install/examples/ejb/cart/ directory.
Running the Enterprise Bean Examples 34-1
The cart Example
34.1.1 The Business Interface
The Cart business interface is a plain Java interface that defines all the business
methods implemented in the bean class. If the bean class implements a single interface,
that interface is assumed to the business interface. The business interface is a local
interface unless it is annotated with the javax.ejb.Remote annotation; the
javax.ejb.Local annotation is optional in this case.
The bean class may implement more than one interface. In that case, the business
interfaces must either be explicitly annotated @Local or @Remote or be specified by
decorating the bean class with @Local or @Remote. However, the following interfaces
are excluded when determining whether the bean class implements more than one
interface:
■
java.io.Serializable
■
java.io.Externalizable
■
Any of the interfaces defined by the javax.ejb package
The source code for the Cart business interface is as follows:
package javaeetutorial.cart.ejb;
import cart.util.BookException;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface Cart {
public void initialize(String person) throws BookException;
public void initialize(String person, String id) throws BookException;
public void addBook(String title);
public void removeBook(String title) throws BookException;
public List<String> getContents();
public void remove();
}
34.1.2 Session Bean Class
The session bean class for this example is called CartBean. Like any stateful session
bean, the CartBean class must meet the following requirements.
■
The class is annotated @Stateful.
■
The class implements the business methods defined in the business interface.
Stateful session beans may also do the following.
■
■
■
Implement the business interface, a plain Java interface. It is good practice to
implement the bean's business interface.
Implement any optional lifecycle callback methods, annotated @PostConstruct,
@PreDestroy, @PostActivate, and @PrePassivate.
Implement any optional business methods annotated @Remove.
The source code for the CartBean class is as follows:
package javaeetutorial.cart.ejb;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
34-2 The Java EE 7 Tutorial
The cart Example
import
import
import
import
javaeetutorial.cart.util.BookException;
javaeetutorial.cart.util.IdVerifier;
javax.ejb.Remove;
javax.ejb.Stateful;
@Stateful
public class CartBean implements Cart {
String customerId;
String customerName;
List<String> contents;
@Override
public void initialize(String person) throws BookException {
if (person == null) {
throw new BookException("Null person not allowed.");
} else {
customerName = person;
}
customerId = "0";
contents = new ArrayList<>();
}
@Override
public void initialize(String person, String id)
throws BookException {
if (person == null) {
throw new BookException("Null person not allowed.");
} else {
customerName = person;
}
IdVerifier idChecker = new IdVerifier();
if (idChecker.validate(id)) {
customerId = id;
} else {
throw new BookException("Invalid id: " + id);
}
contents = new ArrayList<>();
}
@Override
public void addBook(String title) {
contents.add(title);
}
@Override
public void removeBook(String title) throws BookException {
boolean result = contents.remove(title);
if (result == false) {
throw new BookException("\"" + title + " not in cart.");
}
}
@Override
public List<String> getContents() {
return contents;
}
@Remove
Running the Enterprise Bean Examples 34-3
The cart Example
@Override
public void remove() {
contents = null;
}
}
34.1.2.1 Lifecycle Callback Methods
A method in the bean class may be declared as a lifecycle callback method by
annotating the method with the following annotations.
■
■
■
■
javax.annotation.PostConstruct: Methods annotated with @PostConstruct are
invoked by the container on newly constructed bean instances after all
dependency injection has completed and before the first business method is
invoked on the enterprise bean.
javax.annotation.PreDestroy: Methods annotated with @PreDestroy are
invoked after any method annotated @Remove has completed and before the
container removes the enterprise bean instance.
javax.ejb.PostActivate: Methods annotated with @PostActivate are invoked by
the container after the container moves the bean from secondary storage to active
status.
javax.ejb.PrePassivate: Methods annotated with @PrePassivate are invoked by
the container before it passivates the enterprise bean, meaning that the container
temporarily removes the bean from the environment and saves it to secondary
storage.
Lifecycle callback methods must return void and have no parameters.
34.1.2.2 Business Methods
The primary purpose of a session bean is to run business tasks for the client. The client
invokes business methods on the object reference it gets from dependency injection or
JNDI lookup. From the client's perspective, the business methods appear to run locally,
although they run remotely in the session bean. The following code snippet shows
how the CartClient program invokes the business methods:
cart.initialize("Duke DeEarl", "123");
...
cart.addBook("Bel Canto");
...
List<String> bookList = cart.getContents();
...
cart.removeBook("Gravity's Rainbow");
The CartBean class implements the business methods in the following code:
@Override
public void addBook(String title) {
contents.add(title);
}
@Override
public void removeBook(String title) throws BookException {
boolean result = contents.remove(title);
if (result == false) {
throw new BookException("\"" + title + "not in cart.");
}
}
34-4 The Java EE 7 Tutorial
The cart Example
@Override
public List<String> getContents() {
return contents;
}
The signature of a business method must conform to these rules.
■
■
■
■
■
■
The method name must not begin with ejb, to avoid conflicts with callback
methods defined by the EJB architecture. For example, you cannot call a business
method ejbCreate or ejbActivate.
The access control modifier must be public.
If the bean allows remote access through a remote business interface, the
arguments and return types must be legal types for the Java Remote Method
Invocation (RMI) API.
If the bean is a JAX-WS web service endpoint, the arguments and return types for
the methods annotated @WebMethod must be legal types for JAX-WS.
If the bean is a JAX-RS resource, the arguments and return types for the resource
methods must be legal types for JAX-RS.
The modifier must not be static or final.
The throws clause can include exceptions that you define for your application. The
removeBook method, for example, throws a BookException if the book is not in the
cart.
To indicate a system-level problem, such as the inability to connect to a database, a
business method should throw a javax.ejb.EJBException. The container will not
wrap application exceptions, such as BookException. Because EJBException is a
subclass of RuntimeException, you do not need to include it in the throws clause of the
business method.
34.1.3 The @Remove Method
Business methods annotated with javax.ejb.Remove in the stateful session bean class
can be invoked by enterprise bean clients to remove the bean instance. The container
will remove the enterprise bean after a @Remove method completes, either normally or
abnormally.
In CartBean, the remove method is a @Remove method:
@Remove
@Override
public void remove() {
contents = null;
}
34.1.4 Helper Classes
The CartBean session bean has two helper classes: BookException and IdVerifier.
The BookException is thrown by the removeBook method, and the IdVerifier
validates the customerId in one of the create methods. Helper classes may reside in
an EJB JAR file that contains the enterprise bean class; a WAR file if the enterprise bean
is packaged within a WAR; or an EAR file that contains an EJB JAR, a WAR file, or a
separate library JAR file. In cart, the helper classes are included in a library JAR used
by the application client and the EJB JAR.
Running the Enterprise Bean Examples 34-5
The cart Example
34.1.5 Running the cart Example
Now you are ready to compile the remote interface (Cart.java), the enterprise bean
class (CartBean.java), the client class (CartClient.java), and the helper classes
(BookException.java and IdVerifier.java).
You can use either NetBeans IDE or Maven to build, package, deploy, and run the cart
application.
34.1.5.1 To Run the cart Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/ejb
4.
Select the cart folder.
5.
Select the Open Required Projects check box.
6.
Click Open Project.
7.
In the Projects tab, right-click the cart project and select Build.
This builds and packages the application into cart.ear, located in
tut-install/examples/ejb/cart/cart-ear/target/, and deploys this EAR file to
your GlassFish Server instance.
You will see the output of the cart-app-client application client in the Output
tab:
...
Retrieving book title from cart: Infinite Jest
Retrieving book title from cart: Bel Canto
Retrieving book title from cart: Kafka on the Shore
Removing "Gravity's Rainbow" from cart.
Caught a BookException: "Gravity's Rainbow" not in cart.
34.1.5.2 To Run the cart Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/ejb/cart/
3.
Enter the following command:
mvn install
This command compiles and packages the application into an EAR file, cart.ear,
located in the target directory, and deploys the EAR to your GlassFish Server
instance.
Then, the client stubs are retrieved and run. This is equivalent to running the
following command:
appclient -client cart-ear/target/cart-earClient.jar
34-6 The Java EE 7 Tutorial
A Singleton Session Bean Example: counter
The client JAR, cart-earClient.jar, contains the application client class, the
helper class BookException, and the Cart business interface.
When you run the client, the application client container injects any component
references declared in the application client class, in this case the reference to the
Cart enterprise bean.
You will see the output of the cart-app-client application client in the terminal
window:
...
Retrieving book title from cart: Infinite Jest
Retrieving book title from cart: Bel Canto
Retrieving book title from cart: Kafka on the Shore
Removing "Gravity's Rainbow" from cart.
Caught a BookException: "Gravity's Rainbow" not in cart.
34.2 A Singleton Session Bean Example: counter
The counter example demonstrates how to create a singleton session bean.
34.2.1 Creating a Singleton Session Bean
The javax.ejb.Singleton annotation is used to specify that the enterprise bean
implementation class is a singleton session bean:
@Singleton
public class SingletonBean { ... }
34.2.1.1 Initializing Singleton Session Beans
The EJB container is responsible for determining when to initialize a singleton session
bean instance unless the singleton session bean implementation class is annotated with
the javax.ejb.Startup annotation. In this case, sometimes called eager initialization,
the EJB container must initialize the singleton session bean upon application startup.
The singleton session bean is initialized before the EJB container delivers client
requests to any enterprise beans in the application. This allows the singleton session
bean to perform, for example, application startup tasks.
The following singleton session bean stores the status of an application and is eagerly
initialized:
@Startup
@Singleton
public class StatusBean {
private String status;
@PostConstruct
void init {
status = "Ready";
}
...
}
Sometimes multiple singleton session beans are used to initialize data for an
application and therefore must be initialized in a specific order. In these cases, use the
javax.ejb.DependsOn annotation to declare the startup dependencies of the singleton
session bean. The @DependsOn annotation's value attribute is one or more strings that
specify the name of the target singleton session bean. If more than one dependent
singleton bean is specified in @DependsOn, the order in which they are listed is not
Running the Enterprise Bean Examples 34-7
A Singleton Session Bean Example: counter
necessarily the order in which the EJB container will initialize the target singleton
session beans.
The following singleton session bean, PrimaryBean, should be started up first:
@Singleton
public class PrimaryBean { ... }
SecondaryBean depends on PrimaryBean:
@Singleton
@DependsOn("PrimaryBean")
public class SecondaryBean { ... }
This guarantees that the EJB container will initialize PrimaryBean before
SecondaryBean.
The following singleton session bean, TertiaryBean, depends on PrimaryBean and
SecondaryBean:
@Singleton
@DependsOn({"PrimaryBean", "SecondaryBean"})
public class TertiaryBean { ... }
SecondaryBean explicitly requires PrimaryBean to be initialized before it is initialized,
through its own @DependsOn annotation. In this case, the EJB container will first
initialize PrimaryBean, then SecondaryBean, and finally TertiaryBean.
If, however, SecondaryBean did not explicitly depend on PrimaryBean, the EJB
container may initialize either PrimaryBean or SecondaryBean first. That is, the EJB
container could initialize the singletons in the following order: SecondaryBean,
PrimaryBean, TertiaryBean.
34.2.1.2 Managing Concurrent Access in a Singleton Session Bean
Singleton session beans are designed for concurrent access, situations in which many
clients need to access a single instance of a session bean at the same time. A singleton's
client needs only a reference to a singleton in order to invoke any business methods
exposed by the singleton and doesn't need to worry about any other clients that may
be simultaneously invoking business methods on the same singleton.
When creating a singleton session bean, concurrent access to the singleton's business
methods can be controlled in two ways: container-managed concurrency and
bean-managed concurrency.
The javax.ejb.ConcurrencyManagement annotation is used to specify
container-managed or bean-managed concurrency for the singleton. With
@ConcurrencyManagement, a type attribute must be set to either
javax.ejb.ConcurrencyManagementType.CONTAINER or
javax.ejb.ConcurrencyManagementType.BEAN. If no @ConcurrencyManagement
annotation is present on the singleton implementation class, the EJB container default
of container-managed concurrency is used.
Container-Managed Concurrency
If a singleton uses container-managed concurrency, the EJB container controls client
access to the business methods of the singleton. The javax.ejb.Lock annotation and a
javax.ejb.LockType type are used to specify the access level of the singleton's
business methods or @Timeout methods. The LockType enumerated types are READ and
WRITE.
34-8 The Java EE 7 Tutorial
A Singleton Session Bean Example: counter
Annotate a singleton's business or timeout method with @Lock(LockType.READ) if the
method can be concurrently accessed, or shared, with many clients. Annotate the
business or timeout method with @Lock(LockType.WRITE) if the singleton session bean
should be locked to other clients while a client is calling that method. Typically, the
@Lock(LockType.WRITE) annotation is used when clients are modifying the state of the
singleton.
Annotating a singleton class with @Lock specifies that all the business methods and
any timeout methods of the singleton will use the specified lock type unless they
explicitly set the lock type with a method-level @Lock annotation. If no @Lock
annotation is present on the singleton class, the default lock type,
@Lock(LockType.WRITE), is applied to all business and timeout methods.
The following example shows how to use the @ConcurrencyManagement,
@Lock(LockType.READ), and @Lock(LockType.WRITE) annotations for a singleton that
uses container-managed concurrency.
Although by default singletons use container-managed concurrency, the
@ConcurrencyManagement(CONTAINER) annotation may be added at the class level of
the singleton to explicitly set the concurrency management type:
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@Singleton
public class ExampleSingletonBean {
private String state;
@Lock(LockType.READ)
public String getState() {
return state;
}
@Lock(LockType.WRITE)
public void setState(String newState) {
state = newState;
}
}
The getState method can be accessed by many clients at the same time because it is
annotated with @Lock(LockType.READ). When the setState method is called,
however, all the methods in ExampleSingletonBean will be locked to other clients
because setState is annotated with @Lock(LockType.WRITE). This prevents two
clients from attempting to simultaneously change the state variable of
ExampleSingletonBean.
The getData and getStatus methods in the following singleton are of type READ, and
the setStatus method is of type WRITE:
@Singleton
@Lock(LockType.READ)
public class SharedSingletonBean {
private String data;
private String status;
public String getData() {
return data;
}
public String getStatus() {
return status;
}
Running the Enterprise Bean Examples 34-9
A Singleton Session Bean Example: counter
@Lock(LockType.WRITE)
public void setStatus(String newStatus) {
status = newStatus;
}
}
If a method is of locking type WRITE, client access to all the singleton's methods is
blocked until the current client finishes its method call or an access timeout occurs.
When an access timeout occurs, the EJB container throws a
javax.ejb.ConcurrentAccessTimeoutException. The javax.ejb.AccessTimeout
annotation is used to specify the number of milliseconds before an access timeout
occurs. If added at the class level of a singleton, @AccessTimeout specifies the access
timeout value for all methods in the singleton unless a method explicitly overrides the
default with its own @AccessTimeout annotation.
The @AccessTimeout annotation can be applied to both @Lock(LockType.READ) and
@Lock(LockType.WRITE) methods. The @AccessTimeout annotation has one required
element, value, and one optional element, unit. By default, the value is specified in
milliseconds. To change the value unit, set unit to one of the
java.util.concurrent.TimeUnit constants: NANOSECONDS, MICROSECONDS,
MILLISECONDS, or SECONDS.
The following singleton has a default access timeout value of 120,000 milliseconds, or 2
minutes. The doTediousOperation method overrides the default access timeout and
sets the value to 360,000 milliseconds, or 6 minutes:
@Singleton
@AccessTimeout(value=120000)
public class StatusSingletonBean {
private String status;
@Lock(LockType.WRITE)
public void setStatus(String new Status) {
status = newStatus;
}
@Lock(LockType.WRITE)
@AccessTimeout(value=360000)
public void doTediousOperation {
...
}
}
The following singleton has a default access timeout value of 60 seconds, specified
using the TimeUnit.SECONDS constant:
@Singleton
@AccessTimeout(value=60, unit=TimeUnit.SECONDS)
public class StatusSingletonBean { ... }
Bean-Managed Concurrency
Singletons that use bean-managed concurrency allow full concurrent access to all the
business and timeout methods in the singleton. The developer of the singleton is
responsible for ensuring that the state of the singleton is synchronized across all
clients. Developers who create singletons with bean-managed concurrency are allowed
to use the Java programming language synchronization primitives, such as
synchronization and volatile, to prevent errors during concurrent access.
34-10 The Java EE 7 Tutorial
A Singleton Session Bean Example: counter
Add a @ConcurrencyManagement annotation with the type set to
ConcurrencyManagementType.BEAN at the class level of the singleton to specify
bean-managed concurrency:
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
@Singleton
public class AnotherSingletonBean { ... }
34.2.1.3 Handling Errors in a Singleton Session Bean
If a singleton session bean encounters an error when initialized by the EJB container,
that singleton instance will be destroyed.
Unlike other enterprise beans, once a singleton session bean instance is initialized, it is
not destroyed if the singleton's business or lifecycle methods cause system exceptions.
This ensures that the same singleton instance is used throughout the application
lifecycle.
34.2.2 The Architecture of the counter Example
The counter example consists of a singleton session bean, CounterBean, and a
JavaServer Faces Facelets web front end.
CounterBean is a simple singleton with one method, getHits, that returns an integer
representing the number of times a web page has been accessed. Here is the code of
CounterBean:
package javaeetutorial.counter.ejb;
import javax.ejb.Singleton;
/**
* CounterBean is a simple singleton session bean that records the number
* of hits to a web page.
*/
@Singleton
public class CounterBean {
private int hits = 1;
// Increment and return the number of hits
public int getHits() {
return hits++;
}
}
The @Singleton annotation marks CounterBean as a singleton session bean.
CounterBean uses a local, no-interface view.
CounterBean uses the EJB container's default metadata values for singletons to
simplify the coding of the singleton implementation class. There is no
@ConcurrencyManagement annotation on the class, so the default of container-managed
concurrency access is applied. There is no @Lock annotation on the class or business
method, so the default of @Lock(WRITE) is applied to the only business method,
getHits.
The following version of CounterBean is functionally equivalent to the preceding
version:
package javaeetutorial.counter.ejb;
import javax.ejb.Singleton;
Running the Enterprise Bean Examples 34-11
A Singleton Session Bean Example: counter
import
import
import
import
javax.ejb.ConcurrencyManagement;
static javax.ejb.ConcurrencyManagementType.CONTAINER;
javax.ejb.Lock;
javax.ejb.LockType.WRITE;
/**
* CounterBean is a simple singleton session bean that records the number
* of hits to a web page.
*/
@Singleton
@ConcurrencyManagement(CONTAINER)
public class CounterBean {
private int hits = 1;
// Increment and return the number of hits
@Lock(WRITE)
public int getHits() {
return hits++;
}
}
The web front end of counter consists of a JavaServer Faces managed bean,
Count.java, that is used by the Facelets XHTML files template.xhtml and
index.xhtml. The Count JavaServer Faces managed bean obtains a reference to
CounterBean through dependency injection. Count defines a hitCount JavaBeans
property. When the getHitCount getter method is called from the XHTML files,
CounterBean's getHits method is called to return the current number of page hits.
Here's the Count managed bean class:
@Named
@ConversationScoped
public class Count implements Serializable {
@EJB
private CounterBean counterBean;
private int hitCount;
public Count() {
this.hitCount = 0;
}
public int getHitCount() {
hitCount = counterBean.getHits();
return hitCount;
}
public void setHitCount(int newHits) {
this.hitCount = newHits;
}
}
The template.xhtml and index.xhtml files are used to render a Facelets view that
displays the number of hits to that view. The index.xhtml file uses an expression
language statement, #{count.hitCount}, to access the hitCount property of the Count
managed bean. Here is the content of index.xhtml:
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html">
34-12 The Java EE 7 Tutorial
A Web Service Example: helloservice
<ui:composition template="/template.xhtml">
<ui:define name="title">
This page has been accessed #{count.hitCount} time(s).
</ui:define>
<ui:define name="body">
Hooray!
</ui:define>
</ui:composition>
</html>
34.2.3 Running the counter Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
counter example.
34.2.3.1 To Run the counter Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/ejb
4.
Select the counter folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the counter project and select Run.
A web browser will open the URL http://localhost:8080/counter, which
displays the number of hits.
7.
Reload the page to see the hit count increment.
34.2.3.2 To Run the counter Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/ejb/counter/
3.
Enter the following command:
mvn install
This will build and deploy counter to your GlassFish Server instance.
4.
In a web browser, enter the following URL:
http://localhost:8080/counter
5.
Reload the page to see the hit count increment.
34.3 A Web Service Example: helloservice
This example demonstrates a simple web service that generates a response based on
information received from the client. HelloServiceBean is a stateless session bean that
implements a single method: sayHello. This method matches the sayHello method
Running the Enterprise Bean Examples 34-13
A Web Service Example: helloservice
invoked by the client described in A Simple JAX-WS Application Client.
34.3.1 The Web Service Endpoint Implementation Class
HelloServiceBean is the endpoint implementation class, typically the primary
programming artifact for enterprise bean web service endpoints. The web service
endpoint implementation class has the following requirements.
■
■
■
■
■
The class must be annotated with either the javax.jws.WebService or the
javax.jws.WebServiceProvider annotation.
The implementing class may explicitly reference an SEI through the
endpointInterface element of the @WebService annotation but is not required to
do so. If no endpointInterface is specified in @WebService, an SEI is implicitly
defined for the implementing class.
The business methods of the implementing class must be public and must not be
declared static or final.
Business methods that are exposed to web service clients must be annotated with
javax.jws.WebMethod.
Business methods that are exposed to web service clients must have
JAXB-compatible parameters and return types. See the list of JAXB default data
type bindings at Types Supported by JAX-WS.
■
The implementing class must not be declared final and must not be abstract.
■
The implementing class must have a default public constructor.
■
The endpoint class must be annotated @Stateless.
■
The implementing class must not define the finalize method.
■
The implementing class may use the javax.annotation.PostConstruct or
javax.annotation.PreDestroy annotations on its methods for lifecycle event
callbacks.
The @PostConstruct method is called by the container before the implementing
class begins responding to web service clients.
The @PreDestroy method is called by the container before the endpoint is removed
from operation.
34.3.2 Stateless Session Bean Implementation Class
The HelloServiceBean class implements the sayHello method, which is annotated
@WebMethod. The source code for the HelloServiceBean class is as follows:
package javaeetutorial.helloservice.ejb;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;
@Stateless
@WebService
public class HelloServiceBean {
private final String message = "Hello, ";
public void HelloServiceBean() {}
@WebMethod
34-14 The Java EE 7 Tutorial
A Web Service Example: helloservice
public String sayHello(String name) {
return message + name + ".";
}
}
34.3.3 Running the helloservice Example
You can use either NetBeans IDE or Maven to build, package, and deploy the
helloservice example. You can then use the Administration Console to test the web
service endpoint methods.
34.3.3.1 To Build, Package, and Deploy the helloservice Example Using NetBeans
IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/ejb
4.
Select the helloservice folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the helloservice project and select Build.
This builds and packages the application into helloservice.ear, located in
tut-install/examples/ejb/helloservice/target/, and deploys this EAR file to
GlassFish Server.
34.3.3.2 To Build, Package, and Deploy the helloservice Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/ejb/helloservice/
3.
Enter the following command:
mvn install
This compiles the source files and packages the application into an EJB JAR file
located at tut-install/examples/ejb/helloservice/target/helloservice.jar.
Then the EJB JAR file is deployed to GlassFish Server.
Upon deployment, GlassFish Server generates additional artifacts required for
web service invocation, including the WSDL file.
34.3.3.3 To Test the Service without a Client
The GlassFish Server Administration Console allows you to test the methods of a web
service endpoint. To test the sayHello method of HelloServiceBean, follow these
steps.
1.
Open the Administration Console by opening the following URL in a web
browser:
http://localhost:4848/
Running the Enterprise Bean Examples 34-15
Using the Timer Service
2.
In the navigation tree, select the Applications node.
3.
In the Applications table, click the helloservice link.
4.
In the Modules and Components table, click the View Endpoint link.
5.
On the Web Service Endpoint Information page, click the Tester link:
/HelloServiceBeanService/HelloServiceBean?Tester
6.
On the Web Service Test Links page, click the non-secure link (the one that
specifies port 8080).
7.
On the HelloServiceBeanService Web Service Tester page, under Methods, enter a
name as the parameter to the sayHello method.
8.
Click sayHello.
The sayHello Method invocation page opens. Under Method returned, you'll see
the response from the endpoint.
34.4 Using the Timer Service
Applications that model business work flows often rely on timed notifications. The
timer service of the enterprise bean container enables you to schedule timed
notifications for all types of enterprise beans except for stateful session beans. You can
schedule a timed notification to occur according to a calendar schedule, at a specific
time, after a duration of time, or at timed intervals. For example, you could set timers
to go off at 10:30 a.m. on May 23, in 30 days, or every 12 hours.
Enterprise bean timers are either programmatic timers or automatic timers.
Programmatic timers are set by explicitly calling one of the timer creation methods of
the TimerService interface. Automatic timers are created upon the successful
deployment of an enterprise bean that contains a method annotated with the
javax.ejb.Schedule or javax.ejb.Schedules annotations.
34.4.1 Creating Calendar-Based Timer Expressions
Timers can be set according to a calendar-based schedule, expressed using a syntax
similar to the UNIX cron utility. Both programmatic and automatic timers can use
calendar-based timer expressions. Table 34–1 shows the calendar-based timer
attributes.
Table 34–1
Calendar-Based Timer Attributes
Attribute
Description
second
Default
Value
Allowable Values and Examples
One or more
seconds within a
minute
0
0 to 59. For example: second="30".
minute
One or more
minutes within an
hour
0
0 to 59. For example: minute="15".
hour
One or more hours
within a day
0
0 to 23. For example: hour="13".
34-16 The Java EE 7 Tutorial
Using the Timer Service
Table 34–1 (Cont.) Calendar-Based Timer Attributes
Attribute
Description
dayOfWeek
One or more days
within a week
Default
Value
*
Allowable Values and Examples
0 to 7 (both 0 and 7 refer to Sunday). For
example: dayOfWeek="3".
Sun, Mon, Tue, Wed, Thu, Fri, Sat. For example:
dayOfWeek="Mon".
dayOfMonth
One or more days
within a month
*
1 to 31. For example: dayOfMonth="15".
–7 to –1 (a negative number means the nth
day or days before the end of the month). For
example: dayOfMonth="–3".
Last. For example: dayOfMonth="Last".
[1st, 2nd, 3rd, 4th, 5th, Last] [Sun, Mon, Tue,
Wed, Thu, Fri, Sat]. For example:
dayOfMonth="2nd Fri".
month
year
One or more
months within a
year
*
A particular
calendar year
*
1 to 12. For example: month="7".
Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct,
Nov, Dec. For example: month="July".
A four-digit calendar year. For example:
year="2011".
34.4.1.1 Specifying Multiple Values in Calendar Expressions
You can specify multiple values in calendar expressions, as described in the following
sections.
Using Wildcards in Calendar Expressions
Setting an attribute to an asterisk symbol (*) represents all allowable values for the
attribute.
The following expression represents every minute:
minute="*"
The following expression represents every day of the week:
dayOfWeek="*"
Specifying a List of Values
To specify two or more values for an attribute, use a comma (,) to separate the values.
A range of values is allowed as part of a list. Wildcards and intervals, however, are not
allowed.
Duplicates within a list are ignored.
The following expression sets the day of the week to Tuesday and Thursday:
dayOfWeek="Tue, Thu"
The following expression represents 4:00 a.m., every hour from 9:00 a.m. to 5:00 p.m.
using a range, and 10:00 p.m.:
hour="4,9-17,22"
Specifying a Range of Values
Use a dash character (-) to specify an inclusive range of values for an attribute.
Members of a range cannot be wildcards, lists, or intervals. A range of the form x-x, is
Running the Enterprise Bean Examples 34-17
Using the Timer Service
equivalent to the single-valued expression x. A range of the form x-y where x is
greater than y is equivalent to the expression x-maximumvalue, minimumvalue-y. That
is, the expression begins at x, rolls over to the beginning of the allowable values, and
continues up to y.
The following expression represents 9:00 a.m. to 5:00 p.m.:
hour="9-17"
The following expression represents Friday through Monday:
dayOfWeek="5-1"
The following expression represents the twenty-fifth day of the month to the end of
the month, and the beginning of the month to the fifth day of the month:
dayOfMonth="25-5"
It is equivalent to the following expression:
dayOfMonth="25-Last,1-5"
Specifying Intervals
The forward slash (/) constrains an attribute to a starting point and an interval and is
used to specify every N seconds, minutes, or hours within the minute, hour, or day. For
an expression of the form x/y, x represents the starting point and y represents the
interval. The wildcard character may be used in the x position of an interval and is
equivalent to setting x to 0.
Intervals may be set only for second, minute, and hour attributes.
The following expression represents every 10 minutes within the hour:
minute="*/10"
It is equivalent to:
minute="0,10,20,30,40,50"
The following expression represents every 2 hours starting at noon:
hour="12/2"
34.4.2 Programmatic Timers
When a programmatic timer expires (goes off), the container calls the method
annotated @Timeout in the bean's implementation class. The @Timeout method contains
the business logic that handles the timed event.
34.4.2.1 The @Timeout Method
Methods annotated @Timeout in the enterprise bean class must return void and
optionally take a javax.ejb.Timer object as the only parameter. They may not throw
application exceptions:
@Timeout
public void timeout(Timer timer) {
System.out.println("TimerBean: timeout occurred");
}
34-18 The Java EE 7 Tutorial
Using the Timer Service
34.4.2.2 Creating Programmatic Timers
To create a timer, the bean invokes one of the create methods of the TimerService
interface. These methods allow single-action, interval, or calendar-based timers to be
created.
For single-action or interval timers, the expiration of the timer can be expressed as
either a duration or an absolute time. The duration is expressed as a the number of
milliseconds before a timeout event is triggered. To specify an absolute time, create a
java.util.Date object and pass it to the TimerService.createSingleActionTimer or
the TimerService.createTimer method.
The following code sets a programmatic timer that will expire in 1 minute (60,000
milliseconds):
long duration = 60000;
Timer timer =
timerService.createSingleActionTimer(duration, new TimerConfig());
The following code sets a programmatic timer that will expire at 12:05 p.m. on May 1,
2015, specified as a java.util.Date:
SimpleDateFormatter formatter =
new SimpleDateFormatter("MM/dd/yyyy 'at' HH:mm");
Date date = formatter.parse("05/01/2015 at 12:05");
Timer timer = timerService.createSingleActionTimer(date, new TimerConfig());
For calendar-based timers, the expiration of the timer is expressed as a
javax.ejb.ScheduleExpression object, passed as a parameter to the
TimerService.createCalendarTimer method. The ScheduleExpression class
represents calendar-based timer expressions and has methods that correspond to the
attributes described in Creating Calendar-Based Timer Expressions.
The following code creates a programmatic timer using the ScheduleExpression
helper class:
ScheduleExpression schedule = new ScheduleExpression();
schedule.dayOfWeek("Mon");
schedule.hour("12-17, 23");
Timer timer = timerService.createCalendarTimer(schedule);
For details on the method signatures, see the TimerService API documentation at
http://docs.oracle.com/javaee/7/api/javax/ejb/TimerService.html.
The bean described in The timersession Example creates a timer as follows:
Timer timer = timerService.createTimer(intervalDuration,
"Created new programmatic timer");
In the timersession example, the method that calls createTimer is invoked in a
business method, which is called by a client.
Timers are persistent by default. If the server is shut down or crashes, persistent timers
are saved and will become active again when the server is restarted. If a persistent
timer expires while the server is down, the container will call the @Timeout method
when the server is restarted.
Nonpersistent programmatic timers are created by calling
TimerConfig.setPersistent(false) and passing the TimerConfig object to one of the
timer-creation methods.
The Date and long parameters of the createTimer methods represent time with the
resolution of milliseconds. However, because the timer service is not intended for
Running the Enterprise Bean Examples 34-19
Using the Timer Service
real-time applications, a callback to the @Timeout method might not occur with
millisecond precision. The timer service is for business applications, which typically
measure time in hours, days, or longer durations.
34.4.3 Automatic Timers
Automatic timers are created by the EJB container when an enterprise bean that
contains methods annotated with the @Schedule or @Schedules annotations is
deployed. An enterprise bean can have multiple automatic timeout methods, unlike a
programmatic timer, which allows only one method annotated with the @Timeout
annotation in the enterprise bean class.
Automatic timers can be configured through annotations or through the ejb-jar.xml
deployment descriptor.
Adding a @Schedule annotation on an enterprise bean marks that method as a timeout
method according to the calendar schedule specified in the attributes of @Schedule.
The @Schedule annotation has elements that correspond to the calendar expressions
detailed in Creating Calendar-Based Timer Expressions and the persistent, info, and
timezone elements.
The optional persistent element takes a Boolean value and is used to specify whether
the automatic timer should survive a server restart or crash. By default, all automatic
timers are persistent.
The optional timezone element is used to specify that the automatic timer is associated
with a particular time zone. If set, this element will evaluate all timer expressions in
relation to the specified time zone, regardless of the time zone in which the EJB
container is running. By default, all automatic timers set are in relation to the default
time zone of the server.
The optional info element is used to set an informational description of the timer. A
timer's information can be retrieved later by using Timer.getInfo.
The following timeout method uses @Schedule to set a timer that will expire every
Sunday at midnight:
@Schedule(dayOfWeek="Sun", hour="0")
public void cleanupWeekData() { ... }
The @Schedules annotation is used to specify multiple calendar-based timer
expressions for a given timeout method.
The following timeout method uses the @Schedules annotation to set multiple
calendar-based timer expressions. The first expression sets a timer to expire on the last
day of every month. The second expression sets a timer to expire every Friday at 11:00
p.m.:
@Schedules ({
@Schedule(dayOfMonth="Last"),
@Schedule(dayOfWeek="Fri", hour="23")
})
public void doPeriodicCleanup() { ... }
34.4.4 Canceling and Saving Timers
Timers can be cancelled by the following events.
■
When a single-event timer expires, the EJB container calls the associated timeout
method and then cancels the timer.
34-20 The Java EE 7 Tutorial
Using the Timer Service
■
When the bean invokes the cancel method of the Timer interface, the container
cancels the timer.
If a method is invoked on a cancelled timer, the container throws the
javax.ejb.NoSuchObjectLocalException.
To save a Timer object for future reference, invoke its getHandle method and store the
TimerHandle object in a database. (A TimerHandle object is serializable.) To
reinstantiate the Timer object, retrieve the handle from the database and invoke
getTimer on the handle. A TimerHandle object cannot be passed as an argument of a
method defined in a remote or web service interface. In other words, remote clients
and web service clients cannot access a bean's TimerHandle object. Local clients,
however, do not have this restriction.
34.4.5 Getting Timer Information
In addition to defining the cancel and getHandle methods, the Timer interface defines
methods for obtaining information about timers:
public long getTimeRemaining();
public java.util.Date getNextTimeout();
public java.io.Serializable getInfo();
The getInfo method returns the object that was the last parameter of the createTimer
invocation. For example, in the createTimer code snippet of the preceding section, this
information parameter is a String object with the value created timer.
To retrieve all of a bean's active timers, call the getTimers method of the TimerService
interface. The getTimers method returns a collection of Timer objects.
34.4.6 Transactions and Timers
An enterprise bean usually creates a timer within a transaction. If this transaction is
rolled back, the timer creation also is rolled back. Similarly, if a bean cancels a timer
within a transaction that gets rolled back, the timer cancellation is rolled back. In this
case, the timer's duration is reset as if the cancellation had never occurred.
In beans that use container-managed transactions, the @Timeout method usually has
the Required or RequiresNew transaction attribute to preserve transaction integrity.
With these attributes, the EJB container begins the new transaction before calling the
@Timeout method. If the transaction is rolled back, the container will call the @Timeout
method at least one more time.
34.4.7 The timersession Example
The source code for this example is in the
tut-install/examples/ejb/timersession/src/main/java/ directory.
TimerSessionBean is a singleton session bean that shows how to set both an automatic
timer and a programmatic timer. In the source code listing of TimerSessionBean that
follows, the setTimer and @Timeout methods are used to set a programmatic timer. A
TimerService instance is injected by the container when the bean is created. Because
it's a business method, setTimer is exposed to the local, no-interface view of
TimerSessionBean and can be invoked by the client. In this example, the client invokes
setTimer with an interval duration of 8,000 milliseconds, or 8 seconds. The setTimer
method creates a new timer by invoking the createTimer method of TimerService.
Now that the timer is set, the EJB container will invoke the programmaticTimeout
method of TimerSessionBean when the timer expires, in about 8 seconds:
Running the Enterprise Bean Examples 34-21
Using the Timer Service
...
public void setTimer(long intervalDuration) {
logger.log(Level.INFO,
"Setting a programmatic timeout for {0} milliseconds from now.",
intervalDuration);
Timer timer = timerService.createTimer(intervalDuration,
"Created new programmatic timer");
}
@Timeout
public void programmaticTimeout(Timer timer) {
this.setLastProgrammaticTimeout(new Date());
logger.info("Programmatic timeout occurred.");
}
...
TimerSessionBean also has an automatic timer and timeout method,
automaticTimeout. The automatic timer is set to expire every 1 minute and is set by
using a calendar-based timer expression in the @Schedule annotation:
...
@Schedule(minute = "*/1", hour = "*", persistent = false)
public void automaticTimeout() {
this.setLastAutomaticTimeout(new Date());
logger.info("Automatic timeout occured");
}
...
TimerSessionBean also has two business methods: getLastProgrammaticTimeout and
getLastAutomaticTimeout. Clients call these methods to get the date and time of the
last timeout for the programmatic timer and automatic timer, respectively.
Here's the source code for the TimerSessionBean class:
package javaeetutorial.timersession.ejb;
import
import
import
import
import
import
import
import
import
import
java.util.Date;
java.util.logging.Level;
java.util.logging.Logger;
javax.annotation.Resource;
javax.ejb.Schedule;
javax.ejb.Singleton;
javax.ejb.Startup;
javax.ejb.Timeout;
javax.ejb.Timer;
javax.ejb.TimerService;
@Singleton
@Startup
public class TimerSessionBean {
@Resource
TimerService timerService;
private Date lastProgrammaticTimeout;
private Date lastAutomaticTimeout;
private static final Logger logger =
Logger.getLogger("timersession.ejb.TimerSessionBean");
public void setTimer(long intervalDuration) {
logger.log(Level.INFO,
34-22 The Java EE 7 Tutorial
Using the Timer Service
"Setting a programmatic timeout for {0} milliseconds from now.",
intervalDuration);
Timer timer = timerService.createTimer(intervalDuration,
"Created new programmatic timer");
}
@Timeout
public void programmaticTimeout(Timer timer) {
this.setLastProgrammaticTimeout(new Date());
logger.info("Programmatic timeout occurred.");
}
@Schedule(minute = "*/1", hour = "*", persistent = false)
public void automaticTimeout() {
this.setLastAutomaticTimeout(new Date());
logger.info("Automatic timeout occured");
}
public String getLastProgrammaticTimeout() {
if (lastProgrammaticTimeout != null) {
return lastProgrammaticTimeout.toString();
} else {
return "never";
}
}
public void setLastProgrammaticTimeout(Date lastTimeout) {
this.lastProgrammaticTimeout = lastTimeout;
}
public String getLastAutomaticTimeout() {
if (lastAutomaticTimeout != null) {
return lastAutomaticTimeout.toString();
} else {
return "never";
}
}
public void setLastAutomaticTimeout(Date lastAutomaticTimeout) {
this.lastAutomaticTimeout = lastAutomaticTimeout;
}
}
GlassFish Server has a default minimum timeout value of
1,000 milliseconds, or 1 second. If you need to set the timeout value
lower than 1,000 milliseconds, change the value of the Minimum
Delivery Interval setting in the Administration Console. To modify
the minimum timeout value, in the Administration Console expand
Configurations, then expand server-config, select EJB Container,
and click the EJB Timer Service tab. Enter a new timeout value
under Minimum Delivery Interval and click Save. The lowest
practical value for minimum-delivery-interval-in-millis is
around 10 milliseconds, owing to virtual machine constraints.
Note:
34.4.8 Running the timersession Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
timersession example.
Running the Enterprise Bean Examples 34-23
Handling Exceptions
34.4.8.1 To Run the timersession Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/ejb
4.
Select the timersession folder.
5.
Click Open Project.
6.
From the Run menu, choose Run Project.
This builds and packages the application into a WAR file located at
tut-install/examples/ejb/timersession/target/timersession.war, deploys this
WAR file to your GlassFish Server instance, and then runs the web client.
34.4.8.2 To Build, Package, and Deploy the timersession Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/ejb/timersession/
3.
Enter the following command:
mvn install
This builds and packages the application into a WAR file located at
tut-install/examples/ejb/timersession/target/timersession.war and deploys
this WAR file to your GlassFish Server instance.
34.4.8.3 To Run the Web Client
1.
Open a web browser to the following URL:
http://localhost:8080/timersession
2.
Click Set Timer to set a programmatic timer.
3.
Wait for a while and click the browser's Refresh button.
You will see the date and time of the last programmatic and automatic timeouts.
To see the messages that are logged when a timeout occurs, open the server.log
file located in domain-dir/logs/.
34.5 Handling Exceptions
The exceptions thrown by enterprise beans fall into two categories: system and
application.
A system exception indicates a problem with the services that support an application.
For example, a connection to an external resource cannot be obtained, or an injected
resource cannot be found. If it encounters a system-level problem, your enterprise
bean should throw a javax.ejb.EJBException. Because the EJBException is a
subclass of RuntimeException, you do not have to specify it in the throws clause of the
method declaration. If a system exception is thrown, the EJB container might destroy
34-24 The Java EE 7 Tutorial
Handling Exceptions
the bean instance. Therefore, a system exception cannot be handled by the bean's client
program, but instead requires intervention by a system administrator.
An application exception signals an error in the business logic of an enterprise bean.
Application exceptions are typically exceptions that you've coded yourself, such as the
BookException thrown by the business methods of the CartBean example. When an
enterprise bean throws an application exception, the container does not wrap it in
another exception. The client should be able to handle any application exception it
receives.
If a system exception occurs within a transaction, the EJB container rolls back the
transaction. However, if an application exception is thrown within a transaction, the
container does not roll back the transaction.
Running the Enterprise Bean Examples 34-25
Handling Exceptions
34-26 The Java EE 7 Tutorial
35
Using the Embedded Enterprise Bean
Container
35
This chapter demonstrates how to use the embedded enterprise bean container to run
enterprise bean applications in the Java SE environment, outside of a Java EE server.
The following topics are addressed here:
■
Overview of the Embedded Enterprise Bean Container
■
Developing Embeddable Enterprise Bean Applications
■
The standalone Example Application
35.1 Overview of the Embedded Enterprise Bean Container
The embedded enterprise bean container is used to access enterprise bean components
from client code executed in a Java SE environment. The container and the client code
are executed within the same virtual machine. The embedded enterprise bean
container is typically used for testing enterprise beans without having to deploy them
to a server.
Most of the services present in the enterprise bean container in a Java EE server are
available in the embedded enterprise bean container, including injection,
container-managed transactions, and security. Enterprise bean components execute
similarly in both embedded and Java EE environments, and therefore the same
enterprise bean can be easily reused in both standalone and networked applications.
35.2 Developing Embeddable Enterprise Bean Applications
All embeddable enterprise bean containers support the features listed in Table 35–1.
Table 35–1
Required Enterprise Bean Features in the Embeddable Container
Enterprise Bean Feature
Description
Local session beans
Local and no-interface view stateless, stateful, and singleton
session beans. All method access is synchronous. Session beans
must not be web service endpoints.
Transactions
Container-managed and bean-managed transactions.
Security
Declarative and programmatic security.
Interceptors
Class-level and method-level interceptors for session beans.
Deployment descriptor
The optional ejb-jar.xml deployment descriptor, with the
same overriding rules for the enterprise bean container in Java
EE servers.
Using the Embedded Enterprise Bean Container 35-1
Developing Embeddable Enterprise Bean Applications
Container providers are allowed to support the full set of features in enterprise beans,
but applications that use the embedded container will not be portable if they use
enterprise bean features not listed in Table 35–1, such as the timer service, session
beans as web service endpoints, or remote business interfaces.
35.2.1 Running Embedded Applications
The embedded container, the enterprise bean components, and the client all are
executed in the same virtual machine using the same classpath. As a result, developers
can run an application that uses the embedded container just like a typical Java SE
application, as follows:
java -classpath mySessionBean.jar:containerProviderRuntime.jar:myClient.jar \
com.example.ejb.client.Main
In the above example, mySessionBean.jar is an EJB JAR containing a local stateless
session bean, containerProviderRuntime.jar is a JAR file supplied by the enterprise
bean provider that contains the needed runtime classes for the embedded container,
and myClient.jar is a JAR file containing a Java SE application that calls the business
methods in the session bean through the embedded container.
In GlassFish Server, the runtime JAR that includes the classes for the embedded
container is glassfish-embedded-all.jar.
35.2.2 Creating the Enterprise Bean Container
The javax.ejb.embedded.EJBContainer abstract class represents an instance of the
enterprise bean container and includes factory methods for creating a container
instance. The EJBContainer.createEJBContainer method is used to create and
initialize an embedded container instance.
The following code snippet shows how to create an embedded container that is
initialized with the container provider's default settings:
EJBContainer ec = EJBContainer.createEJBContainer();
By default, the embedded container will search the virtual machine classpath for
enterprise bean modules: directories containing a META-INF/ejb-jar.xml deployment
descriptor, directories containing a class file with one of the enterprise bean
component annotations (such as @Stateless), or JAR files containing an ejb-jar.xml
deployment descriptor or class file with an enterprise bean annotation. Any matching
entries are considered enterprise bean modules within the same application. Once all
the valid enterprise bean modules have been found in the classpath, the container will
begin initializing the modules. When the createEJBContainer method successfully
returns, the client application can obtain references to the client view of any enterprise
bean module found by the embedded container.
An alternate version of the EJBContainer.createEJBContainer method takes a Map of
properties and settings for customizing the embeddable container instance:
Properties props = new Properties();
props.setProperty(...);
...
EJBContainer ec = EJBContainer.createEJBContainer(props);
35-2 The Java EE 7 Tutorial
Developing Embeddable Enterprise Bean Applications
35.2.2.1 Explicitly Specifying Enterprise Bean Modules to Be Initialized
Developers can specify exactly which enterprise bean modules the embedded
container will initialize. To explicitly specify the enterprise bean modules initialized by
the embedded container, set the EJBContainer.MODULES property.
The modules may be located either in the virtual machine classpath in which the
embedded container and client code run, or alternately outside the virtual machine
classpath.
To specify modules in the virtual machine classpath, set EJBContainer.MODULES to a
String to specify a single module name, or a String array containing the module
names. The embedded container searches the virtual machine classpath for enterprise
bean modules matching the specified names:
Properties props = new Properties();
props.setProperty(EJBContainer.MODULES, "mySessionBean");
EJBContainer ec = EJBContainer.createEJBContainer(props);
To specify enterprise bean modules outside the virtual machine classpath, set
EJBContainer.MODULES to a java.io.File object or an array of File objects. Each File
object refers to an EJB JAR file, or a directory containing an expanded EJB JAR file:
Properties props = new Properties();
File ejbJarFile = new File(...);
props.setProperty(EJBContainer.MODULES, ejbJarFile);
EJBContainer ec = EJBContainer.createEJBContainer(props);
35.2.3 Looking Up Session Bean References
To look up session bean references in an application using the embedded container,
use an instance of EJBContainer to retrieve a javax.naming.Context object. Call the
EJBContainer.getContext method to retrieve the Context object:
EJBContainer ec = EJBContainer.createEJBContainer();
Context ctx = ec.getContext();
References to session beans can then be obtained using the portable JNDI syntax
detailed in Portable JNDI Syntax. For example, to obtain a reference to MySessionBean,
a local session bean with a no-interface view, use the following code:
MySessionBean msb = (MySessionBean)
ctx.lookup("java:global/mySessionBean/MySessionBean");
35.2.4 Shutting Down the Enterprise Bean Container
From the client, call the close method of the instance of EJBContainer to shut down
the embedded container:
EJBContainer ec = EJBContainer.createEJBContainer();
...
ec.close();
While clients are not required to shut down EJBContainer instances, doing so frees
resources consumed by the embedded container. This is particularly important when
the virtual machine under which the client application is running has a longer lifetime
than the client application.
Using the Embedded Enterprise Bean Container 35-3
The standalone Example Application
35.3 The standalone Example Application
The standalone example application demonstrates how to create an instance of the
embedded enterprise bean container in a JUnit test class and call a session bean
business method. Testing the business methods of an enterprise bean in a unit test
allows developers to exercise the business logic of an application separately from the
other application layers, such as the presentation layer, and without having to deploy
the application to a Java EE server.
The standalone example has two main components: StandaloneBean, a stateless
session bean, and StandaloneBeanTest, a JUnit test class that acts as a client to
StandaloneBean using the embedded container.
StandaloneBean is a simple session bean exposing a local, no-interface view with a
single business method, returnMessage, which returns "Greetings!" as a String:
@Stateless
public class StandaloneBean {
private static final String message = "Greetings!";
public String returnMessage() {
return message;
}
}
StandaloneBeanTest calls StandaloneBean.returnMessage and tests that the returned
message is correct. First, an embedded container instance and initial context are
created within the setUp method, which is annotated with org.junit.Before to
indicate that the method should be executed before the test methods:
@Before
public void setUp() {
ec = EJBContainer.createEJBContainer();
ctx = ec.getContext();
}
The testReturnMessage method, annotated with org.junit.Test to indicate that the
method includes a unit test, obtains a reference to StandaloneBean through the
Context instance, and calls StandaloneBean.returnMessage. The result is compared
with the expected result using a JUnit assertion, assertEquals. If the string returned
from StandaloneBean.returnMessage is equal to "Greetings!" the test passes:
@Test
public void testReturnMessage() throws Exception {
logger.info("Testing standalone.ejb.StandaloneBean.returnMessage()");
StandaloneBean instance = (StandaloneBean)
ctx.lookup("java:global/classes/StandaloneBean");
String expResult = "Greetings!";
String result = instance.returnMessage();
assertEquals(expResult, result);
}
Finally, the tearDown method, annotated with org.junit.After to indicate that the
method should be executed after all the unit tests have run, closes the embedded
container instance:
@After
public void tearDown() {
if (ec != null) {
35-4 The Java EE 7 Tutorial
The standalone Example Application
ec.close();
}
}
35.3.1 To Run the standalone Example Application Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/ejb
4.
Select the standalone folder and click Open Project.
5.
In the Projects tab, right-click standalone and select Test.
This will execute the JUnit test class StandaloneBeanTest. The Output tab shows
the progress of the test and the output log.
35.3.2 To Run the standalone Example Application Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/ejb/standalone/
3.
Enter the following command:
mvn install
This command compiles and packages the application into an JAR file, and
executes the JUnit test class StandaloneBeanTest.
Using the Embedded Enterprise Bean Container 35-5
The standalone Example Application
35-6 The Java EE 7 Tutorial
36
Using Asynchronous Method Invocation in
Session Beans
36
This chapter discusses how to implement asynchronous business methods in session
beans and call them from enterprise bean clients.
The following topics are addressed here:
■
Asynchronous Method Invocation
■
The async Example Application
36.1 Asynchronous Method Invocation
Session beans can implement asynchronous methods, business methods where control
is returned to the client by the enterprise bean container before the method is invoked
on the session bean instance. Clients may then use the Java SE concurrency API to
retrieve the result, cancel the invocation, and check for exceptions. Asynchronous
methods are typically used for long-running operations, for processor-intensive tasks,
for background tasks, to increase application throughput, or to improve application
response time if the method invocation result isn't required immediately.
When a session bean client invokes a typical non-asynchronous business method,
control is not returned to the client until the method has completed. Clients calling
asynchronous methods, however, immediately have control returned to them by the
enterprise bean container. This allows the client to perform other tasks while the
method invocation completes. If the method returns a result, the result is an
implementation of the java.util.concurrent.Future<V> interface, where "V" is the
result value type. The Future<V> interface defines methods the client may use to check
whether the computation is completed, wait for the invocation to complete, retrieve
the final result, and cancel the invocation.
36.1.1 Creating an Asynchronous Business Method
Annotate a business method with javax.ejb.Asynchronous to mark that method as an
asynchronous method, or apply @Asynchronous at the class level to mark all the
business methods of the session bean as asynchronous methods. Session bean methods
that expose web services can't be asynchronous.
Asynchronous methods must return either void or an implementation of the
Future<V> interface. Asynchronous methods that return void can't declare application
exceptions, but if they return Future<V>, they may declare application exceptions. For
example:
@Asynchronous
public Future<String> processPayment(Order order) throws PaymentException { ... }
Using Asynchronous Method Invocation in Session Beans 36-1
Asynchronous Method Invocation
This method will attempt to process the payment of an order, and return the status as a
String. Even if the payment processor takes a long time, the client can continue
working, and display the result when the processing finally completes.
The javax.ejb.AsyncResult<V> class is a concrete implementation of the Future<V>
interface provided as a helper class for returning asynchronous results. AsyncResult
has a constructor with the result as a parameter, making it easy to create Future<V>
implementations. For example, the processPayment method would use AsyncResult
to return the status as a String:
@Asynchronous
public Future<String> processPayment(Order order) throws PaymentException {
...
String status = ...;
return new AsyncResult<String>(status);
}
The result is returned to the enterprise bean container, not directly to the client, and
the enterprise bean container makes the result available to the client. The session bean
can check whether the client requested that the invocation be cancelled by calling the
javax.ejb.SessionContext.wasCancelled method. For example:
@Asynchronous
public Future<String> processPayment(Order order) throws PaymentException {
...
if (SessionContext.wasCancelled()) {
// clean up
} else {
// process the payment
}
...
}
36.1.2 Calling Asynchronous Methods from Enterprise Bean Clients
Session bean clients call asynchronous methods just like non-asynchronous business
methods. If the asynchronous method returns a result, the client receives a Future<V>
instance as soon as the method is invoked. This instance can be used to retrieve the
final result, cancel the invocation, check whether the invocation has completed, check
whether any exceptions were thrown during processing, and check whether the
invocation was cancelled.
36.1.2.1 Retrieving the Final Result from an Asynchronous Method Invocation
The client may retrieve the result using one of the Future<V>.get methods. If
processing hasn't been completed by the session bean handling the invocation, calling
one of the get methods will result in the client halting execution until the invocation
completes. Use the Future<V>.isDone method to determine whether processing has
completed before calling one of the get methods.
The get() method returns the result as the type specified in the type value of the
Future<V> instance. For example, calling Future<String>.get() will return a String
object. If the method invocation was cancelled, calls to get() result in a
java.util.concurrent.CancellationException being thrown. If the invocation
resulted in an exception during processing by the session bean, calls to get() result in
a java.util.concurrent.ExecutionException being thrown. The cause of the
ExecutionException may be retrieved by calling the ExecutionException.getCause
method.
36-2 The Java EE 7 Tutorial
The async Example Application
The get(long timeout, java.util.concurrent.TimeUnit unit) method is similar to
the get() method, but allows the client to set a timeout value. If the timeout value is
exceeded, a java.util.concurrent.TimeoutException is thrown. See the Javadoc for
the TimeUnit class for the available units of time to specify the timeout value.
36.1.2.2 Cancelling an Asynchronous Method Invocation
Call the cancel(boolean mayInterruptIfRunning) method on the Future<V> instance
to attempt to cancel the method invocation. The cancel method returns true if the
cancellation was successful and false if the method invocation cannot be cancelled.
When the invocation cannot be cancelled, the mayInterruptIfRunning parameter is
used to alert the session bean instance on which the method invocation is running that
the client attempted to cancel the invocation. If mayInterruptIfRunning is set to true,
calls to SessionContext.wasCancelled by the session bean instance will return true. If
mayInterruptIfRunning is to set false, calls to SessionContext.wasCancelled by the
session bean instance will return false.
The Future<V>.isCancelled method is used to check whether the method invocation
was cancelled before the asynchronous method invocation completed by calling
Future<V>.cancel. The isCancelled method returns true if the invocation was
cancelled.
36.1.2.3 Checking the Status of an Asynchronous Method Invocation
The Future<V>.isDone method returns true if the session bean instance completed
processing the method invocation. The isDone method returns true if the
asynchronous method invocation completed normally, was cancelled, or resulted in an
exception. That is, isDone indicates only whether the session bean has completed
processing the invocation.
36.2 The async Example Application
The async example demonstrates how to define an asynchronous business method on
a session bean and call it from a web client. This example contains two modules.
■
■
A web application (async-war) that contains a stateless session bean and a
JavaServer Faces interface. The MailerBean stateless session bean defines an
asynchronous method, sendMessage, which uses the JavaMail API to send an
email to an specified email address.
An auxiliary Java SE program (async-smtpd) that simulates an SMTP server. This
program listens on TCP port 3025 for SMTP requests and prints the email
messages to the standard output (instead of delivering them).
The following section describes the architecture of the async-war module.
36.2.1 Architecture of the async-war Module
The async-war module consists of a single stateless session bean, MailerBean, and a
JavaServer Faces web application front end that uses Facelets tags in XHTML files to
display a form for users to enter the email address for the recipient of an email. The
status of the email is updated when the email is finally sent.
The MailerBean session bean injects a JavaMail resource used to send an email
message to an address specified by the user. The message is created, modified, and
sent using the JavaMail API. The session bean looks like this:
Using Asynchronous Method Invocation in Session Beans 36-3
The async Example Application
@Named
@Stateless
public class MailerBean {
@Resource(name="mail/myExampleSession")
private Session session;
private static final Logger logger =
Logger.getLogger(MailerBean.class.getName());
@Asynchronous
public Future<String> sendMessage(String email) {
String status;
try {
Properties properties = new Properties();
properties.put("mail.smtp.port", "3025");
session = Session.getInstance(properties);
Message message = new MimeMessage(session);
message.setFrom();
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(email, false));
message.setSubject("Test message from async example");
message.setHeader("X-Mailer", "JavaMail");
DateFormat dateFormatter = DateFormat
.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT);
Date timeStamp = new Date();
String messageBody = "This is a test message from the async "
+ "example of the Java EE Tutorial. It was sent on "
+ dateFormatter.format(timeStamp)
+ ".";
message.setText(messageBody);
message.setSentDate(timeStamp);
Transport.send(message);
status = "Sent";
logger.log(Level.INFO, "Mail sent to {0}", email);
} catch (MessagingException ex) {
logger.severe("Error in sending message.");
status = "Encountered an error: " + ex.getMessage();
logger.severe(ex.getMessage());
}
return new AsyncResult<>(status);
}
}
The injected JavaMail resource can be configured through the GlassFish Server
Administration Console, through a GlassFish Server administrative command, or
through a resource configuration file packaged with the application. The resource
configuration can be modified at runtime by the GlassFish Server administrator to use
a different mail server or transport protocol.
The web client consists of a Facelets template, template.xhtml; two Facelets clients,
index.xhtml and response.xhtml; and a JavaServer Faces managed bean,
MailerManagedBean. The index.xhtml file contains a form for the target email address.
When the user submits the form, the MailerManagedBean.send method is called. This
method uses an injected instance of the MailerBean session bean to call
MailerBean.sendMessage. The result is sent to the response.xhtml Facelets view.
36.2.2 Running the async Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
async example.
36-4 The Java EE 7 Tutorial
The async Example Application
36.2.2.1 To Run the async Example Application Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/ejb
4.
Select the async folder, select Open Required Projects, and click Open Project.
5.
In the Projects tab, right-click the async-smtpd project and select Run.
The SMTP server simulator starts accepting connections. The async-smptd output
tab shows the following message:
[Test SMTP server listening on port 3025]
6.
In the Projects tab, right-click the async-war project and select Build.
This command configures the JavaMail resource using a GlassFish Server
administrative command and builds, packages, and deploys the async-war
module.
7.
Open the following URL in a web browser window:
http://localhost:8080/async-war
8.
In the web browser window, enter an email address and click Send email.
The MailerBean stateless bean uses the JavaMail API to deliver an email to the
SMTP server simulator. The async-smptd output window in NetBeans IDE shows
the resulting email message, including its headers.
9.
To stop the SMTP server simulator, click the X button on the right side of the status
bar in NetBeans IDE.
10. Delete the JavaMail session resource.
a.
In the Services tab, expand the Servers node, then expand the GlassFish
Server server node.
b.
Expand the Resources node, then expand the JavaMail Sessions node.
c.
Right-click mail/myExampleSession and select Unregister.
36.2.2.2 To Run the async Example Application Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/ejb/async/async-smtpd/
3.
Enter the following command to build and package the SMTP server simulator:
mvn install
4.
Enter the following command to start the STMP server simulator:
mvn exec:java
The following message appears:
Using Asynchronous Method Invocation in Session Beans 36-5
The async Example Application
[Test SMTP server listening on port 3025]
Keep this terminal window open.
5.
In a new terminal window, go to:
tut-install/examples/ejb/async/async-war
6.
Enter the following command to configure the JavaMail resource and to build,
package, and deploy the async-war module:
mvn install
7.
Open the following URL in a web browser window:
http://localhost:8080/async-war
8.
In the web browser window, enter an email address and click Send email.
The MailerBean stateless bean uses the JavaMail API to deliver an email to the
SMTP server simulator. The resulting email message appears on the first terminal
window, including its headers.
9.
To stop the SMTP server simulator, close the terminal window in which you issued
the command to start the STMP server simulator.
10. To delete the JavaMail session resource, type the following command:
asadmin delete-javamail-resource mail/myExampleSession
36-6 The Java EE 7 Tutorial
Part VIII
Part VIII
Persistence
Part VIII explores the Java Persistence API. This part contains the following chapters:
■
Chapter 37, "Introduction to the Java Persistence API"
■
Chapter 38, "Running the Persistence Examples"
■
Chapter 39, "The Java Persistence Query Language"
■
Chapter 40, "Using the Criteria API to Create Queries"
■
Chapter 41, "Creating and Using String-Based Criteria Queries"
■
Chapter 42, "Controlling Concurrent Access to Entity Data with Locking"
■
Chapter 43, "Creating Fetch Plans with Entity Graphs"
■
Chapter 44, "Using a Second-Level Cache with Java Persistence API Applications"
37
Introduction to the Java Persistence API
37
The Java Persistence API provides Java developers with an object/relational mapping
facility for managing relational data in Java applications. Java Persistence consists of
four areas:
■
The Java Persistence API
■
The query language
■
The Java Persistence Criteria API
■
Object/relational mapping metadata
The following topics are addressed here:
■
Entities
■
Entity Inheritance
■
Managing Entities
■
Querying Entities
■
Database Schema Creation
■
Further Information about Persistence
37.1 Entities
An entity is a lightweight persistence domain object. Typically, an entity represents a
table in a relational database, and each entity instance corresponds to a row in that
table. The primary programming artifact of an entity is the entity class, although
entities can use helper classes.
The persistent state of an entity is represented through either persistent fields or
persistent properties. These fields or properties use object/relational mapping
annotations to map the entities and entity relationships to the relational data in the
underlying data store.
37.1.1 Requirements for Entity Classes
An entity class must follow these requirements.
■
■
■
The class must be annotated with the javax.persistence.Entity annotation.
The class must have a public or protected, no-argument constructor. The class may
have other constructors.
The class must not be declared final. No methods or persistent instance variables
must be declared final.
Introduction to the Java Persistence API
37-1
Entities
■
■
■
If an entity instance is passed by value as a detached object, such as through a
session bean's remote business interface, the class must implement the
Serializable interface.
Entities may extend both entity and non-entity classes, and non-entity classes may
extend entity classes.
Persistent instance variables must be declared private, protected, or
package-private and can be accessed directly only by the entity class's methods.
Clients must access the entity's state through accessor or business methods.
37.1.2 Persistent Fields and Properties in Entity Classes
The persistent state of an entity can be accessed through either the entity's instance
variables or properties. The fields or properties must be of the following Java language
types:
■
Java primitive types
■
java.lang.String
■
Other serializable types, including:
–
Wrappers of Java primitive types
–
java.math.BigInteger
–
java.math.BigDecimal
–
java.util.Date
–
java.util.Calendar
–
java.sql.Date
–
java.sql.Time
–
java.sql.TimeStamp
–
User-defined serializable types
–
byte[]
–
Byte[]
–
char[]
–
Character[]
■
Enumerated types
■
Other entities and/or collections of entities
■
Embeddable classes
Entities may use persistent fields, persistent properties, or a combination of both. If the
mapping annotations are applied to the entity's instance variables, the entity uses
persistent fields. If the mapping annotations are applied to the entity's getter methods
for JavaBeans-style properties, the entity uses persistent properties.
37.1.2.1 Persistent Fields
If the entity class uses persistent fields, the Persistence runtime accesses entity-class
instance variables directly. All fields not annotated javax.persistence.Transient or
not marked as Java transient will be persisted to the data store. The object/relational
mapping annotations must be applied to the instance variables.
37-2 The Java EE 7 Tutorial
Entities
37.1.2.2 Persistent Properties
If the entity uses persistent properties, the entity must follow the method conventions
of JavaBeans components. JavaBeans-style properties use getter and setter methods
that are typically named after the entity class's instance variable names. For every
persistent property property of type Type of the entity, there is a getter method
getProperty and setter method setProperty. If the property is a Boolean, you may use
isProperty instead of getProperty. For example, if a Customer entity uses persistent
properties and has a private instance variable called firstName, the class defines a
getFirstName and setFirstName method for retrieving and setting the state of the
firstName instance variable.
The method signatures for single-valued persistent properties are as follows:
Type getProperty()
void setProperty(Type type)
The object/relational mapping annotations for persistent properties must be applied to
the getter methods. Mapping annotations cannot be applied to fields or properties
annotated @Transient or marked transient.
37.1.2.3 Using Collections in Entity Fields and Properties
Collection-valued persistent fields and properties must use the supported Java
collection interfaces regardless of whether the entity uses persistent fields or
properties. The following collection interfaces may be used:
■
java.util.Collection
■
java.util.Set
■
java.util.List
■
java.util.Map
If the entity class uses persistent fields, the type in the preceding method signatures
must be one of these collection types. Generic variants of these collection types may
also be used. For example, if it has a persistent property that contains a set of phone
numbers, the Customer entity would have the following methods:
Set<PhoneNumber> getPhoneNumbers() { ... }
void setPhoneNumbers(Set<PhoneNumber>) { ... }
If a field or property of an entity consists of a collection of basic types or embeddable
classes, use the javax.persistence.ElementCollection annotation on the field or
property.
The two attributes of @ElementCollection are targetClass and fetch. The
targetClass attribute specifies the class name of the basic or embeddable class and is
optional if the field or property is defined using Java programming language generics.
The optional fetch attribute is used to specify whether the collection should be
retrieved lazily or eagerly, using the javax.persistence.FetchType constants of either
LAZY or EAGER, respectively. By default, the collection will be fetched lazily.
The following entity, Person, has a persistent field, nicknames, which is a collection of
String classes that will be fetched eagerly. The targetClass element is not required,
because it uses generics to define the field:
@Entity
public class Person {
...
@ElementCollection(fetch=EAGER)
protected Set<String> nickname = new HashSet();
Introduction to the Java Persistence API
37-3
Entities
...
}
Collections of entity elements and relationships may be represented by java.util.Map
collections. A Map consists of a key and a value.
When using Map elements or relationships, the following rules apply.
■
■
The Map key or value may be a basic Java programming language type, an
embeddable class, or an entity.
When the Map value is an embeddable class or basic type, use the
@ElementCollection annotation.
■
When the Map value is an entity, use the @OneToMany or @ManyToMany annotation.
■
Use the Map type on only one side of a bidirectional relationship.
If the key type of a Map is a Java programming language basic type, use the annotation
javax.persistence.MapKeyColumn to set the column mapping for the key. By default,
the name attribute of @MapKeyColumn is of the form
RELATIONSHIP-FIELD/PROPERTY-NAME_KEY. For example, if the referencing
relationship field name is image, the default name attribute is IMAGE_KEY.
If the key type of a Map is an entity, use the javax.persistence.MapKeyJoinColumn
annotation. If the multiple columns are needed to set the mapping, use the annotation
javax.persistence.MapKeyJoinColumns to include multiple @MapKeyJoinColumn
annotations. If no @MapKeyJoinColumn is present, the mapping column name is by
default set to RELATIONSHIP-FIELD/PROPERTY-NAME_KEY. For example, if the
relationship field name is employee, the default name attribute is EMPLOYEE_KEY.
If Java programming language generic types are not used in the relationship field or
property, the key class must be explicitly set using the
javax.persistence.MapKeyClass annotation.
If the Map key is the primary key or a persistent field or property of the entity that is
the Map value, use the javax.persistence.MapKey annotation. The @MapKeyClass and
@MapKey annotations cannot be used on the same field or property.
If the Map value is a Java programming language basic type or an embeddable class, it
will be mapped as a collection table in the underlying database. If generic types are not
used, the @ElementCollection annotation's targetClass attribute must be set to the
type of the Map value.
If the Map value is an entity and part of a many-to-many or one-to-many unidirectional
relationship, it will be mapped as a join table in the underlying database. A
unidirectional one-to-many relationship that uses a Map may also be mapped using the
@JoinColumn annotation.
If the entity is part of a one-to-many/many-to-one bidirectional relationship, it will be
mapped in the table of the entity that represents the value of the Map. If generic types
are not used, the targetEntity attribute of the @OneToMany and @ManyToMany
annotations must be set to the type of the Map value.
37.1.2.4 Validating Persistent Fields and Properties
The Java API for JavaBeans Validation (Bean Validation) provides a mechanism for
validating application data. Bean Validation is integrated into the Java EE containers,
allowing the same validation logic to be used in any of the tiers of an enterprise
application.
37-4 The Java EE 7 Tutorial
Entities
Bean Validation constraints may be applied to persistent entity classes, embeddable
classes, and mapped superclasses. By default, the Persistence provider will
automatically perform validation on entities with persistent fields or properties
annotated with Bean Validation constraints immediately after the PrePersist,
PreUpdate, and PreRemove lifecycle events.
Bean Validation constraints are annotations applied to the fields or properties of Java
programming language classes. Bean Validation provides a set of constraints as well as
an API for defining custom constraints. Custom constraints can be specific
combinations of the default constraints, or new constraints that don't use the default
constraints. Each constraint is associated with at least one validator class that validates
the value of the constrained field or property. Custom constraint developers must also
provide a validator class for the constraint.
Bean Validation constraints are applied to the persistent fields or properties of
persistent classes. When adding Bean Validation constraints, use the same access
strategy as the persistent class. That is, if the persistent class uses field access, apply
the Bean Validation constraint annotations on the class's fields. If the class uses
property access, apply the constraints on the getter methods.
Table 21–1 lists Bean Validation's built-in constraints, defined in the
javax.validation.constraints package.
All the built-in constraints listed in Table 21–1 have a corresponding annotation,
ConstraintName.List, for grouping multiple constraints of the same type on the same
field or property. For example, the following persistent field has two @Pattern
constraints:
@Pattern.List({
@Pattern(regexp="..."),
@Pattern(regexp="...")
})
The following entity class, Contact, has Bean Validation constraints applied to its
persistent fields:
@Entity
public class Contact implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotNull
protected String firstName;
@NotNull
protected String lastName;
@Pattern(regexp = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\."
+ "[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@"
+ "(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9]"
+ "(?:[a-z0-9-]*[a-z0-9])?",
message = "{invalid.email}")
protected String email;
@Pattern(regexp = "^\\(?(\\d{3})\\)?[- ]?(\\d{3})[- ]?(\\d{4})$",
message = "{invalid.phonenumber}")
protected String mobilePhone;
@Pattern(regexp = "^\\(?(\\d{3})\\)?[- ]?(\\d{3})[- ]?(\\d{4})$",
message = "{invalid.phonenumber}")
protected String homePhone;
@Temporal(javax.persistence.TemporalType.DATE)
@Past
protected Date birthday;
...
Introduction to the Java Persistence API
37-5
Entities
}
The @NotNull annotation on the firstName and lastName fields specifies that those
fields are now required. If a new Contact instance is created where firstName or
lastName have not been initialized, Bean Validation will throw a validation error.
Similarly, if a previously created instance of Contact has been modified so that
firstName or lastName are null, a validation error will be thrown.
The email field has a @Pattern constraint applied to it, with a complicated regular
expression that matches most valid email addresses. If the value of email doesn't
match this regular expression, a validation error will be thrown.
The homePhone and mobilePhone fields have the same @Pattern constraints. The
regular expression matches 10 digit telephone numbers in the United States and
Canada of the form (xxx) xxx-xxxx.
The birthday field is annotated with the @Past constraint, which ensures that the
value of birthday must be in the past.
37.1.3 Primary Keys in Entities
Each entity has a unique object identifier. A customer entity, for example, might be
identified by a customer number. The unique identifier, or primary key, enables clients
to locate a particular entity instance. Every entity must have a primary key. An entity
may have either a simple or a composite primary key.
Simple primary keys use the javax.persistence.Id annotation to denote the primary
key property or field.
Composite primary keys are used when a primary key consists of more than one
attribute, which corresponds to a set of single persistent properties or fields.
Composite primary keys must be defined in a primary key class. Composite primary
keys are denoted using the javax.persistence.EmbeddedId and
javax.persistence.IdClass annotations.
The primary key, or the property or field of a composite primary key, must be one of
the following Java language types:
■
Java primitive types
■
Java primitive wrapper types
■
java.lang.String
■
java.util.Date (the temporal type should be DATE)
■
java.sql.Date
■
java.math.BigDecimal
■
java.math.BigInteger
Floating-point types should never be used in primary keys. If you use a generated
primary key, only integral types will be portable.
A primary key class must meet these requirements.
■
■
The access control modifier of the class must be public.
The properties of the primary key class must be public or protected if
property-based access is used.
■
The class must have a public default constructor.
■
The class must implement the hashCode() and equals(Object other) methods.
37-6 The Java EE 7 Tutorial
Entities
■
■
■
The class must be serializable.
A composite primary key must be represented and mapped to multiple fields or
properties of the entity class or must be represented and mapped as an
embeddable class.
If the class is mapped to multiple fields or properties of the entity class, the names
and types of the primary key fields or properties in the primary key class must
match those of the entity class.
The following primary key class is a composite key, and the customerOrder and
itemId fields together uniquely identify an entity:
public final class LineItemKey implements Serializable {
private Integer customerOrder;
private int itemId;
public LineItemKey() {}
public LineItemKey(Integer order, int itemId) {
this.setCustomerOrder(order);
this.setItemId(itemId);
}
@Override
public int hashCode() {
return ((this.getCustomerOrder() == null
? 0 : this.getCustomerOrder().hashCode())
^ ((int) this.getItemId()));
}
@Override
public boolean equals(Object otherOb) {
if (this == otherOb) {
return true;
}
if (!(otherOb instanceof LineItemKey)) {
return false;
}
LineItemKey other = (LineItemKey) otherOb;
return ((this.getCustomerOrder() == null
? other.getCustomerOrder() == null : this.getCustomerOrder()
.equals(other.getCustomerOrder()))
&& (this.getItemId() == other.getItemId()));
}
@Override
public String toString() {
return "" + getCustomerOrder() + "-" + getItemId();
}
/* Getters and setters */
}
37.1.4 Multiplicity in Entity Relationships
Multiplicities are of the following types.
■
One-to-one: Each entity instance is related to a single instance of another entity.
For example, to model a physical warehouse in which each storage bin contains a
single widget, StorageBin and Widget would have a one-to-one relationship.
Introduction to the Java Persistence API
37-7
Entities
One-to-one relationships use the javax.persistence.OneToOne annotation on the
corresponding persistent property or field.
■
■
■
One-to-many: An entity instance can be related to multiple instances of the other
entities. A sales order, for example, can have multiple line items. In the order
application, CustomerOrder would have a one-to-many relationship with
LineItem. One-to-many relationships use the javax.persistence.OneToMany
annotation on the corresponding persistent property or field.
Many-to-one: Multiple instances of an entity can be related to a single instance of
the other entity. This multiplicity is the opposite of a one-to-many relationship. In
the example just mentioned, the relationship to CustomerOrder from the
perspective of LineItem is many-to-one. Many-to-one relationships use the
javax.persistence.ManyToOne annotation on the corresponding persistent
property or field.
Many-to-many: The entity instances can be related to multiple instances of each
other. For example, each college course has many students, and every student may
take several courses. Therefore, in an enrollment application, Course and Student
would have a many-to-many relationship. Many-to-many relationships use the
javax.persistence.ManyToMany annotation on the corresponding persistent
property or field.
37.1.5 Direction in Entity Relationships
The direction of a relationship can be either bidirectional or unidirectional. A
bidirectional relationship has both an owning side and an inverse side. A
unidirectional relationship has only an owning side. The owning side of a relationship
determines how the Persistence runtime makes updates to the relationship in the
database.
37.1.5.1 Bidirectional Relationships
In a bidirectional relationship, each entity has a relationship field or property that
refers to the other entity. Through the relationship field or property, an entity class's
code can access its related object. If an entity has a related field, the entity is said to
"know" about its related object. For example, if CustomerOrder knows what LineItem
instances it has and if LineItem knows what CustomerOrder it belongs to, they have a
bidirectional relationship.
Bidirectional relationships must follow these rules.
■
■
■
■
The inverse side of a bidirectional relationship must refer to its owning side by
using the mappedBy element of the @OneToOne, @OneToMany, or @ManyToMany
annotation. The mappedBy element designates the property or field in the entity
that is the owner of the relationship.
The many side of many-to-one bidirectional relationships must not define the
mappedBy element. The many side is always the owning side of the relationship.
For one-to-one bidirectional relationships, the owning side corresponds to the side
that contains the corresponding foreign key.
For many-to-many bidirectional relationships, either side may be the owning side.
37.1.5.2 Unidirectional Relationships
In a unidirectional relationship, only one entity has a relationship field or property
that refers to the other. For example, LineItem would have a relationship field that
identifies Product, but Product would not have a relationship field or property for
37-8 The Java EE 7 Tutorial
Entities
LineItem. In other words, LineItem knows about Product, but Product doesn't know
which LineItem instances refer to it.
37.1.5.3 Queries and Relationship Direction
Java Persistence query language and Criteria API queries often navigate across
relationships. The direction of a relationship determines whether a query can navigate
from one entity to another. For example, a query can navigate from LineItem to
Product but cannot navigate in the opposite direction. For CustomerOrder and
LineItem, a query could navigate in both directions because these two entities have a
bidirectional relationship.
37.1.5.4 Cascade Operations and Relationships
Entities that use relationships often have dependencies on the existence of the other
entity in the relationship. For example, a line item is part of an order; if the order is
deleted, the line item also should be deleted. This is called a cascade delete
relationship.
The javax.persistence.CascadeType enumerated type defines the cascade operations
that are applied in the cascade element of the relationship annotations. Table 37–1 lists
the cascade operations for entities.
Table 37–1
Cascade
Operation
Cascade Operations for Entities
Description
ALL
All cascade operations will be applied to the parent entity's related entity. All
is equivalent to specifying cascade={DETACH, MERGE, PERSIST, REFRESH,
REMOVE}
DETACH
If the parent entity is detached from the persistence context, the related entity
will also be detached.
MERGE
If the parent entity is merged into the persistence context, the related entity
will also be merged.
PERSIST
If the parent entity is persisted into the persistence context, the related entity
will also be persisted.
REFRESH
If the parent entity is refreshed in the current persistence context, the related
entity will also be refreshed.
REMOVE
If the parent entity is removed from the current persistence context, the
related entity will also be removed.
Cascade delete relationships are specified using the cascade=REMOVE element
specification for @OneToOne and @OneToMany relationships. For example:
@OneToMany(cascade=REMOVE, mappedBy="customer")
public Set<CustomerOrder> getOrders() { return orders; }
37.1.5.5 Orphan Removal in Relationships
When a target entity in a one-to-one or one-to-many relationship is removed from the
relationship, it is often desirable to cascade the remove operation to the target entity.
Such target entities are considered "orphans," and the orphanRemoval attribute can be
used to specify that orphaned entities should be removed. For example, if an order has
many line items and one of them is removed from the order, the removed line item is
considered an orphan. If orphanRemoval is set to true, the line item entity will be
deleted when the line item is removed from the order.
Introduction to the Java Persistence API
37-9
Entities
The orphanRemoval attribute in @OneToMany and @oneToOne takes a Boolean value and
is by default false.
The following example will cascade the remove operation to the orphaned order
entity when the customer entity is deleted:
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<CustomerOrder> getOrders() { ... }
37.1.6 Embeddable Classes in Entities
Embeddable classes are used to represent the state of an entity but don't have a
persistent identity of their own, unlike entity classes. Instances of an embeddable class
share the identity of the entity that owns it. Embeddable classes exist only as the state
of another entity. An entity may have single-valued or collection-valued embeddable
class attributes.
Embeddable classes have the same rules as entity classes but are annotated with the
javax.persistence.Embeddable annotation instead of @Entity.
The following embeddable class, ZipCode, has the fields zip and plusFour:
@Embeddable
public class ZipCode {
String zip;
String plusFour;
...
}
This embeddable class is used by the Address entity:
@Entity
public class Address {
@Id
protected long id
String street1;
String street2;
String city;
String province;
@Embedded
ZipCode zipCode;
String country;
...
}
Entities that own embeddable classes as part of their persistent state may annotate the
field or property with the javax.persistence.Embedded annotation but are not
required to do so.
Embeddable classes may themselves use other embeddable classes to represent their
state. They may also contain collections of basic Java programming language types or
other embeddable classes. Embeddable classes may also contain relationships to other
entities or collections of entities. If the embeddable class has such a relationship, the
relationship is from the target entity or collection of entities to the entity that owns the
embeddable class.
37-10 The Java EE 7 Tutorial
Entity Inheritance
37.2 Entity Inheritance
Entities support class inheritance, polymorphic associations, and polymorphic queries.
Entity classes can extend non-entity classes, and non-entity classes can extend entity
classes. Entity classes can be both abstract and concrete.
The roster example application demonstrates entity inheritance, as described in
Entity Inheritance in the roster Application.
37.2.1 Abstract Entities
An abstract class may be declared an entity by decorating the class with @Entity.
Abstract entities are like concrete entities but cannot be instantiated.
Abstract entities can be queried just like concrete entities. If an abstract entity is the
target of a query, the query operates on all the concrete subclasses of the abstract
entity:
@Entity
public abstract class Employee {
@Id
protected Integer employeeId;
...
}
@Entity
public class FullTimeEmployee extends Employee {
protected Integer salary;
...
}
@Entity
public class PartTimeEmployee extends Employee {
protected Float hourlyWage;
}
37.2.2 Mapped Superclasses
Entities may inherit from superclasses that contain persistent state and mapping
information but are not entities. That is, the superclass is not decorated with the
@Entity annotation and is not mapped as an entity by the Java Persistence provider.
These superclasses are most often used when you have state and mapping information
common to multiple entity classes.
Mapped superclasses are specified by decorating the class with the annotation
javax.persistence.MappedSuperclass:
@MappedSuperclass
public class Employee {
@Id
protected Integer employeeId;
...
}
@Entity
public class FullTimeEmployee extends Employee {
protected Integer salary;
...
}
@Entity
public class PartTimeEmployee extends Employee {
protected Float hourlyWage;
...
}
Introduction to the Java Persistence API
37-11
Entity Inheritance
Mapped superclasses cannot be queried and cannot be used in EntityManager or
Query operations. You must use entity subclasses of the mapped superclass in
EntityManager or Query operations. Mapped superclasses can't be targets of entity
relationships. Mapped superclasses can be abstract or concrete.
Mapped superclasses do not have any corresponding tables in the underlying
datastore. Entities that inherit from the mapped superclass define the table mappings.
For instance, in the preceding code sample, the underlying tables would be
FULLTIMEEMPLOYEE and PARTTIMEEMPLOYEE, but there is no EMPLOYEE table.
37.2.3 Non-Entity Superclasses
Entities may have non-entity superclasses, and these superclasses can be either
abstract or concrete. The state of non-entity superclasses is nonpersistent, and any state
inherited from the non-entity superclass by an entity class is nonpersistent. Non-entity
superclasses may not be used in EntityManager or Query operations. Any mapping or
relationship annotations in non-entity superclasses are ignored.
37.2.4 Entity Inheritance Mapping Strategies
You can configure how the Java Persistence provider maps inherited entities to the
underlying datastore by decorating the root class of the hierarchy with the annotation
javax.persistence.Inheritance. The following mapping strategies are used to map
the entity data to the underlying database:
■
A single table per class hierarchy
■
A table per concrete entity class
■
A "join" strategy, whereby fields or properties that are specific to a subclass are
mapped to a different table than the fields or properties that are common to the
parent class
The strategy is configured by setting the strategy element of @Inheritance to one of
the options defined in the javax.persistence.InheritanceType enumerated type:
public enum InheritanceType {
SINGLE_TABLE,
JOINED,
TABLE_PER_CLASS
};
The default strategy, InheritanceType.SINGLE_TABLE, is used if the @Inheritance
annotation is not specified on the root class of the entity hierarchy.
37.2.4.1 The Single Table per Class Hierarchy Strategy
With this strategy, which corresponds to the default InheritanceType.SINGLE_TABLE,
all classes in the hierarchy are mapped to a single table in the database. This table has
a discriminator column containing a value that identifies the subclass to which the
instance represented by the row belongs.
The discriminator column, whose elements are shown in Table 37–2, can be specified
by using the javax.persistence.DiscriminatorColumn annotation on the root of the
entity class hierarchy.
37-12 The Java EE 7 Tutorial
Entity Inheritance
Table 37–2
@DiscriminatorColumn Elements
Type
Name
Description
String
name
The name of the column to be used as the
discriminator column. The default is DTYPE. This
element is optional.
DiscriminatorType discriminatorType The type of the column to be used as a
discriminator column. The default is
DiscriminatorType.STRING. This element is
optional.
String
columnDefinition
The SQL fragment to use when creating the
discriminator column. The default is generated by
the Persistence provider and is
implementation-specific. This element is optional.
String
length
The column length for String-based discriminator
types. This element is ignored for non-String
discriminator types. The default is 31. This element
is optional.
The javax.persistence.DiscriminatorType enumerated type is used to set the type
of the discriminator column in the database by setting the discriminatorType element
of @DiscriminatorColumn to one of the defined types. DiscriminatorType is defined
as follows:
public enum DiscriminatorType {
STRING,
CHAR,
INTEGER
};
If @DiscriminatorColumn is not specified on the root of the entity hierarchy and a
discriminator column is required, the Persistence provider assumes a default column
name of DTYPE and column type of DiscriminatorType.STRING.
The javax.persistence.DiscriminatorValue annotation may be used to set the value
entered into the discriminator column for each entity in a class hierarchy. You may
decorate only concrete entity classes with @DiscriminatorValue.
If @DiscriminatorValue is not specified on an entity in a class hierarchy that uses a
discriminator column, the Persistence provider will provide a default,
implementation-specific value. If the discriminatorType element of
@DiscriminatorColumn is DiscriminatorType.STRING, the default value is the name of
the entity.
This strategy provides good support for polymorphic relationships between entities
and queries that cover the entire entity class hierarchy. However, this strategy requires
the columns that contain the state of subclasses to be nullable.
37.2.4.2 The Table per Concrete Class Strategy
In this strategy, which corresponds to InheritanceType.TABLE_PER_CLASS, each
concrete class is mapped to a separate table in the database. All fields or properties in
the class, including inherited fields or properties, are mapped to columns in the class's
table in the database.
This strategy provides poor support for polymorphic relationships and usually
requires either SQL UNION queries or separate SQL queries for each subclass for queries
that cover the entire entity class hierarchy.
Introduction to the Java Persistence API
37-13
Managing Entities
Support for this strategy is optional and may not be supported by all Java Persistence
API providers. The default Java Persistence API provider in GlassFish Server does not
support this strategy.
37.2.4.3 The Joined Subclass Strategy
In this strategy, which corresponds to InheritanceType.JOINED, the root of the class
hierarchy is represented by a single table, and each subclass has a separate table that
contains only those fields specific to that subclass. That is, the subclass table does not
contain columns for inherited fields or properties. The subclass table also has a column
or columns that represent its primary key, which is a foreign key to the primary key of
the superclass table.
This strategy provides good support for polymorphic relationships but requires one or
more join operations to be performed when instantiating entity subclasses. This may
result in poor performance for extensive class hierarchies. Similarly, queries that cover
the entire class hierarchy require join operations between the subclass tables, resulting
in decreased performance.
Some Java Persistence API providers, including the default provider in GlassFish
Server, require a discriminator column that corresponds to the root entity when using
the joined subclass strategy. If you are not using automatic table creation in your
application, make sure that the database table is set up correctly for the discriminator
column defaults, or use the @DiscriminatorColumn annotation to match your database
schema. For information on discriminator columns, see The Single Table per Class
Hierarchy Strategy.
37.3 Managing Entities
Entities are managed by the entity manager, which is represented by
javax.persistence.EntityManager instances. Each EntityManager instance is
associated with a persistence context: a set of managed entity instances that exist in a
particular data store. A persistence context defines the scope under which particular
entity instances are created, persisted, and removed. The EntityManager interface
defines the methods that are used to interact with the persistence context.
37.3.1 The EntityManager Interface
The EntityManager API creates and removes persistent entity instances, finds entities
by the entity's primary key, and allows queries to be run on entities.
37.3.1.1 Container-Managed Entity Managers
With a container-managed entity manager, an EntityManager instance's persistence
context is automatically propagated by the container to all application components
that use the EntityManager instance within a single Java Transaction API (JTA)
transaction.
JTA transactions usually involve calls across application components. To complete a
JTA transaction, these components usually need access to a single persistence context.
This occurs when an EntityManager is injected into the application components by
means of the javax.persistence.PersistenceContext annotation. The persistence
context is automatically propagated with the current JTA transaction, and
EntityManager references that are mapped to the same persistence unit provide access
to the persistence context within that transaction. By automatically propagating the
persistence context, application components don't need to pass references to
EntityManager instances to each other in order to make changes within a single
37-14 The Java EE 7 Tutorial
Managing Entities
transaction. The Java EE container manages the lifecycle of container-managed entity
managers.
To obtain an EntityManager instance, inject the entity manager into the application
component:
@PersistenceContext
EntityManager em;
37.3.1.2 Application-Managed Entity Managers
With an application-managed entity manager, on the other hand, the persistence
context is not propagated to application components, and the lifecycle of
EntityManager instances is managed by the application.
Application-managed entity managers are used when applications need to access a
persistence context that is not propagated with the JTA transaction across
EntityManager instances in a particular persistence unit. In this case, each
EntityManager creates a new, isolated persistence context. The EntityManager and its
associated persistence context are created and destroyed explicitly by the application.
They are also used when directly injecting EntityManager instances can't be done
because EntityManager instances are not thread-safe. EntityManagerFactory instances
are thread-safe.
Applications create EntityManager instances in this case by using the
createEntityManager method of javax.persistence.EntityManagerFactory.
To obtain an EntityManager instance, you first must obtain an EntityManagerFactory
instance by injecting it into the application component by means of the
javax.persistence.PersistenceUnit annotation:
@PersistenceUnit
EntityManagerFactory emf;
Then obtain an EntityManager from the EntityManagerFactory instance:
EntityManager em = emf.createEntityManager();
Application-managed entity managers don't automatically propagate the JTA
transaction context. Such applications need to manually gain access to the JTA
transaction manager and add transaction demarcation information when performing
entity operations. The javax.transaction.UserTransaction interface defines
methods to begin, commit, and roll back transactions. Inject an instance of
UserTransaction by creating an instance variable annotated with @Resource:
@Resource
UserTransaction utx;
To begin a transaction, call the UserTransaction.begin method. When all the entity
operations are complete, call the UserTransaction.commit method to commit the
transaction. The UserTransaction.rollback method is used to roll back the current
transaction.
The following example shows how to manage transactions in an application that uses
an application-managed entity manager:
@PersistenceUnit
EntityManagerFactory emf;
EntityManager em;
@Resource
UserTransaction utx;
...
Introduction to the Java Persistence API
37-15
Managing Entities
em = emf.createEntityManager();
try {
utx.begin();
em.persist(SomeEntity);
em.merge(AnotherEntity);
em.remove(ThirdEntity);
utx.commit();
} catch (Exception e) {
utx.rollback();
}
37.3.1.3 Finding Entities Using the EntityManager
The EntityManager.find method is used to look up entities in the data store by the
entity's primary key:
@PersistenceContext
EntityManager em;
public void enterOrder(int custID, CustomerOrder newOrder) {
Customer cust = em.find(Customer.class, custID);
cust.getOrders().add(newOrder);
newOrder.setCustomer(cust);
}
37.3.1.4 Managing an Entity Instance's Lifecycle
You manage entity instances by invoking operations on the entity by means of an
EntityManager instance. Entity instances are in one of four states: new, managed,
detached, or removed.
■
■
■
■
New entity instances have no persistent identity and are not yet associated with a
persistence context.
Managed entity instances have a persistent identity and are associated with a
persistence context.
Detached entity instances have a persistent identity and are not currently
associated with a persistence context.
Removed entity instances have a persistent identity, are associated with a
persistent context, and are scheduled for removal from the data store.
37.3.1.5 Persisting Entity Instances
New entity instances become managed and persistent either by invoking the persist
method or by a cascading persist operation invoked from related entities that have
the cascade=PERSIST or cascade=ALL elements set in the relationship annotation. This
means that the entity's data is stored to the database when the transaction associated
with the persist operation is completed. If the entity is already managed, the persist
operation is ignored, although the persist operation will cascade to related entities
that have the cascade element set to PERSIST or ALL in the relationship annotation. If
persist is called on a removed entity instance, the entity becomes managed. If the
entity is detached, either persist will throw an IllegalArgumentException, or the
transaction commit will fail. The following method performs a persist operation:
@PersistenceContext
EntityManager em;
...
public LineItem createLineItem(CustomerOrder order, Product product,
int quantity) {
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
37-16 The Java EE 7 Tutorial
Managing Entities
em.persist(li);
return li;
}
The persist operation is propagated to all entities related to the calling entity that
have the cascade element set to ALL or PERSIST in the relationship annotation:
@OneToMany(cascade=ALL, mappedBy="order")
public Collection<LineItem> getLineItems() {
return lineItems;
}
37.3.1.6 Removing Entity Instances
Managed entity instances are removed by invoking the remove method or by a
cascading remove operation invoked from related entities that have the
cascade=REMOVE or cascade=ALL elements set in the relationship annotation. If the
remove method is invoked on a new entity, the remove operation is ignored, although
remove will cascade to related entities that have the cascade element set to REMOVE or
ALL in the relationship annotation. If remove is invoked on a detached entity, either
remove will throw an IllegalArgumentException, or the transaction commit will fail.
If invoked on an already removed entity, remove will be ignored. The entity's data will
be removed from the data store when the transaction is completed or as a result of the
flush operation.
In the following example, all LineItem entities associated with the order are also
removed, as CustomerOrder.getLineItems has cascade=ALL set in the relationship
annotation:
public void removeOrder(Integer orderId) {
try {
CustomerOrder order = em.find(CustomerOrder.class, orderId);
em.remove(order);
}...
37.3.1.7 Synchronizing Entity Data to the Database
The state of persistent entities is synchronized to the database when the transaction
with which the entity is associated commits. If a managed entity is in a bidirectional
relationship with another managed entity, the data will be persisted, based on the
owning side of the relationship.
To force synchronization of the managed entity to the data store, invoke the flush
method of the EntityManager instance. If the entity is related to another entity and the
relationship annotation has the cascade element set to PERSIST or ALL, the related
entity's data will be synchronized with the data store when flush is called.
If the entity is removed, calling flush will remove the entity data from the data store.
37.3.2 Persistence Units
A persistence unit defines a set of all entity classes that are managed by
EntityManager instances in an application. This set of entity classes represents the data
contained within a single data store.
Persistence units are defined by the persistence.xml configuration file. The following
is an example persistence.xml file:
<persistence>
<persistence-unit name="OrderManagement">
<description>This unit manages orders and customers.
Introduction to the Java Persistence API
37-17
Querying Entities
It does not rely on any vendor-specific features and can
therefore be deployed to any persistence provider.
</description>
<jta-data-source>jdbc/MyOrderDB</jta-data-source>
<jar-file>MyOrderApp.jar</jar-file>
<class>com.widgets.CustomerOrder</class>
<class>com.widgets.Customer</class>
</persistence-unit>
</persistence>
This file defines a persistence unit named OrderManagement, which uses a JTA-aware
data source, jdbc/MyOrderDB. The jar-file and class elements specify managed
persistence classes: entity classes, embeddable classes, and mapped superclasses. The
jar-file element specifies JAR files that are visible to the packaged persistence unit
that contain managed persistence classes, whereas the class element explicitly names
managed persistence classes.
The jta-data-source (for JTA-aware data sources) and non-jta-data-source (for
non-JTA-aware data sources) elements specify the global JNDI name of the data source
to be used by the container.
The JAR file or directory whose META-INF directory contains persistence.xml is called
the root of the persistence unit. The scope of the persistence unit is determined by the
persistence unit's root. Each persistence unit must be identified with a name that is
unique to the persistence unit's scope.
Persistent units can be packaged as part of a WAR or EJB JAR file or can be packaged
as a JAR file that can then be included in an WAR or EAR file.
■
■
■
If you package the persistent unit as a set of classes in an EJB JAR file,
persistence.xml should be put in the EJB JAR's META-INF directory.
If you package the persistence unit as a set of classes in a WAR file,
persistence.xml should be located in the WAR file's WEB-INF/classes/META-INF
directory.
If you package the persistence unit in a JAR file that will be included in a WAR or
EAR file, the JAR file should be located in either
–
The WEB-INF/lib directory of a WAR
–
Or the EAR file's library directory
In the Java Persistence API 1.0, JAR files could be located at
the root of an EAR file as the root of the persistence unit. This is no
longer supported. Portable applications should use the EAR file's
library directory as the root of the persistence unit.
Note:
37.4 Querying Entities
The Java Persistence API provides the following methods for querying entities.
■
■
The Java Persistence query language (JPQL) is a simple, string-based language
similar to SQL used to query entities and their relationships. See Chapter 39, "The
Java Persistence Query Language" for more information.
The Criteria API is used to create typesafe queries using Java programming
language APIs to query for entities and their relationships. See Chapter 40, "Using
the Criteria API to Create Queries" for more information.
37-18 The Java EE 7 Tutorial
Database Schema Creation
Both JPQL and the Criteria API have advantages and disadvantages.
Just a few lines long, JPQL queries are typically more concise and more readable than
Criteria queries. Developers familiar with SQL will find it easy to learn the syntax of
JPQL. JPQL named queries can be defined in the entity class using a Java
programming language annotation or in the application's deployment descriptor.
JPQL queries are not typesafe, however, and require a cast when retrieving the query
result from the entity manager. This means that type-casting errors may not be caught
at compile time. JPQL queries don't support open-ended parameters.
Criteria queries allow you to define the query in the business tier of the application.
Although this is also possible using JPQL dynamic queries, Criteria queries provide
better performance because JPQL dynamic queries must be parsed each time they are
called. Criteria queries are typesafe and therefore don't require casting, as JPQL
queries do. The Criteria API is just another Java programming language API and
doesn't require developers to learn the syntax of another query language. Criteria
queries are typically more verbose than JPQL queries and require the developer to
create several objects and perform operations on those objects before submitting the
query to the entity manager.
37.5 Database Schema Creation
The persistence provider can be configured to automatically create the database tables,
load data into the tables, and remove the tables during application deployment using
standard properties in the application's deployment descriptor. These tasks are
typically used during the development phase of a release, not against a production
database.
The following is an example of a persistence.xml deployment descriptor that
specifies that the provider should drop all database artifacts using a provided script,
create the artifacts with a provided script, and load data from a provided script when
the application is deployed:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="examplePU" transaction-type="JTA">
<jta-data-source>java:global/ExampleDataSource</jta-data-source>
<properties>
<property name="javax.persistence.schema-generation.database.action"
value="drop-and-create"/>
<property name="javax.persistence.schema-generation.create-source"
value="script"/>
<property name="javax.persistence.schema-generation.create-script-source"
value="META-INF/sql/create.sql" />
<property name="javax.persistence.sql-load-script-source"
value="META-INF/sql/data.sql" />
<property name="javax.persistence.schema-generation.drop-source"
value="script" />
<property name="javax.persistence.schema-generation.drop-script-source"
value="META-INF/sql/drop.sql" />
</properties>
</persistence-unit>
</persistence>
Introduction to the Java Persistence API
37-19
Database Schema Creation
37.5.1 Configuring an Application to Create or Drop Database Tables
The javax.persistence.schema-generation.database.action property is used to
specify the action taken by the persistence provider when an application is deployed.
If the property is not set, the persistence provider will not create or drop any database
artifacts.
Table 37–3
Schema Creation Actions
Setting
Description
none
No schema creation or deletion will take place.
create
The provider will create the database artifacts on application
deployment. The artifacts will remain unchanged after
application redeployment.
drop-and-create
Any artifacts in the database will be deleted, and the provider
will create the database artifacts on deployment.
drop
Any artifacts in the database will be deleted on application
deployment.
In this example, the persistence provider will delete any remaining database artifacts
and then create the artifacts when the application is deployed:
<property name="javax.persistence.schema-generation.database.action"
value="drop-and-create"/>
By default, the object/relational metadata in the persistence unit is used to create the
database artifacts. You may also supply scripts used by the provider to create and
delete the database artifacts. The
javax.persistence.schema-generation.create-source and
javax.persistence.schema-generation.drop-source properties control how the
provider will create or delete the database artifacts.
Table 37–4
Settings for Create and Delete Source Properties
Setting
Description
metadata
Use the object/relational metadata in the application to create or
delete the database artifacts.
script
Use a provided script for creating or deleting the database
artifacts.
metadata-then-script
Use a combination of object/relational metadata, then a
user-provided script to create or delete the database artifacts.
script-then-metadata
Use a combination of a user-provided script, then the
object/relational metadata to create and delete the database
artifacts.
In this example, the persistence provider will use a script packaged within the
application to create the database artifacts:
<property name="javax.persistence.schema-generation.create-source"
value="script"/>
If you specify a script in create-source or drop-source, specify the location of the
script using the javax.persistence.schema-generation.create-script-source or
javax.persistence.schema-generation.drop-script-source property. The location
of the script is relative to the root of the persistence unit:
37-20 The Java EE 7 Tutorial
Further Information about Persistence
<property name="javax.persistence.schema-generation.create-script-source"
value="META-INF/sql/create.sql" />
In the above example, the create-script-source is set to a SQL file called create.sql
in the META-INF/sql directory relative to root of the persistence unit.
37.5.2 Loading Data Using SQL Scripts
If you want to populate the database tables with data before the application loads,
specify the location of a load script in the
javax.persistence.sql-load-script-source property. The location specified in this
property is relative to the root of the persistence unit.
In this example, the load script is a file called data.sql in the META-INF/sql directory
relative to the root of the persistence unit:
<property name="javax.persistence.sql-load-script-source"
value="META-INF/sql/data.sql" />
37.6 Further Information about Persistence
For more information about the Java Persistence API, see
■
Java Persistence 2.1 API specification:
http://jcp.org/en/jsr/detail?id=338
■
EclipseLink, the Java Persistence API implementation in GlassFish Server:
http://www.eclipse.org/eclipselink/jpa.php
■
EclipseLink team blog:
http://eclipselink.blogspot.com/
■
EclipseLink wiki documentation:
http://wiki.eclipse.org/EclipseLink
Introduction to the Java Persistence API
37-21
Further Information about Persistence
37-22 The Java EE 7 Tutorial
38
Running the Persistence Examples
38
This chapter explains how to use the Java Persistence API. The material here focuses
on the source code and settings of three examples. The first example, order, is an
application that uses a stateful session bean to manage entities related to an ordering
system. The second example, roster, is an application that manages a community
sports system. The third example, address-book, is a web application that stores
contact data. This chapter assumes that you are familiar with the concepts detailed in
Chapter 37, "Introduction to the Java Persistence API".
The following topics are addressed here:
■
The order Application
■
The roster Application
■
The address-book Application
38.1 The order Application
The order application is a simple inventory and ordering application for maintaining a
catalog of parts and placing an itemized order of those parts. The application has
entities that represent parts, vendors, orders, and line items. These entities are accessed
using a stateful session bean that holds the business logic of the application. A simple
singleton session bean creates the initial entities on application deployment. A Facelets
web application manipulates the data and displays data from the catalog.
The information contained in an order can be divided into elements. What is the order
number? What parts are included in the order? What parts make up that part? Who
makes the part? What are the specifications for the part? Are there any schematics for
the part? The order application is a simplified version of an ordering system that has
all these elements.
The order application consists of a single WAR module that includes the enterprise
bean classes, the entities, the support classes, and the Facelets XHTML and class files.
The database schema in the Java DB database for order is shown in Figure 38–1.
Running the Persistence Examples 38-1
The order Application
Figure 38–1 Database Schema for the order Application
CUSTOMERORDER
LINEITEM
ORDERID
INT
ITEMID
INT
DISCOUNT
INT
ORDERID
INT
TIMESTAMP
LASTUPDATE
QUANTITY
VARCHAR(255)
SHIPMENTINFO
INT
VENDORPARTNUMBER
BIGINT
CHAR(1)
STATUS
VENDOR_PART
VENDOR
BIGINT
VENDORPARTNUMBER
DESCRIPTION
PRICE
VARCHAR(255)
ADDRESS
VARCHAR(255)
DOUBLE(52,0)
CONTACT
VARCHAR(255)
VENDORNAME
VARCHAR(255)
PHONE
VARCHAR(255)
INT
VENDORID
VARCHAR(255)
PARTNUMBER
INT
VENDORID
INT
PARTREVISION
PART
PART_DETAIL
INT
REVISION
PARTNUMBER
VARCHAR(255)
PARTNUMBER
VARCHAR(255)
REVISION
INT
DESCRIPTION
VARCHAR(255)
DRAWING
BLOB
SPECIFICATION
BLOB
DATE
REVISIONDATE
INT
BOMREVISION
VARCHAR(255)
BOMPARTNUMBER
Primary key
Primary foreign key
Foreign key
Field
In this diagram, for simplicity, the PERSISTENCE_ORDER_ prefix
is omitted from the table names.
Note:
38.1.1 Entity Relationships in the order Application
The order application demonstrates several types of entity relationships:
self-referential, one-to-one, one-to-many, many-to-one, and unidirectional
relationships.
38.1.1.1 Self-Referential Relationships
A self-referential relationship occurs between relationship fields in the same entity.
Part has a field, bomPart, which has a one-to-many relationship with the field parts,
which is also in Part. That is, a part can be made up of many parts, and each of those
parts has exactly one bill-of-material part.
38-2 The Java EE 7 Tutorial
The order Application
The primary key for Part is a compound primary key, a combination of the
partNumber and revision fields. This key is mapped to the PARTNUMBER and REVISION
columns in the PERSISTENCE_ORDER_PART table:
...
@ManyToOne
@JoinColumns({
@JoinColumn(name="BOMPARTNUMBER", referencedColumnName="PARTNUMBER"),
@JoinColumn(name="BOMREVISION", referencedColumnName="REVISION")
})
public Part getBomPart() {
return bomPart;
}
...
@OneToMany(mappedBy="bomPart")
public Collection<Part> getParts() {
return parts;
}
...
38.1.1.2 One-to-One Relationships
Part has a field, vendorPart, that has a one-to-one relationship with VendorPart's part
field. That is, each part has exactly one vendor part, and vice versa.
Here is the relationship mapping in Part:
@OneToOne(mappedBy="part")
public VendorPart getVendorPart() {
return vendorPart;
}
Here is the relationship mapping in VendorPart:
@OneToOne
@JoinColumns({
@JoinColumn(name="PARTNUMBER", referencedColumnName="PARTNUMBER"),
@JoinColumn(name="PARTREVISION", referencedColumnName="REVISION")
})
public Part getPart() {
return part;
}
Note that, because Part uses a compound primary key, the @JoinColumns annotation is
used to map the columns in the PERSISTENCE_ORDER_VENDOR_PART table to the columns
in PERSISTENCE_ORDER_PART. The PERSISTENCE_ORDER_VENDOR_PART table's
PARTREVISION column refers to PERSISTENCE_ORDER_PART's REVISION column.
38.1.1.3 One-to-Many Relationship Mapped to Overlapping Primary and Foreign
Keys
CustomerOrder has a field, lineItems, that has a one-to-many relationship with
LineItem's field customerOrder. That is, each order has one or more line item.
LineItem uses a compound primary key that is made up of the orderId and itemId
fields. This compound primary key maps to the ORDERID and ITEMID columns in the
PERSISTENCE_ORDER_LINEITEM table. ORDERID is a foreign key to the ORDERID column in
the PERSISTENCE_ORDER_CUSTOMERORDER table. This means that the ORDERID column is
mapped twice: once as a primary key field, orderId; and again as a relationship field,
order.
Running the Persistence Examples 38-3
The order Application
Here is the relationship mapping in CustomerOrder:
@OneToMany(cascade=ALL, mappedBy="customerOrder")
public Collection<LineItem> getLineItems() {
return lineItems;
}
Here is the relationship mapping in LineItem:
@Id
@ManyToOne
@JoinColumn(name="ORDERID")
public CustomerOrder getCustomerOrder() {
return customerOrder;
}
38.1.1.4 Unidirectional Relationships
LineItem has a field, vendorPart, that has a unidirectional many-to-one relationship
with VendorPart. That is, there is no field in the target entity in this relationship:
@JoinColumn(name="VENDORPARTNUMBER")
@ManyToOne
public VendorPart getVendorPart() {
return vendorPart;
}
38.1.2 Primary Keys in the order Application
The order application uses several types of primary keys: single-valued primary keys,
generated primary keys, and compound primary keys.
38.1.2.1 Generated Primary Keys
VendorPart uses a generated primary key value. That is, the application does not
assign primary key values for the entities but instead relies on the persistence provider
to generate the primary key values. The @GeneratedValue annotation is used to specify
that an entity will use a generated primary key.
In VendorPart, the following code specifies the settings for generating primary key
values:
@TableGenerator(
name="vendorPartGen",
table="PERSISTENCE_ORDER_SEQUENCE_GENERATOR",
pkColumnName="GEN_KEY",
valueColumnName="GEN_VALUE",
pkColumnValue="VENDOR_PART_ID",
allocationSize=10)
@Id
@GeneratedValue(strategy=GenerationType.TABLE, generator="vendorPartGen")
public Long getVendorPartNumber() {
return vendorPartNumber;
}
The @TableGenerator annotation is used in conjunction with @GeneratedValue's
strategy=TABLE element. That is, the strategy used to generate the primary keys is to
use a table in the database. The @TableGenerator annotation is used to configure the
settings for the generator table. The name element sets the name of the generator,
which is vendorPartGen in VendorPart.
38-4 The Java EE 7 Tutorial
The order Application
The PERSISTENCE_ORDER_SEQUENCE_GENERATOR table, whose two columns are GEN_KEY
and GEN_VALUE, will store the generated primary key values. This table could be used
to generate other entities' primary keys, so the pkColumnValue element is set to
VENDOR_PART_ID to distinguish this entity's generated primary keys from other entities'
generated primary keys. The allocationSize element specifies the amount to
increment when allocating primary key values. In this case, each VendorPart's primary
key will increment by 10.
The primary key field vendorPartNumber is of type Long, as the generated primary
key's field must be an integral type.
38.1.2.2 Compound Primary Keys
A compound primary key is made up of multiple fields and follows the requirements
described in Primary Keys in Entities. To use a compound primary key, you must
create a wrapper class.
In order, two entities use compound primary keys: Part and LineItem.
■
■
Part uses the PartKey wrapper class. Part's primary key is a combination of the
part number and the revision number. PartKey encapsulates this primary key.
LineItem uses the LineItemKey class. LineItem's primary key is a combination of
the order number and the item number. LineItemKey encapsulates this primary
key.
This is the LineItemKey compound primary key wrapper class:
package javaeetutorial.order.entity;
import java.io.Serializable;
public final class LineItemKey implements Serializable {
private Integer customerOrder;
private int itemId;
public LineItemKey() {}
public LineItemKey(Integer order, int itemId) {
this.setCustomerOrder(order);
this.setItemId(itemId);
}
@Override
public int hashCode() {
return ((this.getCustomerOrder() == null
? 0 : this.getCustomerOrder().hashCode())
^ ((int) this.getItemId()));
}
@Override
public boolean equals(Object otherOb) {
if (this == otherOb) {
return true;
}
if (!(otherOb instanceof LineItemKey)) {
return false;
}
LineItemKey other = (LineItemKey) otherOb;
return ((this.getCustomerOrder() == null
Running the Persistence Examples 38-5
The order Application
? other.getCustomerOrder == null : this.getOrderId()
.equals(other.getCustomerOrder()))
&& (this.getItemId == oother.getItemId()));
}
@Override
public String toString() {
return "" + getCustomerOrder() + "-" + getItemId();
}
public Integer getCustomerOrder() {
return customerOrder;
}
public void setCustomerOrder(Integer order) {
this.customerOrder = order;
}
public int getItemId() {
return itemId;
}
public void setItemId(int itemId) {
this.itemId = itemId;
}
}
The @IdClass annotation is used to specify the primary key class in the entity class. In
LineItem, @IdClass is used as follows:
@IdClass(LineItemKey.class)
@Entity
...
public class LineItem implements Serializable {
...
}
The two fields in LineItem are tagged with the @Id annotation to mark those fields as
part of the compound primary key:
@Id
public int getItemId() {
return itemId;
}
...
@Id
@ManyToOne
@JoinColumn(name="ORDERID")
public CustomerOrder getCustomerOrder() {
return customerOrder;
}
For customerOrder, you also use the @JoinColumn annotation to specify the column
name in the table and that this column is an overlapping foreign key pointing at the
PERSISTENCE_ORDER_CUSTOMERORDER table's ORDERID column (see One-to-Many
Relationship Mapped to Overlapping Primary and Foreign Keys). That is,
customerOrder will be set by the CustomerOrder entity.
In LineItem's constructor, the line item number (LineItem.itemId) is set using the
CustomerOrder.getNextId method:
38-6 The Java EE 7 Tutorial
The order Application
public LineItem(CustomerOrder order, int quantity, VendorPart vendorPart) {
this.customerOrder = order;
this.itemId = order.getNextId();
this.quantity = quantity;
this.vendorPart = vendorPart;
}
CustomerOrder.getNextId counts the number of current line items, adds 1, and
returns that number:
@Transient
public int getNextId() {
return this.lineItems.size() + 1;
}
Part requires the @Column annotation on the two fields that comprise Part's compound
primary key, because Part's compound primary key is an overlapping primary
key/foreign key:
@IdClass(PartKey.class)
@Entity
...
public class Part implements Serializable {
...
@Id
@Column(nullable=false)
public String getPartNumber() {
return partNumber;
}
...
@Id
@Column(nullable=false)
public int getRevision() {
return revision;
}
...
}
38.1.3 Entity Mapped to More Than One Database Table
Part's fields map to more than one database table: PERSISTENCE_ORDER_PART and
PERSISTENCE_ORDER_PART_DETAIL. The PERSISTENCE_ORDER_PART_DETAIL table holds
the specification and schematics for the part. The @SecondaryTable annotation is used
to specify the secondary table:
...
@Entity
@Table(name="PERSISTENCE_ORDER_PART")
@SecondaryTable(name="PERSISTENCE_ORDER_PART_DETAIL", pkJoinColumns={
@PrimaryKeyJoinColumn(name="PARTNUMBER",
referencedColumnName="PARTNUMBER"),
@PrimaryKeyJoinColumn(name="REVISION",
referencedColumnName="REVISION")
})
public class Part implements Serializable {
...
}
PERSISTENCE_ORDER_PART_DETAIL and PERSISTENCE_ORDER_PART share the same
primary key values. The pkJoinColumns element of @SecondaryTable is used to specify
Running the Persistence Examples 38-7
The order Application
that PERSISTENCE_ORDER_PART_DETAIL's primary key columns are foreign keys to
PERSISTENCE_ORDER_PART. The @PrimaryKeyJoinColumn annotation sets the primary
key column names and specifies which column in the primary table the column refers
to. In this case, the primary key column names for both PERSISTENCE_ORDER_PART_
DETAIL and PERSISTENCE_ORDER_PART are the same: PARTNUMBER and REVISION,
respectively.
38.1.4 Cascade Operations in the order Application
Entities that have relationships to other entities often have dependencies on the
existence of the other entity in the relationship. For example, a line item is part of an
order; if the order is deleted, then the line item also should be deleted. This is called a
cascade delete relationship.
In order, there are two cascade delete dependencies in the entity relationships. If the
CustomerOrder to which a LineItem is related is deleted, the LineItem also should be
deleted. If the Vendor to which a VendorPart is related is deleted, the VendorPart also
should be deleted.
You specify the cascade operations for entity relationships by setting the cascade
element in the inverse (nonowning) side of the relationship. The cascade element is set
to ALL in the case of CustomerOrder.lineItems. This means that all persistence
operations (deletes, updates, and so on) are cascaded from orders to line items.
Here is the relationship mapping in CustomerOrder:
@OneToMany(cascade=ALL, mappedBy="customerOrder")
public Collection<LineItem> getLineItems() {
return lineItems;
}
Here is the relationship mapping in LineItem:
@Id
@ManyToOne
@JoinColumn(name="ORDERID")
public CustomerOrder getCustomerOrder() {
return customerOrder;
}
38.1.5 BLOB and CLOB Database Types in the order Application
The PARTDETAIL table in the database has a column, DRAWING, of type BLOB. BLOB stands
for binary large objects, which are used for storing binary data, such as an image. The
DRAWING column is mapped to the field Part.drawing of type java.io.Serializable.
The @Lob annotation is used to denote that the field is a large object:
@Column(table="PERSISTENCE_ORDER_PART_DETAIL")
@Lob
public Serializable getDrawing() {
return drawing;
}
PERSISTENCE_ORDER_PART_DETAIL also has a column, SPECIFICATION, of type CLOB.
CLOB stands for character large objects, which are used to store string data too large to
be stored in a VARCHAR column. SPECIFICATION is mapped to the field
Part.specification of type java.lang.String. The @Lob annotation is also used here
to denote that the field is a large object:
@Column(table="PERSISTENCE_ORDER_PART_DETAIL")
38-8 The Java EE 7 Tutorial
The order Application
@Lob
public String getSpecification() {
return specification;
}
Both of these fields use the @Column annotation and set the table element to the
secondary table.
38.1.6 Temporal Types in the order Application
The CustomerOrder.lastUpdate persistent property, which is of type java.util.Date,
is mapped to the PERSISTENCE_ORDER_CUSTOMERORDER.LASTUPDATE database field,
which is of the SQL type TIMESTAMP. To ensure the proper mapping between these
types, you must use the @Temporal annotation with the proper temporal type specified
in @Temporal's element. @Temporal's elements are of type
javax.persistence.TemporalType. The possible values are
■
DATE, which maps to java.sql.Date
■
TIME, which maps to java.sql.Time
■
TIMESTAMP, which maps to java.sql.Timestamp
Here is the relevant section of CustomerOrder:
@Temporal(TIMESTAMP)
public Date getLastUpdate() {
return lastUpdate;
}
38.1.7 Managing the order Application's Entities
The RequestBean stateful session bean contains the business logic and manages the
entities of order. RequestBean uses the @PersistenceContext annotation to retrieve an
entity manager instance, which is used to manage order's entities in RequestBean's
business methods:
@PersistenceContext
private EntityManager em;
This EntityManager instance is a container-managed entity manager, so the container
takes care of all the transactions involved in managing order's entities.
38.1.7.1 Creating Entities
The RequestBean.createPart business method creates a new Part entity. The
EntityManager.persist method is used to persist the newly created entity to the
database:
Part part = new Part(partNumber,
revision,
description,
revisionDate,
specification,
drawing);
em.persist(part);
The ConfigBean singleton session bean is used to initialize the data in order.
ConfigBean is annotated with @Startup, which indicates that the EJB container should
create ConfigBean when order is deployed. The createData method is annotated with
Running the Persistence Examples 38-9
The order Application
@PostConstruct and creates the initial entities used by order by calling RequestBean's
business methods.
38.1.7.2 Finding Entities
The RequestBean.getOrderPrice business method returns the price of a given order
based on the orderId. The EntityManager.find method is used to retrieve the entity
from the database:
CustomerOrder order = em.find(CustomerOrder.class, orderId);
The first argument of EntityManager.find is the entity class, and the second is the
primary key.
38.1.7.3 Setting Entity Relationships
The RequestBean.createVendorPart business method creates a VendorPart associated
with a particular Vendor. The EntityManager.persist method is used to persist the
newly created VendorPart entity to the database, and the VendorPart.setVendor and
Vendor.setVendorPart methods are used to associate the VendorPart with the Vendor:
PartKey pkey = new PartKey();
pkey.setPartNumber(partNumber);
pkey.setRevision(revision);
Part part = em.find(Part.class, pkey);
VendorPart vendorPart = new VendorPart(description, price, part);
em.persist(vendorPart);
Vendor vendor = em.find(Vendor.class, vendorId);
vendor.addVendorPart(vendorPart);
vendorPart.setVendor(vendor);
38.1.7.4 Using Queries
The RequestBean.adjustOrderDiscount business method updates the discount
applied to all orders. This method uses the findAllOrders named query, defined in
CustomerOrder:
@NamedQuery(
name="findAllOrders",
query="SELECT co FROM CustomerOrder co " +
"ORDER BY co.orderId"
)
The EntityManager.createNamedQuery method is used to run the query. Because the
query returns a List of all the orders, the Query.getResultList method is used:
List orders = em.createNamedQuery(
"findAllOrders")
.getResultList();
The RequestBean.getTotalPricePerVendor business method returns the total price of
all the parts for a particular vendor. This method uses a named parameter, id, defined
in the named query findTotalVendorPartPricePerVendor defined in VendorPart:
@NamedQuery(
name="findTotalVendorPartPricePerVendor",
query="SELECT SUM(vp.price) " +
"FROM VendorPart vp " +
38-10 The Java EE 7 Tutorial
The order Application
"WHERE vp.vendor.vendorId = :id"
)
When running the query, the Query.setParameter method is used to set the named
parameter id to the value of vendorId, the parameter to
RequestBean.getTotalPricePerVendor:
return (Double) em.createNamedQuery(
"findTotalVendorPartPricePerVendor")
.setParameter("id", vendorId)
.getSingleResult();
The Query.getSingleResult method is used for this query because the query returns a
single value.
38.1.7.5 Removing Entities
The RequestBean.removeOrder business method deletes a given order from the
database. This method uses the EntityManager.remove method to delete the entity
from the database:
CustomerOrder order = em.find(CustomerOrder.class, orderId);
em.remove(order);
38.1.8 Running the order Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
order application. First, you will create the database tables in the Java DB server.
38.1.8.1 To Run the order Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
If the database server is not already running, start it by following the instructions
in Starting and Stopping the Java DB Server.
3.
From the File menu, choose Open Project.
4.
In the Open Project dialog box, navigate to:
tut-install/examples/persistence
5.
Select the order folder.
6.
Click Open Project.
7.
In the Projects tab, right-click the order project and select Run.
NetBeans IDE opens a web browser to the following URL:
http://localhost:8080/order/
38.1.8.2 To Run the order Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
If the database server is not already running, start it by following the instructions
in Starting and Stopping the Java DB Server.
3.
In a terminal window, go to:
tut-install/examples/persistence/order/
Running the Persistence Examples
38-11
The roster Application
4.
Enter the following command:
mvn install
This compiles the source files and packages the application into a WAR file located
at tut-install/examples/persistence/order/target/order.war. Then the WAR file
is deployed to your GlassFish Server instance.
5.
To create and update the order data, open a web browser to the following URL:
http://localhost:8080/order/
38.2 The roster Application
The roster application maintains the team rosters for players in recreational sports
leagues. The application has four components: Java Persistence API entities (Player,
Team, and League), a stateful session bean (RequestBean), an application client
(RosterClient), and three helper classes (PlayerDetails, TeamDetails, and
LeagueDetails).
Functionally, roster is similar to the order application, with three new features that
order does not have: many-to-many relationships, entity inheritance, and automatic
table creation at deployment time.
The database schema in the Java DB database for the roster application is shown in
Figure 38–2.
Figure 38–2 Database Schema for the roster Application
TEAM_PLAYER
PLAYER
PLAYER_ID
VARCHAR(255)
ID
VARCHAR(255)
TEAM_ID
VARCHAR(255)
NAME
VARCHAR(255)
POSITION
VARCHAR(255)
SALARY
DOUBLE(52,0)
TEAM
ID
VARCHAR(255)
CITY
VARCHAR(255)
NAME
VARCHAR(255)
LEAGUE_ID
VARCHAR(255)
LEAGUE
ID
VARCHAR(255)
Primary key
DTYPE
VARCHAR(31)
Foreign key
NAME
VARCHAR(255)
Field
SPORT
VARCHAR(255)
In this diagram, for simplicity, the PERSISTENCE_ROSTER_
prefix is omitted from the table names.
Note:
38-12 The Java EE 7 Tutorial
The roster Application
38.2.1 Relationships in the roster Application
A recreational sports system has the following relationships.
■
A player can be on many teams.
■
A team can have many players.
■
A team is in exactly one league.
■
A league has many teams.
In roster this system is reflected by the following relationships between the Player,
Team, and League entities.
■
There is a many-to-many relationship between Player and Team.
■
There is a many-to-one relationship between Team and League.
38.2.1.1 The Many-To-Many Relationship in roster
The many-to-many relationship between Player and Team is specified by using the
@ManyToMany annotation. In Team.java, the @ManyToMany annotation decorates the
getPlayers method:
@ManyToMany
@JoinTable(
name="PERSISTENCE_ROSTER_TEAM_PLAYER",
joinColumns=
@JoinColumn(name="TEAM_ID", referencedColumnName="ID"),
inverseJoinColumns=
@JoinColumn(name="PLAYER_ID", referencedColumnName="ID")
)
public Collection<Player> getPlayers() {
return players;
}
The @JoinTable annotation is used to specify a database table that will associate
player IDs with team IDs. The entity that specifies the @JoinTable is the owner of the
relationship, so the Team entity is the owner of the relationship with the Player entity.
Because roster uses automatic table creation at deployment time, the container will
create a join table named PERSISTENCE_ROSTER_TEAM_PLAYER.
Player is the inverse, or nonowning, side of the relationship with Team. As one-to-one
and many-to-one relationships, the nonowning side is marked by the mappedBy
element in the relationship annotation. Because the relationship between Player and
Team is bidirectional, the choice of which entity is the owner of the relationship is
arbitrary.
In Player.java, the @ManyToMany annotation decorates the getTeams method:
@ManyToMany(mappedBy="players")
public Collection<Team> getTeams() {
return teams;
}
38.2.2 Entity Inheritance in the roster Application
The roster application shows how to use entity inheritance, as described in Entity
Inheritance.
Running the Persistence Examples
38-13
The roster Application
The League entity in roster is an abstract entity with two concrete subclasses:
SummerLeague and WinterLeague. Because League is an abstract class, it cannot be
instantiated:
@Entity
@Table(name = "PERSISTENCE_ROSTER_LEAGUE")
public abstract class League implements Serializable { ... }
Instead, when creating a league, clients use SummerLeague or WinterLeague.
SummerLeague and WinterLeague inherit the persistent properties defined in League
and add only a constructor that verifies that the sport parameter matches the type of
sport allowed in that seasonal league. For example, here is the SummerLeague entity:
...
@Entity
public class SummerLeague extends League implements Serializable {
/** Creates a new instance of SummerLeague */
public SummerLeague() {
}
public SummerLeague(String id, String name, String sport)
throws IncorrectSportException {
this.id = id;
this.name = name;
if (sport.equalsIgnoreCase("swimming") ||
sport.equalsIgnoreCase("soccer") ||
sport.equalsIgnoreCase("basketball") ||
sport.equalsIgnoreCase("baseball")) {
this.sport = sport;
} else {
throw new IncorrectSportException("Sport is not a summer sport.");
}
}
}
The roster application uses the default mapping strategy of
InheritanceType.SINGLE_TABLE, so the @Inheritance annotation is not required. If
you want to use a different mapping strategy, decorate League with @Inheritance and
specify the mapping strategy in the strategy element:
@Entity
@Inheritance(strategy=JOINED)
@Table(name="PERSISTENCE_ROSTER_LEAGUE")
public abstract class League implements Serializable { ... }
The roster application uses the default discriminator column name, so the
@DiscriminatorColumn annotation is not required. Because you are using automatic
table generation in roster, the Persistence provider will create a discriminator column
called DTYPE in the PERSISTENCE_ROSTER_LEAGUE table, which will store the name of
the inherited entity used to create the league. If you want to use a different name for
the discriminator column, decorate League with @DiscriminatorColumn and set the
name element:
@Entity
@DiscriminatorColumn(name="DISCRIMINATOR")
@Table(name="PERSISTENCE_ROSTER_LEAGUE")
public abstract class League implements Serializable { ... }
38-14 The Java EE 7 Tutorial
The roster Application
38.2.3 Criteria Queries in the roster Application
The roster application uses Criteria API queries, as opposed to the JPQL queries used
in order. Criteria queries are Java programming language, typesafe queries defined in
the business tier of roster, in the RequestBean stateful session bean.
38.2.3.1 Metamodel Classes in the roster Application
Metamodel classes model an entity's attributes and are used by Criteria queries to
navigate to an entity's attributes. Each entity class in roster has a corresponding
metamodel class, generated at compile time, with the same package name as the entity
and appended with an underscore character (_). For example, the
roster.entity.Player entity has a corresponding metamodel class,
roster.entity.Player_.
Each persistent field or property in the entity class has a corresponding attribute in the
entity's metamodel class. For the Player entity, the corresponding metamodel class is
as follows:
@StaticMetamodel(Player.class)
public class Player_ {
public static volatile SingularAttribute<Player, String>
public static volatile SingularAttribute<Player, String>
public static volatile SingularAttribute<Player, String>
public static volatile SingularAttribute<Player, Double>
public static volatile CollectionAttribute<Player, Team>
}
id;
name;
position;
salary;
teams;
38.2.3.2 Obtaining a CriteriaBuilder Instance in RequestBean
The CriteriaBuilder interface defines methods to create criteria query objects and
create expressions for modifying those query objects. RequestBean creates an instance
of CriteriaBuilder by using a @PostConstruct method, init:
@PersistenceContext
private EntityManager em;
private CriteriaBuilder cb;
@PostConstruct
private void init() {
cb = em.getCriteriaBuilder();
}
The EntityManager instance is injected at runtime, and then that EntityManager object
is used to create the CriteriaBuilder instance by calling getCriteriaBuilder. The
CriteriaBuilder instance is created in a @PostConstruct method to ensure that the
EntityManager instance has been injected by the enterprise bean container.
38.2.3.3 Creating Criteria Queries in RequestBean's Business Methods
Many of the business methods in RequestBean define Criteria queries. One business
method, getPlayersByPosition, returns a list of players who play a particular
position on a team:
public List<PlayerDetails> getPlayersByPosition(String position) {
logger.info("getPlayersByPosition");
List<Player> players = null;
try {
CriteriaQuery<Player> cq = cb.createQuery(Player.class);
if (cq != null) {
Running the Persistence Examples
38-15
The roster Application
Root<Player> player = cq.from(Player.class);
// set the where clause
cq.where(cb.equal(player.get(Player_.position), position));
cq.select(player);
TypedQuery<Player> q = em.createQuery(cq);
players = q.getResultList();
}
return copyPlayersToDetails(players);
} catch (Exception ex) {
throw new EJBException(ex);
}
}
A query object is created by calling the CriteriaBuilder object's createQuery method,
with the type set to Player because the query will return a list of players.
The query root, the base entity from which the query will navigate to find the entity's
attributes and related entities, is created by calling the from method of the query
object. This sets the FROM clause of the query.
The WHERE clause, set by calling the where method on the query object, restricts the
results of the query according to the conditions of an expression. The
CriteriaBuilder.equal method compares the two expressions. In
getPlayersByPosition, the position attribute of the Player_ metamodel class,
accessed by calling the get method of the query root, is compared to the position
parameter passed to getPlayersByPosition.
The SELECT clause of the query is set by calling the select method of the query object.
The query will return Player entities, so the query root object is passed as a parameter
to select.
The query object is prepared for execution by calling EntityManager.createQuery,
which returns a TypedQuery<T> object with the type of the query, in this case Player.
This typed query object is used to execute the query, which occurs when the
getResultList method is called, and a List<Player> collection is returned.
38.2.4 Automatic Table Generation in the roster Application
At deployment time, GlassFish Server will automatically drop and create the database
tables used by roster. This is done by setting the
javax.persistence.schema-generation.database.action property to
drop-and-create in persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="em" transaction-type="JTA">
<jta-data-source>java:comp/DefaultDataSource</jta-data-source>
<properties>
<property name="javax.persistence.schema-generation.database.action"
value="drop-and-create"/>
</properties>
</persistence-unit>
</persistence>
38-16 The Java EE 7 Tutorial
The roster Application
38.2.5 Running the roster Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
roster application.
38.2.5.1 To Run the roster Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
If the database server is not already running, start it by following the instructions
in Starting and Stopping the Java DB Server.
3.
From the File menu, choose Open Project.
4.
In the Open Project dialog box, navigate to:
tut-install/examples/persistence
5.
Select the roster folder.
6.
Select the Open Required Projects check box.
7.
Click Open Project.
8.
In the Projects tab, right-click the roster project and select Build.
This will compile, package, and deploy the EAR to GlassFish Server.
You will see the following partial output from the application client in the Output
tab:
List all players in team T2:
P6 Ian Carlyle goalkeeper 555.0
P7 Rebecca Struthers midfielder 777.0
P8 Anne Anderson forward 65.0
P9 Jan Wesley defender 100.0
P10 Terry Smithson midfielder 100.0
List all teams in league L1:
T1 Honey Bees Visalia
T2 Gophers Manteca
T5 Crows Orland
List all defenders:
P2 Alice Smith defender 505.0
P5 Barney Bold defender 100.0
P9 Jan Wesley defender 100.0
P22 Janice Walker defender 857.0
P25 Frank Fletcher defender 399.0
38.2.5.2 To Run the roster Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
If the database server is not already running, start it by following the instructions
in Starting and Stopping the Java DB Server.
3.
In a terminal window, go to:
tut-install/examples/persistence/roster/roster-ear/
4.
Enter the following command:
Running the Persistence Examples
38-17
The address-book Application
mvn install
This compiles the source files and packages the application into an EAR file
located at tut-install/examples/persistence/roster/target/roster.ear. The
EAR file is then deployed to GlassFish Server. GlassFish Server will then drop and
create the database tables during deployment, as specified in persistence.xml.
After successfully deploying the EAR, the client stubs are retrieved and the
application client is run using the appclient application included with GlassFish
Server.
You will see the output, which begins as follows:
[echo]
[exec]
[exec]
[exec]
[exec]
[exec]
[exec]
running application client container.
List all players in team T2:
P6 Ian Carlyle goalkeeper 555.0
P7 Rebecca Struthers midfielder 777.0
P8 Anne Anderson forward 65.0
P9 Jan Wesley defender 100.0
P10 Terry Smithson midfielder 100.0
[exec]
[exec]
[exec]
[exec]
List all teams in league L1:
T1 Honey Bees Visalia
T2 Gophers Manteca
T5 Crows Orland
[exec]
[exec]
[exec]
[exec]
[exec]
[exec]
List all defenders:
P2 Alice Smith defender 505.0
P5 Barney Bold defender 100.0
P9 Jan Wesley defender 100.0
P22 Janice Walker defender 857.0
P25 Frank Fletcher defender 399.0
38.3 The address-book Application
The address-book example application is a simple web application that stores contact
data. It uses a single entity class, Contact, that uses the Java API for JavaBeans
Validation (Bean Validation) to validate the data stored in the persistent attributes of
the entity, as described in Validating Persistent Fields and Properties.
38.3.1 Bean Validation Constraints in address-book
The Contact entity uses the @NotNull, @Pattern, and @Past constraints on the
persistent attributes.
The @NotNull constraint marks the attribute as a required field. The attribute must be
set to a non-null value before the entity can be persisted or modified. Bean Validation
will throw a validation error if the attribute is null when the entity is persisted or
modified.
The @Pattern constraint defines a regular expression that the value of the attribute
must match before the entity can be persisted or modified. This constraint has two
different uses in address-book.
■
The regular expression declared in the @Pattern annotation on the email field
matches email addresses of the form name@domain name.top level domain, allowing
only valid characters for email addresses. For example, username@example.com
will pass validation, as will firstname.lastname@mail.example.com. However,
firstname,lastname@example.com, which contains an illegal comma character in
the local name, will fail validation.
38-18 The Java EE 7 Tutorial
The address-book Application
■
The mobilePhone and homePhone fields are annotated with a @Pattern constraint
that defines a regular expression to match phone numbers of the form (xxx)
xxx-xxxx.
The @Past constraint is applied to the birthday field, which must be a java.util.Date
in the past.
Here are the relevant parts of the Contact entity class:
@Entity
public class Contact implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotNull
protected String firstName;
@NotNull
protected String lastName;
@Pattern(regexp = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\."
+ "[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@"
+ "(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9]"
+ "(?:[a-z0-9-]*[a-z0-9])?",
message = "{invalid.email}")
protected String email;
@Pattern(regexp = "^\\(?(\\d{3})\\)?[- ]?(\\d{3})[- ]?(\\d{4})$",
message = "{invalid.phonenumber}")
protected String mobilePhone;
@Pattern(regexp = "^\\(?(\\d{3})\\)?[- ]?(\\d{3})[- ]?(\\d{4})$",
message = "{invalid.phonenumber}")
protected String homePhone;
@Temporal(javax.persistence.TemporalType.DATE)
@Past
protected Date birthday;
...
}
38.3.2 Specifying Error Messages for Constraints in address-book
Some of the constraints in the Contact entity specify an optional message:
@Pattern(regexp = "^\\(?(\\d{3})\\)?[- ]?(\\d{3})[- ]?(\\d{4})$",
message = "{invalid.phonenumber}")
protected String homePhone;
The optional message element in the @Pattern constraint overrides the default
validation message. The message can be specified directly:
@Pattern(regexp = "^\\(?(\\d{3})\\)?[- ]?(\\d{3})[- ]?(\\d{4})$",
message = "Invalid phone number!")
protected String homePhone;
The constraints in Contact, however, are strings in the resource bundle
ValidationMessages.properties, under
tut-install/examples/persistence/address-book/src/java/. This allows the
validation messages to be located in one single properties file and the messages to be
easily localized. Overridden Bean Validation messages must be placed in a resource
bundle properties file named ValidationMessages.properties in the default package,
with localized resource bundles taking the form ValidationMessages_
locale-prefix.properties. For example, ValidationMessages_es.properties is the
resource bundle used in Spanish-speaking locales.
Running the Persistence Examples
38-19
The address-book Application
38.3.3 Validating Contact Input from a JavaServer Faces Application
The address-book application uses a JavaServer Faces web front end to allow users to
enter contacts. While JavaServer Faces has a form input validation mechanism using
tags in Facelets XHTML files, address-book doesn't use these validation tags. Bean
Validation constraints in JavaServer Faces managed beans, in this case in the Contact
entity, automatically trigger validation when the forms are submitted.
The following code snippet from the Create.xhtml Facelets file shows some of the
input form for creating new Contact instances:
<h:form>
<table columns="3" role="presentation">
<tr>
<td><h:outputLabel value="#{bundle.CreateContactLabel_firstName}"
for="firstName" /></td>
<td><h:inputText id="firstName"
value="#{contactController.selected.firstName}"
title="#{bundle.CreateContactTitle_firstName}"/>
</td>
<td><h:message for="firstName" /></td>
</tr>
<tr>
<td><h:outputLabel value="#{bundle.CreateContactLabel_lastName}"
for="lastName" /></td>
<td><h:inputText id="lastName"
value="#{contactController.selected.lastName}"
title="#{bundle.CreateContactTitle_lastName}" />
</td>
<td><h:message for="lastName" /></td>
</tr>
...
</table>
</h:form>
The <h:inputText> tags firstName and lastName are bound to the attributes in the
Contact entity instance selected in the ContactController stateless session bean.
Each <h:inputText> tag has an associated <h:message> tag that will display validation
error messages. The form doesn't require any JavaServer Faces validation tags,
however.
38.3.4 Running the address-book Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
address-book application.
38.3.4.1 To Run the address-book Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
If the database server is not already running, start it by following the instructions
in Starting and Stopping the Java DB Server.
3.
From the File menu, choose Open Project.
4.
In the Open Project dialog box, navigate to:
tut-install/examples/persistence
5.
Select the address-book folder.
38-20 The Java EE 7 Tutorial
The address-book Application
6.
Click Open Project.
7.
In the Projects tab, right-click the address-book project and select Run.
After the application has been deployed, a web browser window appears at the
following URL:
http://localhost:8080/address-book/
8.
Click Show All Contact Items, then Create New Contact. Enter values in the
fields; then click Save.
If any of the values entered violate the constraints in Contact, an error message
will appear in red beside the field with the incorrect values.
38.3.4.2 To Run the address-book Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
If the database server is not already running, start it by following the instructions
in Starting and Stopping the Java DB Server.
3.
In a terminal window, go to:
tut-install/examples/persistence/address-book/
4.
Enter the following command:
mvn install
This will compile and assemble the address-book application into a WAR. The
WAR file is then deployed to GlassFish Server.
5.
Open a web browser window and enter the following URL:
http://localhost:8080/address-book/
6.
Click Show All Contact Items, then Create New Contact. Enter values in the
fields; then click Save.
If any of the values entered violate the constraints in Contact, an error message
will appear in red beside the field with the incorrect values.
Running the Persistence Examples
38-21
The address-book Application
38-22 The Java EE 7 Tutorial
39
The Java Persistence Query Language
39
The Java Persistence query language defines queries for entities and their persistent
state. The query language allows you to write portable queries that work regardless of
the underlying data store.
The query language uses the abstract persistence schemas of entities, including their
relationships, for its data model and defines operators and expressions based on this
data model. The scope of a query spans the abstract schemas of related entities that are
packaged in the same persistence unit. The query language uses an SQL-like syntax to
select objects or values based on entity abstract schema types and relationships among
them.
This chapter relies on the material presented in earlier chapters. For conceptual
information, see Chapter 37, "Introduction to the Java Persistence API". For code
examples, see Chapter 38, "Running the Persistence Examples."
The following topics are addressed here:
■
Query Language Terminology
■
Creating Queries Using the Java Persistence Query Language
■
Simplified Query Language Syntax
■
Example Queries
■
Full Query Language Syntax
39.1 Query Language Terminology
The following list defines some of the terms referred to in this chapter.
■
■
■
■
Abstract schema: The persistent schema abstraction (persistent entities, their state,
and their relationships) over which queries operate. The query language translates
queries over this persistent schema abstraction into queries that are executed over
the database schema to which entities are mapped.
Abstract schema type: The type to which the persistent property of an entity
evaluates in the abstract schema. That is, each persistent field or property in an
entity has a corresponding state field of the same type in the abstract schema. The
abstract schema type of an entity is derived from the entity class and the metadata
information provided by Java language annotations.
Backus-Naur Form (BNF): A notation that describes the syntax of high-level
languages. The syntax diagrams in this chapter are in BNF notation.
Navigation: The traversal of relationships in a query language expression. The
navigation operator is a period.
The Java Persistence Query Language 39-1
Creating Queries Using the Java Persistence Query Language
■
■
■
Path expression: An expression that navigates to an entity's state or relationship
field.
State field: A persistent field of an entity.
Relationship field: A persistent field of an entity whose type is the abstract
schema type of the related entity.
39.2 Creating Queries Using the Java Persistence Query Language
The EntityManager.createQuery and EntityManager.createNamedQuery methods are
used to query the datastore by using Java Persistence query language queries.
The createQuery method is used to create dynamic queries, which are queries defined
directly within an application's business logic:
public List findWithName(String name) {
return em.createQuery(
"SELECT c FROM Customer c WHERE c.name LIKE :custName")
.setParameter("custName", name)
.setMaxResults(10)
.getResultList();
}
The createNamedQuery method is used to create static queries, or queries that are
defined in metadata by using the javax.persistence.NamedQuery annotation. The
name element of @NamedQuery specifies the name of the query that will be used with the
createNamedQuery method. The query element of @NamedQuery is the query:
@NamedQuery(
name="findAllCustomersWithName",
query="SELECT c FROM Customer c WHERE c.name LIKE :custName"
)
Here's an example of createNamedQuery, which uses the @NamedQuery:
@PersistenceContext
public EntityManager em;
...
customers = em.createNamedQuery("findAllCustomersWithName")
.setParameter("custName", "Smith")
.getResultList();
39.2.1 Named Parameters in Queries
Named parameters are query parameters that are prefixed with a colon (:). Named
parameters in a query are bound to an argument by the following method:
javax.persistence.Query.setParameter(String name, Object value)
In the following example, the name argument to the findWithName business method is
bound to the :custName named parameter in the query by calling
Query.setParameter:
public List findWithName(String name) {
return em.createQuery(
"SELECT c FROM Customer c WHERE c.name LIKE :custName")
.setParameter("custName", name)
.getResultList();
}
39-2 The Java EE 7 Tutorial
Simplified Query Language Syntax
Named parameters are case-sensitive and may be used by both dynamic and static
queries.
39.2.2 Positional Parameters in Queries
You may use positional parameters instead of named parameters in queries. Positional
parameters are prefixed with a question mark (?) followed by the numeric position of
the parameter in the query. The method Query.setParameter(integer position,
Object value) is used to set the parameter values.
In the following example, the findWithName business method is rewritten to use input
parameters:
public List findWithName(String name) {
return em.createQuery(
"SELECT c FROM Customer c WHERE c.name LIKE ?1")
.setParameter(1, name)
.getResultList();
}
Input parameters are numbered starting from 1. Input parameters are case-sensitive,
and may be used by both dynamic and static queries.
39.3 Simplified Query Language Syntax
This section briefly describes the syntax of the query language so that you can quickly
move on to Example Queries. When you are ready to learn about the syntax in more
detail, see Full Query Language Syntax.
39.3.1 Select Statements
A select query has six clauses: SELECT, FROM, WHERE, GROUP BY, HAVING, and ORDER BY.
The SELECT and FROM clauses are required, but the WHERE, GROUP BY, HAVING, and ORDER
BY clauses are optional. Here is the high-level BNF syntax of a query language select
query:
QL_statement ::= select_clause from_clause
[where_clause][groupby_clause][having_clause][orderby_clause]
The BNF syntax defines the following clauses.
■
■
■
■
The SELECT clause defines the types of the objects or values returned by the query.
The FROM clause defines the scope of the query by declaring one or more
identification variables, which can be referenced in the SELECT and WHERE clauses.
An identification variable represents one of the following elements:
–
The abstract schema name of an entity
–
An element of a collection relationship
–
An element of a single-valued relationship
–
A member of a collection that is the multiple side of a one-to-many
relationship
The WHERE clause is a conditional expression that restricts the objects or values
retrieved by the query. Although the clause is optional, most queries have a WHERE
clause.
The GROUP BY clause groups query results according to a set of properties.
The Java Persistence Query Language 39-3
Example Queries
■
■
The HAVING clause is used with the GROUP BY clause to further restrict the query
results according to a conditional expression.
The ORDER BY clause sorts the objects or values returned by the query into a
specified order.
39.3.2 Update and Delete Statements
Update and delete statements provide bulk operations over sets of entities. These
statements have the following syntax:
update_statement :: = update_clause [where_clause]
delete_statement :: = delete_clause [where_clause]
The update and delete clauses determine the type of the entities to be updated or
deleted. The WHERE clause may be used to restrict the scope of the update or delete
operation.
39.4 Example Queries
The following queries are from the Player entity of the roster application, which is
documented in The roster Application.
39.4.1 Simple Queries
If you are unfamiliar with the query language, these simple queries are a good place to
start.
39.4.1.1 A Basic Select Query
SELECT p
FROM Player p
■
■
Data retrieved: All players.
Description: The FROM clause declares an identification variable named p, omitting
the optional keyword AS. If the AS keyword were included, the clause would be
written as follows:
FROM Player AS p
The Player element is the abstract schema name of the Player entity.
■
See also: Identification Variables.
39.4.1.2 Eliminating Duplicate Values
SELECT DISTINCT p
FROM Player p
WHERE p.position = ?1
■
Data retrieved: The players with the position specified by the query's parameter.
■
Description: The DISTINCT keyword eliminates duplicate values.
The WHERE clause restricts the players retrieved by checking their position, a
persistent field of the Player entity. The ?1 element denotes the input parameter of
the query.
■
See also: Input Parameters and The DISTINCT Keyword.
39-4 The Java EE 7 Tutorial
Example Queries
39.4.1.3 Using Named Parameters
SELECT DISTINCT p
FROM Player p
WHERE p.position = :position AND p.name = :name
■
■
Data retrieved: The players having the specified positions and names.
Description: The position and name elements are persistent fields of the Player
entity. The WHERE clause compares the values of these fields with the named
parameters of the query, set using the Query.setNamedParameter method. The
query language denotes a named input parameter using a colon (:) followed by an
identifier. The first input parameter is :position, the second is :name.
39.4.2 Queries That Navigate to Related Entities
In the query language, an expression can traverse, or navigate, to related entities.
These expressions are the primary difference between the Java Persistence query
language and SQL. Queries navigates to related entities, whereas SQL joins tables.
39.4.2.1 A Simple Query with Relationships
SELECT DISTINCT p
FROM Player p, IN (p.teams) t
■
■
Data retrieved: All players who belong to a team.
Description: The FROM clause declares two identification variables: p and t. The p
variable represents the Player entity, and the t variable represents the related Team
entity. The declaration for t references the previously declared p variable. The IN
keyword signifies that teams is a collection of related entities. The p.teams
expression navigates from a Player to its related Team. The period in the p.teams
expression is the navigation operator.
You may also use the JOIN statement to write the same query:
SELECT DISTINCT p
FROM Player p JOIN p.teams t
This query could also be rewritten as:
SELECT DISTINCT p
FROM Player p
WHERE p.team IS NOT EMPTY
39.4.2.2 Navigating to Single-Valued Relationship Fields
Use the JOIN clause statement to navigate to a single-valued relationship field:
SELECT t
FROM Team t JOIN t.league l
WHERE l.sport = 'soccer' OR l.sport ='football'
In this example, the query will return all teams that are in either soccer or football
leagues.
39.4.2.3 Traversing Relationships with an Input Parameter
SELECT DISTINCT p
FROM Player p, IN (p.teams) AS t
WHERE t.city = :city
The Java Persistence Query Language 39-5
Example Queries
■
■
Data retrieved: The players whose teams belong to the specified city.
Description: This query is similar to the previous example but adds an input
parameter. The AS keyword in the FROM clause is optional. In the WHERE clause, the
period preceding the persistent variable city is a delimiter, not a navigation
operator. Strictly speaking, expressions can navigate to relationship fields (related
entities) but not to persistent fields. To access a persistent field, an expression uses
the period as a delimiter.
Expressions cannot navigate beyond (or further qualify) relationship fields that are
collections. In the syntax of an expression, a collection-valued field is a terminal
symbol. Because the teams field is a collection, the WHERE clause cannot specify
p.teams.city (an illegal expression).
■
See also: Path Expressions.
39.4.2.4 Traversing Multiple Relationships
SELECT DISTINCT p
FROM Player p, IN (p.teams) t
WHERE t.league = :league
■
■
Data retrieved: The players who belong to the specified league.
Description: The expressions in this query navigate over two relationships. The
p.teams expression navigates the Player-Team relationship, and the t.league
expression navigates the Team-League relationship.
In the other examples, the input parameters are String objects; in this example, the
parameter is an object whose type is a League. This type matches the league
relationship field in the comparison expression of the WHERE clause.
39.4.2.5 Navigating According to Related Fields
SELECT DISTINCT p
FROM Player p, IN (p.teams) t
WHERE t.league.sport = :sport
■
■
Data retrieved: The players who participate in the specified sport.
Description: The sport persistent field belongs to the League entity. To reach the
sport field, the query must first navigate from the Player entity to Team (p.teams)
and then from Team to the League entity (t.league). Because it is not a collection,
the league relationship field can be followed by the sport persistent field.
39.4.3 Queries with Other Conditional Expressions
Every WHERE clause must specify a conditional expression, of which there are several
kinds. In the previous examples, the conditional expressions are comparison
expressions that test for equality. The following examples demonstrate some of the
other kinds of conditional expressions. For descriptions of all conditional expressions,
see WHERE Clause.
39.4.3.1 The LIKE Expression
SELECT p
FROM Player p
WHERE p.name LIKE 'Mich%'
■
Data retrieved: All players whose names begin with "Mich."
39-6 The Java EE 7 Tutorial
Example Queries
■
■
Description: The LIKE expression uses wildcard characters to search for strings
that match the wildcard pattern. In this case, the query uses the LIKE expression
and the % wildcard to find all players whose names begin with the string "Mich."
For example, "Michael" and "Michelle" both match the wildcard pattern.
See also: LIKE Expressions.
39.4.3.2 The IS NULL Expression
SELECT t
FROM Team t
WHERE t.league IS NULL
■
■
■
Data retrieved: All teams not associated with a league.
Description: The IS NULL expression can be used to check whether a relationship
has been set between two entities. In this case, the query checks whether the teams
are associated with any leagues and returns the teams that do not have a league.
See also: NULL Comparison Expressions and NULL Values.
39.4.3.3 The IS EMPTY Expression
SELECT p
FROM Player p
WHERE p.teams IS EMPTY
■
■
■
Data retrieved: All players who do not belong to a team.
Description: The teams relationship field of the Player entity is a collection. If a
player does not belong to a team, the teams collection is empty, and the
conditional expression is TRUE.
See also: Empty Collection Comparison Expressions.
39.4.3.4 The BETWEEN Expression
SELECT DISTINCT p
FROM Player p
WHERE p.salary BETWEEN :lowerSalary AND :higherSalary
■
■
Data retrieved: The players whose salaries fall within the range of the specified
salaries.
Description: This BETWEEN expression has three arithmetic expressions: a persistent
field (p.salary) and the two input parameters (:lowerSalary and
:higherSalary). The following expression is equivalent to the BETWEEN expression:
p.salary >= :lowerSalary AND p.salary <= :higherSalary
■
See also: BETWEEN Expressions.
39.4.3.5 Comparison Operators
SELECT DISTINCT p1
FROM Player p1, Player p2
WHERE p1.salary > p2.salary AND p2.name = :name
■
Data retrieved: All players whose salaries are higher than the salary of the player
with the specified name.
The Java Persistence Query Language 39-7
Full Query Language Syntax
■
■
Description: The FROM clause declares two identification variables (p1 and p2) of
the same type (Player). Two identification variables are needed because the WHERE
clause compares the salary of one player (p2) with that of the other players (p1).
See also: Identification Variables.
39.4.4 Bulk Updates and Deletes
The following examples show how to use the UPDATE and DELETE expressions in
queries. UPDATE and DELETE operate on multiple entities according to the condition or
conditions set in the WHERE clause. The WHERE clause in UPDATE and DELETE queries
follows the same rules as SELECT queries.
39.4.4.1 Update Queries
UPDATE Player p
SET p.status = 'inactive'
WHERE p.lastPlayed < :inactiveThresholdDate
■
Description: This query sets the status of a set of players to inactive if the
player's last game was longer ago than the date specified in
inactiveThresholdDate.
39.4.4.2 Delete Queries
DELETE
FROM Player p
WHERE p.status = 'inactive'
AND p.teams IS EMPTY
■
Description: This query deletes all inactive players who are not on a team.
39.5 Full Query Language Syntax
This section discusses the query language syntax, as defined in the Java Persistence
API 2.0 specification available at http://jcp.org/en/jsr/detail?id=317.
Much of the following material paraphrases or directly quotes the specification.
39.5.1 BNF Symbols
Table 39–1 describes the BNF symbols used in this chapter.
Table 39–1
BNF Symbol Summary
Symbol
Description
::=
The element to the left of the symbol is defined by the constructs on the right.
*
The preceding construct may occur zero or more times.
{...}
The constructs within the braces are grouped together.
[...]
The constructs within the brackets are optional.
|
An exclusive OR.
BOLDFACE
A keyword; although capitalized in the BNF diagram, keywords are not
case-sensitive.
White space
A whitespace character can be a space, a horizontal tab, or a line feed.
39-8 The Java EE 7 Tutorial
Full Query Language Syntax
39.5.2 BNF Grammar of the Java Persistence Query Language
Here is the entire BNF diagram for the query language:
QL_statement ::= select_statement | update_statement | delete_statement
select_statement ::= select_clause from_clause [where_clause] [groupby_clause]
[having_clause] [orderby_clause]
update_statement ::= update_clause [where_clause]
delete_statement ::= delete_clause [where_clause]
from_clause ::=
FROM identification_variable_declaration
{, {identification_variable_declaration |
collection_member_declaration}}*
identification_variable_declaration ::=
range_variable_declaration { join | fetch_join }*
range_variable_declaration ::= abstract_schema_name [AS]
identification_variable
join ::= join_spec join_association_path_expression [AS]
identification_variable
fetch_join ::= join_specFETCH join_association_path_expression
association_path_expression ::=
collection_valued_path_expression |
single_valued_association_path_expression
join_spec::= [LEFT [OUTER] |INNER] JOIN
join_association_path_expression ::=
join_collection_valued_path_expression |
join_single_valued_association_path_expression
join_collection_valued_path_expression::=
identification_variable.collection_valued_association_field
join_single_valued_association_path_expression::=
identification_variable.single_valued_association_field
collection_member_declaration ::=
IN (collection_valued_path_expression) [AS]
identification_variable
single_valued_path_expression ::=
state_field_path_expression |
single_valued_association_path_expression
state_field_path_expression ::=
{identification_variable |
single_valued_association_path_expression}.state_field
single_valued_association_path_expression ::=
identification_variable.{single_valued_association_field.}*
single_valued_association_field
collection_valued_path_expression ::=
identification_variable.{single_valued_association_field.}*
collection_valued_association_field
state_field ::=
{embedded_class_state_field.}*simple_state_field
update_clause ::=UPDATE abstract_schema_name [[AS]
identification_variable] SET update_item {, update_item}*
update_item ::= [identification_variable.]{state_field |
single_valued_association_field} = new_value
new_value ::=
simple_arithmetic_expression |
string_primary |
datetime_primary |
boolean_primary |
enum_primary simple_entity_expression |
NULL
delete_clause ::= DELETE FROM abstract_schema_name [[AS]
identification_variable]
The Java Persistence Query Language 39-9
Full Query Language Syntax
select_clause ::= SELECT [DISTINCT] select_expression {,
select_expression}*
select_expression ::=
single_valued_path_expression |
aggregate_expression |
identification_variable |
OBJECT(identification_variable) |
constructor_expression
constructor_expression ::=
NEW constructor_name(constructor_item {,
constructor_item}*)
constructor_item ::= single_valued_path_expression |
aggregate_expression
aggregate_expression ::=
{AVG |MAX |MIN |SUM} ([DISTINCT]
state_field_path_expression) |
COUNT ([DISTINCT] identification_variable |
state_field_path_expression |
single_valued_association_path_expression)
where_clause ::= WHERE conditional_expression
groupby_clause ::= GROUP BY groupby_item {, groupby_item}*
groupby_item ::= single_valued_path_expression
having_clause ::= HAVING conditional_expression
orderby_clause ::= ORDER BY orderby_item {, orderby_item}*
orderby_item ::= state_field_path_expression [ASC |DESC]
subquery ::= simple_select_clause subquery_from_clause
[where_clause] [groupby_clause] [having_clause]
subquery_from_clause ::=
FROM subselect_identification_variable_declaration
{, subselect_identification_variable_declaration}*
subselect_identification_variable_declaration ::=
identification_variable_declaration |
association_path_expression [AS] identification_variable |
collection_member_declaration
simple_select_clause ::= SELECT [DISTINCT]
simple_select_expression
simple_select_expression::=
single_valued_path_expression |
aggregate_expression |
identification_variable
conditional_expression ::= conditional_term |
conditional_expression OR conditional_term
conditional_term ::= conditional_factor | conditional_term AND
conditional_factor
conditional_factor ::= [NOT] conditional_primary
conditional_primary ::= simple_cond_expression |(
conditional_expression)
simple_cond_expression ::=
comparison_expression |
between_expression |
like_expression |
in_expression |
null_comparison_expression |
empty_collection_comparison_expression |
collection_member_expression |
exists_expression
between_expression ::=
arithmetic_expression [NOT] BETWEEN
arithmetic_expressionAND arithmetic_expression |
string_expression [NOT] BETWEEN string_expression AND
39-10 The Java EE 7 Tutorial
Full Query Language Syntax
string_expression |
datetime_expression [NOT] BETWEEN
datetime_expression AND datetime_expression
in_expression ::=
state_field_path_expression [NOT] IN (in_item {, in_item}*
| subquery)
in_item ::= literal | input_parameter
like_expression ::=
string_expression [NOT] LIKE pattern_value [ESCAPE
escape_character]
null_comparison_expression ::=
{single_valued_path_expression | input_parameter} IS [NOT]
NULL
empty_collection_comparison_expression ::=
collection_valued_path_expression IS [NOT] EMPTY
collection_member_expression ::= entity_expression
[NOT] MEMBER [OF] collection_valued_path_expression
exists_expression::= [NOT] EXISTS (subquery)
all_or_any_expression ::= {ALL |ANY |SOME} (subquery)
comparison_expression ::=
string_expression comparison_operator {string_expression |
all_or_any_expression} |
boolean_expression {= |<> } {boolean_expression |
all_or_any_expression} |
enum_expression {= |<> } {enum_expression |
all_or_any_expression} |
datetime_expression comparison_operator
{datetime_expression | all_or_any_expression} |
entity_expression {= |<> } {entity_expression |
all_or_any_expression} |
arithmetic_expression comparison_operator
{arithmetic_expression | all_or_any_expression}
comparison_operator ::= = |> |>= |< |<= |<>
arithmetic_expression ::= simple_arithmetic_expression |
(subquery)
simple_arithmetic_expression ::=
arithmetic_term | simple_arithmetic_expression {+ |- }
arithmetic_term
arithmetic_term ::= arithmetic_factor | arithmetic_term {* |/ }
arithmetic_factor
arithmetic_factor ::= [{+ |- }] arithmetic_primary
arithmetic_primary ::=
state_field_path_expression |
numeric_literal |
(simple_arithmetic_expression) |
input_parameter |
functions_returning_numerics |
aggregate_expression
string_expression ::= string_primary | (subquery)
string_primary ::=
state_field_path_expression |
string_literal |
input_parameter |
functions_returning_strings |
aggregate_expression
datetime_expression ::= datetime_primary | (subquery)
datetime_primary ::=
state_field_path_expression |
input_parameter |
functions_returning_datetime |
The Java Persistence Query Language
39-11
Full Query Language Syntax
aggregate_expression
boolean_expression ::= boolean_primary | (subquery)
boolean_primary ::=
state_field_path_expression |
boolean_literal |
input_parameter
enum_expression ::= enum_primary | (subquery)
enum_primary ::=
state_field_path_expression |
enum_literal |
input_parameter
entity_expression ::=
single_valued_association_path_expression |
simple_entity_expression
simple_entity_expression ::=
identification_variable |
input_parameter
functions_returning_numerics::=
LENGTH(string_primary) |
LOCATE(string_primary, string_primary[,
simple_arithmetic_expression]) |
ABS(simple_arithmetic_expression) |
SQRT(simple_arithmetic_expression) |
MOD(simple_arithmetic_expression,
simple_arithmetic_expression) |
SIZE(collection_valued_path_expression)
functions_returning_datetime ::=
CURRENT_DATE |
CURRENT_TIME |
CURRENT_TIMESTAMP
functions_returning_strings ::=
CONCAT(string_primary, string_primary) |
SUBSTRING(string_primary,
simple_arithmetic_expression,
simple_arithmetic_expression)|
TRIM([[trim_specification] [trim_character] FROM]
string_primary) |
LOWER(string_primary) |
UPPER(string_primary)
trim_specification ::= LEADING | TRAILING | BOTH
39.5.3 FROM Clause
The FROM clause defines the domain of the query by declaring identification variables.
39.5.3.1 Identifiers
An identifier is a sequence of one or more characters. The first character must be a
valid first character (letter, $, _) in an identifier of the Java programming language,
hereafter in this chapter called simply "Java." Each subsequent character in the
sequence must be a valid nonfirst character (letter, digit, $, _) in a Java identifier. (For
details, see the Java SE API documentation of the isJavaIdentifierStart and
isJavaIdentifierPart methods of the Character class.) The question mark (?) is a
reserved character in the query language and cannot be used in an identifier.
A query language identifier is case-sensitive, with two exceptions:
■
Keywords
■
Identification variables
39-12 The Java EE 7 Tutorial
Full Query Language Syntax
An identifier cannot be the same as a query language keyword. Here is a list of query
language keywords:
ABS
ALL
AND
ANY
AS
ASC
AVG
BETWEEN
BIT_LENGTH
BOTH
BY
CASE
CHAR_LENGTH
CHARACTER_LENGTH
CLASS
COALESCE
CONCAT
COUNT
CURRENT_DATE
CURRENT_TIMESTAMP
DELETE
DESC
DISTINCT
ELSE
EMPTY
END
ENTRY
ESCAPE
EXISTS
FALSE
FETCH
FROM
GROUP
HAVING
IN
INDEX
INNER
IS
JOIN
KEY
LEADING
LEFT
LENGTH
LIKE
LOCATE
LOWER
MAX
MEMBER
MIN
MOD
NEW
NOT
NULL
The Java Persistence Query Language
39-13
Full Query Language Syntax
NULLIF
OBJECT
OF
OR
ORDER
OUTER
POSITION
SELECT
SET
SIZE
SOME
SQRT
SUBSTRING
SUM
THEN
TRAILING
TRIM
TRUE
TYPE
UNKNOWN
UPDATE
UPPER
VALUE
WHEN
WHERE
It is not recommended that you use an SQL keyword as an identifier, because the list
of keywords may expand to include other reserved SQL words in the future.
39.5.3.2 Identification Variables
An identification variable is an identifier declared in the FROM clause. Although they
can reference identification variables, the SELECT and WHERE clauses cannot declare
them. All identification variables must be declared in the FROM clause.
Because it is an identifier, an identification variable has the same naming conventions
and restrictions as an identifier, with the exception that an identification variable is
case-insensitive. For example, an identification variable cannot be the same as a query
language keyword. (See Identifiers for more naming rules.) Also, within a given
persistence unit, an identification variable name must not match the name of any
entity or abstract schema.
The FROM clause can contain multiple declarations, separated by commas. A
declaration can reference another identification variable that has been previously
declared (to the left). In the following FROM clause, the variable t references the
previously declared variable p:
FROM Player p, IN (p.teams) AS t
Even if it is not used in the WHERE clause, an identification variable's declaration can
affect the results of the query. For example, compare the next two queries. The
following query returns all players, whether or not they belong to a team:
SELECT p
FROM Player p
In contrast, because it declares the t identification variable, the next query fetches all
players who belong to a team:
39-14 The Java EE 7 Tutorial
Full Query Language Syntax
SELECT p
FROM Player p, IN (p.teams) AS t
The following query returns the same results as the preceding query, but the WHERE
clause makes it easier to read:
SELECT p
FROM Player p
WHERE p.teams IS NOT EMPTY
An identification variable always designates a reference to a single value whose type is
that of the expression used in the declaration. There are two kinds of declarations:
range variable and collection member.
39.5.3.3 Range Variable Declarations
To declare an identification variable as an abstract schema type, you specify a range
variable declaration. In other words, an identification variable can range over the
abstract schema type of an entity. In the following example, an identification variable
named p represents the abstract schema named Player:
FROM Player p
A range variable declaration can include the optional AS operator:
FROM Player AS p
To obtain objects, a query usually uses path expressions to navigate through the
relationships. But for those objects that cannot be obtained by navigation, you can use
a range variable declaration to designate a starting point, or query root.
If the query compares multiple values of the same abstract schema type, the FROM
clause must declare multiple identification variables for the abstract schema:
FROM Player p1, Player p2
For an example of such a query, see Comparison Operators.
39.5.3.4 Collection Member Declarations
In a one-to-many relationship, the multiple side consists of a collection of entities. An
identification variable can represent a member of this collection. To access a collection
member, the path expression in the variable's declaration navigates through the
relationships in the abstract schema. (For more information on path expressions, see
Path Expressions.) Because a path expression can be based on another path expression,
the navigation can traverse several relationships. See Traversing Multiple
Relationships.
A collection member declaration must include the IN operator but can omit the
optional AS operator.
In the following example, the entity represented by the abstract schema named Player
has a relationship field called teams. The identification variable called t represents a
single member of the teams collection:
FROM Player p, IN (p.teams) t
39.5.3.5 Joins
The JOIN operator is used to traverse over relationships between entities and is
functionally similar to the IN operator.
The Java Persistence Query Language
39-15
Full Query Language Syntax
In the following example, the query joins over the relationship between customers and
orders:
SELECT c
FROM Customer c JOIN c.orders o
WHERE c.status = 1 AND o.totalPrice > 10000
The INNER keyword is optional:
SELECT c
FROM Customer c INNER JOIN c.orders o
WHERE c.status = 1 AND o.totalPrice > 10000
These examples are equivalent to the following query, which uses the IN operator:
SELECT c
FROM Customer c, IN (c.orders) o
WHERE c.status = 1 AND o.totalPrice > 10000
You can also join a single-valued relationship:
SELECT t
FROM Team t JOIN t.league l
WHERE l.sport = :sport
A LEFT JOIN or LEFT OUTER JOIN retrieves a set of entities where matching values in
the join condition may be absent. The OUTER keyword is optional:
SELECT c.name, o.totalPrice
FROM CustomerOrder o LEFT JOIN o.customer c
A FETCH JOIN is a join operation that returns associated entities as a side effect of
running the query. In the following example, the query returns a set of departments
and, as a side effect, the associated employees of the departments, even though the
employees were not explicitly retrieved by the SELECT clause:
SELECT d
FROM Department d LEFT JOIN FETCH d.employees
WHERE d.deptno = 1
39.5.4 Path Expressions
Path expressions are important constructs in the syntax of the query language for
several reasons. First, path expressions define navigation paths through the
relationships in the abstract schema. These path definitions affect both the scope and
the results of a query. Second, path expressions can appear in any of the main clauses
of a query (SELECT, DELETE, HAVING, UPDATE, WHERE, FROM, GROUP BY, ORDER BY). Finally,
although much of the query language is a subset of SQL, path expressions are
extensions not found in SQL.
39.5.4.1 Examples of Path Expressions
Here, the WHERE clause contains a single_valued_path_expression; the p is an
identification variable, and salary is a persistent field of Player:
SELECT DISTINCT p
FROM Player p
WHERE p.salary BETWEEN :lowerSalary AND :higherSalary
39-16 The Java EE 7 Tutorial
Full Query Language Syntax
Here, the WHERE clause also contains a single_valued_path_expression; t is an
identification variable, league is a single-valued relationship field, and sport is a
persistent field of league:
SELECT DISTINCT p
FROM Player p, IN (p.teams) t
WHERE t.league.sport = :sport
Here, the WHERE clause contains a collection_valued_path_expression; p is an
identification variable, and teams designates a collection-valued relationship field:
SELECT DISTINCT p
FROM Player p
WHERE p.teams IS EMPTY
39.5.4.2 Expression Types
The type of a path expression is the type of the object represented by the ending
element, which can be one of the following:
■
Persistent field
■
Single-valued relationship field
■
Collection-valued relationship field
For example, the type of the expression p.salary is double because the terminating
persistent field (salary) is a double.
In the expression p.teams, the terminating element is a collection-valued relationship
field (teams). This expression's type is a collection of the abstract schema type named
Team. Because Team is the abstract schema name for the Team entity, this type maps to
the entity. For more information on the type mapping of abstract schemas, see Return
Types.
39.5.4.3 Navigation
A path expression enables the query to navigate to related entities. The terminating
elements of an expression determine whether navigation is allowed. If an expression
contains a single-valued relationship field, the navigation can continue to an object
that is related to the field. However, an expression cannot navigate beyond a persistent
field or a collection-valued relationship field. For example, the expression
p.teams.league.sport is illegal because teams is a collection-valued relationship
field. To reach the sport field, the FROM clause could define an identification variable
named t for the teams field:
FROM Player AS p, IN (p.teams) t
WHERE t.league.sport = 'soccer'
39.5.5 WHERE Clause
The WHERE clause specifies a conditional expression that limits the values returned by
the query. The query returns all corresponding values in the data store for which the
conditional expression is TRUE. Although usually specified, the WHERE clause is
optional. If the WHERE clause is omitted, the query returns all values. The high-level
syntax for the WHERE clause is as follows:
where_clause ::= WHERE conditional_expression
39.5.5.1 Literals
There are four kinds of literals: string, numeric, Boolean, and enum.
The Java Persistence Query Language
39-17
Full Query Language Syntax
■
String literals: A string literal is enclosed in single quotes:
'Duke'
If a string literal contains a single quote, you indicate the quote by using two
single quotes:
'Duke''s'
Like a Java String, a string literal in the query language uses the Unicode
character encoding.
■
■
■
Numeric literals: There are two types of numeric literals: exact and approximate.
–
An exact numeric literal is a numeric value without a decimal point, such as
65, –233, and +12. Using the Java integer syntax, exact numeric literals support
numbers in the range of a Java long.
–
An approximate numeric literal is a numeric value in scientific notation, such
as 57., –85.7, and +2.1. Using the syntax of the Java floating-point literal,
approximate numeric literals support numbers in the range of a Java double.
Boolean literals: A Boolean literal is either TRUE or FALSE. These keywords are not
case-sensitive.
Enum literals: The Java Persistence query language supports the use of enum
literals using the Java enum literal syntax. The enum class name must be specified
as a fully qualified class name:
SELECT e
FROM Employee e
WHERE e.status = com.example.EmployeeStatus.FULL_TIME
39.5.5.2 Input Parameters
An input parameter can be either a named parameter or a positional parameter.
■
■
A named input parameter is designated by a colon (:) followed by a string; for
example, :name.
A positional input parameter is designated by a question mark (?) followed by an
integer. For example, the first input parameter is ?1, the second is ?2, and so forth.
The following rules apply to input parameters.
■
They can be used only in a WHERE or HAVING clause.
■
Positional parameters must be numbered, starting with the integer 1.
■
Named parameters and positional parameters may not be mixed in a single query.
■
Named parameters are case-sensitive.
39.5.5.3 Conditional Expressions
A WHERE clause consists of a conditional expression, which is evaluated from left to
right within a precedence level. You can change the order of evaluation by using
parentheses.
39.5.5.4 Operators and Their Precedence
Table 39–2 lists the query language operators in order of decreasing precedence.
39-18 The Java EE 7 Tutorial
Full Query Language Syntax
Table 39–2
Query Language Order Precedence
Type
Precedence Order
Navigation
. (a period)
Arithmetic
+ – (unary)
* / (multiplication and division)
+ – (addition and subtraction)
Comparison
=
>
>=
<
<=
<> (not equal)
[NOT] BETWEEN
[NOT] LIKE
[NOT] IN
IS [NOT] NULL
IS [NOT] EMPTY
[NOT] MEMBER OF
Logical
NOT
AND
OR
39.5.5.5 BETWEEN Expressions
A BETWEEN expression determines whether an arithmetic expression falls within a
range of values.
These two expressions are equivalent:
p.age BETWEEN 15 AND 19
p.age >= 15 AND p.age <= 19
The following two expressions also are equivalent:
p.age NOT BETWEEN 15 AND 19
p.age < 15 OR p.age > 19
If an arithmetic expression has a NULL value, the value of the BETWEEN expression is
unknown.
39.5.5.6 IN Expressions
An IN expression determines whether a string belongs to a set of string literals or
whether a number belongs to a set of number values.
The path expression must have a string or numeric value. If the path expression has a
NULL value, the value of the IN expression is unknown.
In the following example, the expression is TRUE if the country is UK , but FALSE if the
country is Peru:
o.country IN ('UK', 'US', 'France')
The Java Persistence Query Language
39-19
Full Query Language Syntax
You may also use input parameters:
o.country IN ('UK', 'US', 'France', :country)
39.5.5.7 LIKE Expressions
A LIKE expression determines whether a wildcard pattern matches a string.
The path expression must have a string or numeric value. If this value is NULL, the
value of the LIKE expression is unknown. The pattern value is a string literal that can
contain wildcard characters. The underscore (_) wildcard character represents any
single character. The percent (%) wildcard character represents zero or more characters.
The ESCAPE clause specifies an escape character for the wildcard characters in the
pattern value. Table 39–3 shows some sample LIKE expressions.
Table 39–3
LIKE Expression Examples
Expression
TRUE
FALSE
address.phone LIKE '12%3'
'123'
'1234'
'12993'
asentence.word LIKE 'l_se'
'lose'
'loose'
aword.underscored LIKE '\_%' ESCAPE '\'
'_foo'
'bar'
address.phone NOT LIKE '12%3'
'1234'
'123'
'12993'
39.5.5.8 NULL Comparison Expressions
A NULL comparison expression tests whether a single-valued path expression or an
input parameter has a NULL value. Usually, the NULL comparison expression is used to
test whether a single-valued relationship has been set:
SELECT t
FROM Team t
WHERE t.league IS NULL
This query selects all teams where the league relationship is not set. Note that the
following query is not equivalent:
SELECT t
FROM Team t
WHERE t.league = NULL
The comparison with NULL using the equals operator (=) always returns an unknown
value, even if the relationship is not set. The second query will always return an empty
result.
39.5.5.9 Empty Collection Comparison Expressions
The IS [NOT] EMPTY comparison expression tests whether a collection-valued path
expression has no elements. In other words, it tests whether a collection-valued
relationship has been set.
If the collection-valued path expression is NULL, the empty collection comparison
expression has a NULL value.
Here is an example that finds all orders that do not have any line items:
SELECT o
FROM CustomerOrder o
39-20 The Java EE 7 Tutorial
Full Query Language Syntax
WHERE o.lineItems IS EMPTY
39.5.5.10 Collection Member Expressions
The [NOT] MEMBER [OF] collection member expression determines whether a value is a
member of a collection. The value and the collection members must have the same
type.
If either the collection-valued or single-valued path expression is unknown, the
collection member expression is unknown. If the collection-valued path expression
designates an empty collection, the collection member expression is FALSE.
The OF keyword is optional.
The following example tests whether a line item is part of an order:
SELECT o
FROM CustomerOrder o
WHERE :lineItem MEMBER OF o.lineItems
39.5.5.11 Subqueries
Subqueries may be used in the WHERE or HAVING clause of a query. Subqueries must be
surrounded by parentheses.
The following example finds all customers who have placed more than ten orders:
SELECT c
FROM Customer c
WHERE (SELECT COUNT(o) FROM c.orders o)> 10
Subqueries may contain EXISTS, ALL, and ANY expressions.
■
EXISTS expressions: The [NOT] EXISTS expression is used with a subquery and is
true only if the result of the subquery consists of one or more values; otherwise, it
is false.
The following example finds all employees whose spouses are also employees:
SELECT DISTINCT emp
FROM Employee emp
WHERE EXISTS (
SELECT spouseEmp
FROM Employee spouseEmp
WHERE spouseEmp = emp.spouse)
■
ALL and ANY expressions: The ALL expression is used with a subquery and is
true if all the values returned by the subquery are true or if the subquery is empty.
The ANY expression is used with a subquery and is true if some of the values
returned by the subquery are true. An ANY expression is false if the subquery result
is empty or if all the values returned are false. The SOME keyword is synonymous
with ANY.
The ALL and ANY expressions are used with the =, <, <=, >, >=, and <> comparison
operators.
The following example finds all employees whose salaries are higher than the
salaries of the managers in the employee's department:
SELECT emp
FROM Employee emp
WHERE emp.salary > ALL (
SELECT m.salary
The Java Persistence Query Language
39-21
Full Query Language Syntax
FROM Manager m
WHERE m.department = emp.department)
39.5.5.12 Functional Expressions
The query language includes several string, arithmetic, and date/time functions that
may be used in the SELECT, WHERE, or HAVING clause of a query. The functions are listed
in Table 39–4, Table 39–5, and Table 39–6.
In Table 39–4, the start and length arguments are of type int and designate positions
in the String argument. The first position in a string is designated by 1.
Table 39–4
String Expressions
Function Syntax
Return Type
CONCAT(String, String)
String
LENGTH(String)
int
LOCATE(String, String [, start])
int
SUBSTRING(String, start, length)
String
TRIM([[LEADING|TRAILING|BOTH] char) FROM] (String)
String
LOWER(String)
String
UPPER(String)
String
The CONCAT function concatenates two strings into one string.
The LENGTH function returns the length of a string in characters as an integer.
The LOCATE function returns the position of a given string within a string. This
function returns the first position at which the string was found as an integer. The first
argument is the string to be located. The second argument is the string to be searched.
The optional third argument is an integer that represents the starting string position.
By default, LOCATE starts at the beginning of the string. The starting position of a string
is 1. If the string cannot be located, LOCATE returns 0.
The SUBSTRING function returns a string that is a substring of the first argument based
on the starting position and length.
The TRIM function trims the specified character from the beginning and/or end of a
string. If no character is specified, TRIM removes spaces or blanks from the string. If the
optional LEADING specification is used, TRIM removes only the leading characters from
the string. If the optional TRAILING specification is used, TRIM removes only the trailing
characters from the string. The default is BOTH, which removes the leading and trailing
characters from the string.
The LOWER and UPPER functions convert a string to lowercase or uppercase,
respectively.
In Table 39–5, the number argument can be an int, a float, or a double.
Table 39–5
Arithmetic Expressions
Function Syntax
Return Type
ABS(number)
int, float, or double
MOD(int, int)
int
SQRT(double)
double
39-22 The Java EE 7 Tutorial
Full Query Language Syntax
Table 39–5 (Cont.) Arithmetic Expressions
Function Syntax
Return Type
SIZE(Collection)
int
The ABS function takes a numeric expression and returns a number of the same type as
the argument.
The MOD function returns the remainder of the first argument divided by the second.
The SQRT function returns the square root of a number.
The SIZE function returns an integer of the number of elements in the given collection.
In Table 39–6, the date/time functions return the date, time, or timestamp on the
database server.
Table 39–6
Date/Time Expressions
Function Syntax
Return Type
CURRENT_DATE
java.sql.Date
CURRENT_TIME
java.sql.Time
CURRENT_TIMESTAMP
java.sql.Timestamp
39.5.5.13 Case Expressions
Case expressions change based on a condition, similar to the case keyword of the Java
programming language. The CASE keyword indicates the start of a case expression, and
the expression is terminated by the END keyword. The WHEN and THEN keywords define
individual conditions, and the ELSE keyword defines the default condition should
none of the other conditions be satisfied.
The following query selects the name of a person and a conditional string, depending
on the subtype of the Person entity. If the subtype is Student, the string kid is
returned. If the subtype is Guardian or Staff, the string adult is returned. If the entity
is some other subtype of Person, the string unknown is returned:
SELECT p.name
CASE TYPE(p)
WHEN Student THEN 'kid'
WHEN Guardian THEN 'adult'
WHEN Staff THEN 'adult'
ELSE 'unknown'
END
FROM Person p
The following query sets a discount for various types of customers. Gold-level
customers get a 20% discount, silver-level customers get a 15% discount, bronze-level
customers get a 10% discount, and everyone else gets a 5% discount:
UPDATE Customer c
SET c.discount =
CASE c.level
WHEN 'Gold' THEN 20
WHEN 'SILVER' THEN 15
WHEN 'Bronze' THEN 10
ELSE 5
END
The Java Persistence Query Language
39-23
Full Query Language Syntax
39.5.5.14 NULL Values
If the target of a reference is not in the persistent store, the target is NULL. For
conditional expressions containing NULL, the query language uses the semantics
defined by SQL92. Briefly, these semantics are as follows.
■
■
■
■
If a comparison or arithmetic operation has an unknown value, it yields a NULL
value.
Two NULL values are not equal. Comparing two NULL values yields an unknown
value.
The IS NULL test converts a NULL persistent field or a single-valued relationship
field to TRUE. The IS NOT NULL test converts them to FALSE.
Boolean operators and conditional tests use the three-valued logic defined by
Table 39–7 and Table 39–8. (In these tables, T stands for TRUE, F for FALSE, and U
for unknown.)
Table 39–7
AND Operator Logic
AND
T
F
U
T
T
F
U
F
F
F
F
U
U
F
U
OR
T
F
U
T
T
T
T
F
T
F
U
U
T
U
U
Table 39–8
OR Operator Logic
39.5.5.15 Equality Semantics
In the query language, only values of the same type can be compared. However, this
rule has one exception: Exact and approximate numeric values can be compared. In
such a comparison, the required type conversion adheres to the rules of Java numeric
promotion.
The query language treats compared values as if they were Java types and not as if
they represented types in the underlying data store. For example, a persistent field that
could be either an integer or a NULL must be designated as an Integer object and not as
an int primitive. This designation is required because a Java object can be NULL, but a
primitive cannot.
Two strings are equal only if they contain the same sequence of characters. Trailing
blanks are significant; for example, the strings 'abc' and 'abc ' are not equal.
Two entities of the same abstract schema type are equal only if their primary keys have
the same value. Table 39–9 shows the operator logic of a negation, and Table 39–10
shows the truth values of conditional tests.
Table 39–9
NOT Operator Logic
NOT Value
Value
T
F
39-24 The Java EE 7 Tutorial
Full Query Language Syntax
Table 39–9 (Cont.) NOT Operator Logic
NOT Value
Value
F
T
U
U
Table 39–10
Conditional Test
Conditional Test
T
F
U
Expression IS TRUE
T
F
F
Expression IS FALSE
F
T
F
Expression is unknown
F
F
T
39.5.6 SELECT Clause
The SELECT clause defines the types of the objects or values returned by the query.
39.5.6.1 Return Types
The return type of the SELECT clause is defined by the result types of the select
expressions contained within it. If multiple expressions are used, the result of the
query is an Object[], and the elements in the array correspond to the order of the
expressions in the SELECT clause and in type to the result types of each expression.
A SELECT clause cannot specify a collection-valued expression. For example, the
SELECT clause p.teams is invalid because teams is a collection. However, the clause in
the following query is valid because t is a single element of the teams collection:
SELECT t
FROM Player p, IN (p.teams) t
The following query is an example of a query with multiple expressions in the SELECT
clause:
SELECT c.name, c.country.name
FROM customer c
WHERE c.lastname = 'Coss' AND c.firstname = 'Roxane'
This query returns a list of Object[] elements; the first array element is a string
denoting the customer name, and the second array element is a string denoting the
name of the customer's country.
The result of a query may be the result of an aggregate function, listed in Table 39–11.
Table 39–11
Aggregate Functions in Select Statements
Name
Return Type
Description
AVG
Double
Returns the mean average of the
fields
COUNT
Long
Returns the total number of
results
MAX
The type of the field
Returns the highest value in the
result set
MIN
The type of the field
Returns the lowest value in the
result set
The Java Persistence Query Language
39-25
Full Query Language Syntax
Table 39–11
(Cont.) Aggregate Functions in Select Statements
Name
Return Type
Description
SUM
Long (for integral fields)
Returns the sum of all the values
in the result set
Double (for floating-point fields)
BigInteger (for BigInteger fields)
BigDecimal (for BigDecimal fields)
For select method queries with an aggregate function (AVG, COUNT, MAX, MIN, or SUM) in
the SELECT clause, the following rules apply.
■
■
The AVG, MAX, MIN, and SUM functions return null if there are no values to which the
function can be applied.
The COUNT function returns 0 if there are no values to which the function can be
applied.
The following example returns the average order quantity:
SELECT AVG(o.quantity)
FROM CustomerOrder o
The following example returns the total cost of the items ordered by Roxane Coss:
SELECT SUM(l.price)
FROM CustomerOrder o JOIN o.lineItems l JOIN o.customer c
WHERE c.lastname = 'Coss' AND c.firstname = 'Roxane'
The following example returns the total number of orders:
SELECT COUNT(o)
FROM CustomerOrder o
The following example returns the total number of items that have prices in Hal
Incandenza's order:
SELECT COUNT(l.price)
FROM CustomerOrder o JOIN o.lineItems l JOIN o.customer c
WHERE c.lastname = 'Incandenza' AND c.firstname = 'Hal'
39.5.6.2 The DISTINCT Keyword
The DISTINCT keyword eliminates duplicate return values. If a query returns a
java.util.Collection, which allows duplicates, you must specify the DISTINCT
keyword to eliminate duplicates.
39.5.6.3 Constructor Expressions
Constructor expressions allow you to return Java instances that store a query result
element instead of an Object[].
The following query creates a CustomerDetail instance per Customer matching the
WHERE clause. A CustomerDetail stores the customer name and customer's country
name. So the query returns a List of CustomerDetail instances:
SELECT NEW com.example.CustomerDetail(c.name, c.country.name)
FROM customer c
WHERE c.lastname = 'Coss' AND c.firstname = 'Roxane'
39-26 The Java EE 7 Tutorial
Full Query Language Syntax
39.5.7 ORDER BY Clause
As its name suggests, the ORDER BY clause orders the values or objects returned by the
query.
If the ORDER BY clause contains multiple elements, the left-to-right sequence of the
elements determines the high-to-low precedence.
The ASC keyword specifies ascending order, the default, and the DESC keyword
indicates descending order.
When using the ORDER BY clause, the SELECT clause must return an orderable set of
objects or values. You cannot order the values or objects for values or objects not
returned by the SELECT clause. For example, the following query is valid because the
ORDER BY clause uses the objects returned by the SELECT clause:
SELECT o
FROM Customer c JOIN c.orders o JOIN c.address a
WHERE a.state = 'CA'
ORDER BY o.quantity, o.totalcost
The following example is not valid, because the ORDER BY clause uses a value not
returned by the SELECT clause:
SELECT p.product_name
FROM CustomerOrder o, IN(o.lineItems) l JOIN o.customer c
WHERE c.lastname = 'Faehmel' AND c.firstname = 'Robert'
ORDER BY o.quantity
39.5.8 GROUP BY and HAVING Clauses
The GROUP BY clause allows you to group values according to a set of properties.
The following query groups the customers by their country and returns the number of
customers per country:
SELECT c.country, COUNT(c)
FROM Customer c GROUP BY c.country
The HAVING clause is used with the GROUP BY clause to further restrict the returned
result of a query.
The following query groups orders by the status of their customer and returns the
customer status plus the average totalPrice for all orders where the corresponding
customers have the same status. In addition, it considers only customers with status 1,
2, or 3, so orders of other customers are not taken into account:
SELECT c.status, AVG(o.totalPrice)
FROM CustomerOrder o JOIN o.customer c
GROUP BY c.status HAVING c.status IN (1, 2, 3)
The Java Persistence Query Language
39-27
Full Query Language Syntax
39-28 The Java EE 7 Tutorial
40
Using the Criteria API to Create Queries
40
The Criteria API is used to define queries for entities and their persistent state by
creating query-defining objects. Criteria queries are written using Java programming
language APIs, are typesafe, and are portable. Such queries work regardless of the
underlying data store.
The following topics are addressed here:
■
Overview of the Criteria and Metamodel APIs
■
Using the Metamodel API to Model Entity Classes
■
Using the Criteria API and Metamodel API to Create Basic Typesafe Queries
40.1 Overview of the Criteria and Metamodel APIs
Similar to JPQL, the Criteria API is based on the abstract schema of persistent entities,
their relationships, and embedded objects. The Criteria API operates on this abstract
schema to allow developers to find, modify, and delete persistent entities by invoking
Java Persistence API entity operations. The Metamodel API works in concert with the
Criteria API to model persistent entity classes for Criteria queries.
The Criteria API and JPQL are closely related and are designed to allow similar
operations in their queries. Developers familiar with JPQL syntax will find equivalent
object-level operations in the Criteria API.
The following simple Criteria query returns all instances of the Pet entity in the data
source:
EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet);
TypedQuery<Pet> q = em.createQuery(cq);
List<Pet> allPets = q.getResultList();
The equivalent JPQL query is
SELECT p
FROM Pet p
This query demonstrates the basic steps to create a Criteria query.
1.
Use an EntityManager instance to create a CriteriaBuilder object.
2.
Create a query object by creating an instance of the CriteriaQuery interface. This
query object's attributes will be modified with the details of the query.
Using the Criteria API to Create Queries 40-1
Using the Metamodel API to Model Entity Classes
3.
Set the query root by calling the from method on the CriteriaQuery object.
4.
Specify what the type of the query result will be by calling the select method of
the CriteriaQuery object.
5.
Prepare the query for execution by creating a TypedQuery<T> instance, specifying
the type of the query result.
6.
Execute the query by calling the getResultList method on the TypedQuery<T>
object. Because this query returns a collection of entities, the result is stored in a
List.
The tasks associated with each step are discussed in detail in this chapter.
To create a CriteriaBuilder instance, call the getCriteriaBuilder method on the
EntityManager instance:
CriteriaBuilder cb = em.getCriteriaBuilder();
Use the CriteriaBuilder instance to create a query object:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
The query will return instances of the Pet entity. To create a typesafe query, specify the
type of the query when you create the CriteriaQuery object.
Call the from method of the query object to set the FROM clause of the query and to
specify the root of the query:
Root<Pet> pet = cq.from(Pet.class);
Call the select method of the query object, passing in the query root, to set the SELECT
clause of the query:
cq.select(pet);
Now, use the query object to create a TypedQuery<T> object that can be executed
against the data source. The modifications to the query object are captured to create a
ready-to-execute query:
TypedQuery<Pet> q = em.createQuery(cq);
Execute this typed query object by calling its getResultList method, because this
query will return multiple entity instances. The following statement stores the results
in a List<Pet> collection-valued object:
List<Pet> allPets = q.getResultList();
40.2 Using the Metamodel API to Model Entity Classes
Use the Metamodel API to create a metamodel of the managed entities in a particular
persistence unit. For each entity class in a particular package, a metamodel class is
created with a trailing underscore and with attributes that correspond to the persistent
fields or properties of the entity class.
The following entity class, com.example.Pet, has four persistent fields: id, name, color,
and owners:
package com.example;
...
@Entity
public class Pet {
@Id
40-2 The Java EE 7 Tutorial
Using the Metamodel API to Model Entity Classes
protected Long id;
protected String name;
protected String color;
@ManyToOne
protected Set<Person> owners;
...
}
The corresponding Metamodel class is as follows:
package com.example;
...
@Static Metamodel(Pet.class)
public class Pet_ {
public
public
public
public
static
static
static
static
volatile
volatile
volatile
volatile
SingularAttribute<Pet, Long> id;
SingularAttribute<Pet, String> name;
SingularAttribute<Pet, String> color;
SetAttribute<Pet, Person> owners;
}
Criteria queries use the metamodel class and its attributes to refer to the managed
entity classes and their persistent state and relationships.
40.2.1 Using Metamodel Classes
Metamodel classes that correspond to entity classes are of the following type:
javax.persistence.metamodel.EntityType<T>
Annotation processors typically generate metamodel classes either at development
time or at runtime. Developers of applications that use Criteria queries may do either
of the following:
■
■
Generate static metamodel classes by using the persistence provider's annotation
processor
Obtain the metamodel class by doing one of the following:
–
Call the getModel method on the query root object
–
Obtain an instance of the Metamodel interface and then pass the entity type to
the instance's entity method
The following code snippet shows how to obtain the Pet entity's metamodel class by
calling Root<T>.getModel:
EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
EntityType<Pet> Pet_ = pet.getModel();
The following code snippet shows how to obtain the Pet entity's metamodel class by
first obtaining a metamodel instance by using EntityManager.getMetamodel and then
calling entity on the metamodel instance:
EntityManager em = ...;
Metamodel m = em.getMetamodel();
EntityType<Pet> Pet_ = m.entity(Pet.class);
Using the Criteria API to Create Queries 40-3
Using the Criteria API and Metamodel API to Create Basic Typesafe Queries
The most common use case is to generate typesafe static
metamodel classes at development time. Obtaining the metamodel
classes dynamically, by calling Root<T>.getModel or
EntityManager.getMetamodel and then the entity method, doesn't
allow for type safety and doesn't allow the application to call
persistent field or property names on the metamodel class.
Note:
40.3 Using the Criteria API and Metamodel API to Create Basic Typesafe
Queries
The basic semantics of a Criteria query consists of a SELECT clause, a FROM clause, and
an optional WHERE clause, similar to a JPQL query. Criteria queries set these clauses by
using Java programming language objects, so the query can be created in a typesafe
manner.
40.3.1 Creating a Criteria Query
The javax.persistence.criteria.CriteriaBuilder interface is used to construct
■
Criteria queries
■
Selections
■
Expressions
■
Predicates
■
Ordering
To obtain an instance of the CriteriaBuilder interface, call the getCriteriaBuilder
method on either an EntityManager or an EntityManagerFactory instance.
The following code shows how to obtain a CriteriaBuilder instance by using the
EntityManager.getCriteriaBuilder method:
EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
Criteria queries are constructed by obtaining an instance of the following interface:
javax.persistence.criteria.CriteriaQuery
CriteriaQuery objects define a particular query that will navigate over one or more
entities. Obtain CriteriaQuery instances by calling one of the
CriteriaBuilder.createQuery methods. To create typesafe queries, call the
CriteriaBuilder.createQuery method as follows:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
The CriteriaQuery object's type should be set to the expected result type of the query.
In the preceding code, the object's type is set to CriteriaQuery<Pet> for a query that
will find instances of the Pet entity.
The following code snippet creates a CriteriaQuery object for a query that returns a
String:
CriteriaQuery<String> cq = cb.createQuery(String.class);
40-4 The Java EE 7 Tutorial
Using the Criteria API and Metamodel API to Create Basic Typesafe Queries
40.3.2 Query Roots
For a particular CriteriaQuery object, the root entity of the query, from which all
navigation originates, is called the query root. It is similar to the FROM clause in a JPQL
query.
Create the query root by calling the from method on the CriteriaQuery instance. The
argument to the from method is either the entity class or an EntityType<T> instance
for the entity.
The following code sets the query root to the Pet entity:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
The following code sets the query root to the Pet class by using an EntityType<T>
instance:
EntityManager em = ...;
Metamodel m = em.getMetamodel();
EntityType<Pet> Pet_ = m.entity(Pet.class);
Root<Pet> pet = cq.from(Pet_);
Criteria queries may have more than one query root. This usually occurs when the
query navigates from several entities.
The following code has two Root instances:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet1 = cq.from(Pet.class);
Root<Pet> pet2 = cq.from(Pet.class);
40.3.3 Querying Relationships Using Joins
For queries that navigate to related entity classes, the query must define a join to the
related entity by calling one of the From.join methods on the query root object or
another join object. The join methods are similar to the JOIN keyword in JPQL.
The target of the join uses the Metamodel class of type EntityType<T> to specify the
persistent field or property of the joined entity.
The join methods return an object of type Join<X, Y>, where X is the source entity
and Y is the target of the join. In the following code snippet, Pet is the source entity,
Owner is the target, and Pet_ is a statically generated metamodel class:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Pet, Owner> owner = pet.join(Pet_.owners);
You can chain joins together to navigate to related entities of the target entity without
having to create a Join<X, Y> instance for each join:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Owner, Address> address = pet.join(Pet_.owners).join(Owner_.addresses);
Using the Criteria API to Create Queries 40-5
Using the Criteria API and Metamodel API to Create Basic Typesafe Queries
40.3.4 Path Navigation in Criteria Queries
Path objects, which are used in the SELECT and WHERE clauses of a Criteria query, can be
query root entities, join entities, or other Path objects. Use the Path.get method to
navigate to attributes of the entities of a query.
The argument to the get method is the corresponding attribute of the entity's
Metamodel class. The attribute can be either a single-valued attribute, specified by
@SingularAttribute in the Metamodel class, or a collection-valued attribute, specified
by one of @CollectionAttribute, @SetAttribute, @ListAttribute, or @MapAttribute.
The following query returns the names of all the pets in the data store. The get method
is called on the query root, pet, with the name attribute of the Pet entity's Metamodel
class, Pet_, as the argument:
CriteriaQuery<String> cq = cb.createQuery(String.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet.get(Pet_.name));
40.3.5 Restricting Criteria Query Results
Conditions that are set by calling the CriteriaQuery.where method can restrict the
results of a query on the CriteriaQuery object. Calling the where method is analogous
to setting the WHERE clause in a JPQL query.
The where method evaluates instances of the Expression interface to restrict the results
according to the conditions of the expressions. To create Expression instances, use
methods defined in the Expression and CriteriaBuilder interfaces.
40.3.5.1 The Expression Interface Methods
An Expression object is used in a query's SELECT, WHERE, or HAVING clause. Table 40–1
shows conditional methods you can use with Expression objects.
Table 40–1
Conditional Methods in the Expression Interface
Method
Description
isNull
Tests whether an expression is null
isNotNull
Tests whether an expression is not null
in
Tests whether an expression is within a list of values
The following query uses the Expression.isNull method to find all pets where the
color attribute is null:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(pet.get(Pet_.color).isNull());
The following query uses the Expression.in method to find all brown and black pets:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(pet.get(Pet_.color).in("brown", "black"));
The in method can also check whether an attribute is a member of a collection.
40-6 The Java EE 7 Tutorial
Using the Criteria API and Metamodel API to Create Basic Typesafe Queries
40.3.5.2 Expression Methods in the CriteriaBuilder Interface
The CriteriaBuilder interface defines additional methods for creating expressions.
These methods correspond to the arithmetic, string, date, time, and case operators and
functions of JPQL. Table 40–2 shows conditional methods you can use with
CriteriaBuilder objects.
Table 40–2
Conditional Methods in the CriteriaBuilder Interface
Conditional
Method
Description
equal
Tests whether two expressions are equal
notEqual
Tests whether two expressions are not equal
gt
Tests whether the first numeric expression is greater than the second
numeric expression
ge
Tests whether the first numeric expression is greater than or equal to the
second numeric expression
lt
Tests whether the first numeric expression is less than the second numeric
expression
le
Tests whether the first numeric expression is less than or equal to the
second numeric expression
between
Tests whether the first expression is between the second and third
expression in value
like
Tests whether the expression matches a given pattern
The following code uses the CriteriaBuilder.equal method:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(cb.equal(pet.get(Pet_.name), "Fido"));
The following code uses the CriteriaBuilder.gt method:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Date someDate = new Date(...);
cq.where(cb.gt(pet.get(Pet_.birthday), date));
The following code uses the CriteriaBuilder.between method:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Date firstDate = new Date(...);
Date secondDate = new Date(...);
cq.where(cb.between(pet.get(Pet_.birthday), firstDate, secondDate));
The following code uses the CriteriaBuilder.like method:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(cb.like(pet.get(Pet_.name), "*do"));
To specify multiple conditional predicates, use the compound predicate methods of
the CriteriaBuilder interface, as shown in Table 40–3.
Using the Criteria API to Create Queries 40-7
Using the Criteria API and Metamodel API to Create Basic Typesafe Queries
Table 40–3
Compound Predicate Methods in the CriteriaBuilder Interface
Method
Description
and
A logical conjunction of two Boolean expressions
or
A logical disjunction of two Boolean expressions
not
A logical negation of the given Boolean expression
The following code shows the use of compound predicates in queries:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(cb.equal(pet.get(Pet_.name), "Fido")
.and(cb.equal(pet.get(Pet_.color), "brown")));
40.3.6 Managing Criteria Query Results
For queries that return more than one result, it is often helpful to organize those
results. The CriteriaQuery interface defines the following ordering and grouping
methods:
■
■
The orderBy method orders query results according to attributes of an entity
The groupBy method groups the results of a query together according to attributes
of an entity, and the having method restricts those groups according to a condition
40.3.6.1 Ordering Results
To order the results of a query, call the CriteriaQuery.orderBy method, passing in an
Order object. To create an Order object, call either the CriteriaBuilder.asc or the
CriteriaBuilder.desc method. The asc method is used to order the results by
ascending value of the passed expression parameter. The desc method is used to order
the results by descending value of the passed expression parameter. The following
query shows the use of the desc method:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet);
cq.orderBy(cb.desc(pet.get(Pet_.birthday)));
In this query, the results will be ordered by the pet's birthday from highest to lowest.
That is, pets born in December will appear before pets born in May.
The following query shows the use of the asc method:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Owner, Address> address = pet.join(Pet_.owners).join(Owner_.address);
cq.select(pet);
cq.orderBy(cb.asc(address.get(Address_.postalCode)));
In this query, the results will be ordered by the pet owner's postal code from lowest to
highest. That is, pets whose owner lives in the 10001 zip code will appear before pets
whose owner lives in the 91000 zip code.
If more than one Order object is passed to orderBy, the precedence is determined by
the order in which they appear in the argument list of orderBy. The first Order object
has precedence.
The following code orders results by multiple criteria:
40-8 The Java EE 7 Tutorial
Using the Criteria API and Metamodel API to Create Basic Typesafe Queries
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Pet, Owner> owner = pet.join(Pet_.owners);
cq.select(pet);
cq.orderBy(cb.asc(owner.get(Owner_.lastName)), owner.get(Owner_.firstName)));
The results of this query will be ordered alphabetically by the pet owner's last name,
then first name.
40.3.6.2 Grouping Results
The CriteriaQuery.groupBy method partitions the query results into groups. To set
these groups, pass an expression to groupBy:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.groupBy(pet.get(Pet_.color));
This query returns all Pet entities and groups the results by the pet's color.
Use the CriteriaQuery.having method in conjunction with groupBy to filter over the
groups. The having method, which takes a conditional expression as a parameter,
restricts the query result according to the conditional expression:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.groupBy(pet.get(Pet_.color));
cq.having(cb.in(pet.get(Pet_.color)).value("brown").value("blonde"));
In this example, the query groups the returned Pet entities by color, as in the
preceding example. However, the only returned groups will be Pet entities where the
color attribute is set to brown or blonde. That is, no gray-colored pets will be returned
in this query.
40.3.7 Executing Queries
To prepare a query for execution, create a TypedQuery<T> object with the type of the
query result, passing the CriteriaQuery object to EntityManager.createQuery.
To execute a query, call either getSingleResult or getResultList on the
TypedQuery<T> object.
40.3.7.1 Single-Valued Query Results
Use the TypedQuery<T>.getSingleResult method to execute queries that return a
single result:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
...
TypedQuery<Pet> q = em.createQuery(cq);
Pet result = q.getSingleResult();
40.3.7.2 Collection-Valued Query Results
Use the TypedQuery<T>.getResultList method to execute queries that return a
collection of objects:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
...
TypedQuery<Pet> q = em.createQuery(cq);
List<Pet> results = q.getResultList();
Using the Criteria API to Create Queries 40-9
Using the Criteria API and Metamodel API to Create Basic Typesafe Queries
40-10 The Java EE 7 Tutorial
41
Creating and Using String-Based Criteria
Queries
41
This chapter describes how to create weakly typed string-based Criteria API queries.
The following topics are addressed here:
■
Overview of String-Based Criteria API Queries
■
Creating String-Based Queries
■
Executing String-Based Queries
41.1 Overview of String-Based Criteria API Queries
String-based Criteria API queries ("string-based queries") are Java programming
language queries that use strings rather than strongly typed metamodel objects to
specify entity attributes when traversing a data hierarchy. String-based queries are
constructed similarly to metamodel queries, can be static or dynamic, and can express
the same kind of queries and operations as strongly typed metamodel queries.
Strongly typed metamodel queries are the preferred method of constructing Criteria
API queries.
The main advantage of string-based queries over metamodel queries is the ability to
construct Criteria queries at development time without the need to generate static
metamodel classes or otherwise access dynamically generated metamodel classes.
The main disadvantage to string-based queries is their lack of type safety; this problem
may lead to runtime errors due to type mismatches that would be caught at
development time if you used strongly typed metamodel queries.
For information on constructing criteria queries, see Chapter 40, "Using the Criteria
API to Create Queries".
41.2 Creating String-Based Queries
To create a string-based query, specify the attribute names of entity classes directly as
strings, instead of specifying the attributes of the metamodel class. For example, this
query finds all Pet entities where the value of the name attribute is Fido:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(cb.equal(pet.get("name"), "Fido"));
The name of the attribute is specified as a string. This query is the equivalent of the
following metamodel query:
Creating and Using String-Based Criteria Queries 41-1
Executing String-Based Queries
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Metamodel m = em.getMetamodel();
EntityType<Pet> Pet_ = m.entity(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(cb.equal(pet.get(Pet_.name), "Fido"));
Type mismatch errors in string-based queries will not
appear until the code is executed at runtime, unlike in the above
metamodel query, where type mismatches will be caught at
compile time.
Note:
Joins are specified in the same way:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Owner, Address> address = pet.join("owners").join("addresses");
All the conditional expressions, method expressions, path navigation methods, and
result restriction methods used in metamodel queries can also be used in string-based
queries. In each case, the attributes are specified using strings. For example, here is a
string-based query that uses the in expression:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(pet.get("color").in("brown", "black"));
Here is a string-based query that orders the results in descending order by date:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet);
cq.orderBy(cb.desc(pet.get("birthday")));
41.3 Executing String-Based Queries
String-based queries are executed similarly to strongly typed Criteria queries. First
create a javax.persistence.TypedQuery object by passing the criteria query object to
the EntityManager.createQuery method, then call either getSingleResult or
getResultList on the query object to execute the query:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(cb.equal(pet.get("name"), "Fido"));
TypedQuery<Pet> q = em.createQuery(cq);
List<Pet> results = q.getResultList();
41-2 The Java EE 7 Tutorial
42
Controlling Concurrent Access to Entity
Data with Locking
42
This chapter details how to handle concurrent access to entity data, and the locking
strategies available to Java Persistence API application developers.
The following topics are addressed here:
■
Overview of Entity Locking and Concurrency
■
Lock Modes
42.1 Overview of Entity Locking and Concurrency
Entity data is concurrently accessed if the data in a data source is accessed at the same
time by multiple applications. Ensure that the underlying data's integrity is preserved
when it is accessed concurrently.
When data is updated in the database tables in a transaction, the persistence provider
assumes the database management system will hold short-term read locks and
long-term write locks to maintain data integrity. Most persistence providers will delay
database writes until the end of the transaction, except when the application explicitly
calls for a flush (that is, the application calls the EntityManager.flush method or
executes queries with the flush mode set to AUTO).
By default, persistence providers use optimistic locking, where, before committing
changes to the data, the persistence provider checks that no other transaction has
modified or deleted the data since the data was read. This is accomplished by a
version column in the database table, with a corresponding version attribute in the
entity class. When a row is modified, the version value is incremented. The original
transaction checks the version attribute, and if the data has been modified by another
transaction, a javax.persistence.OptimisticLockException will be thrown, and the
original transaction will be rolled back. When the application specifies optimistic lock
modes, the persistence provider verifies that a particular entity has not changed since
it was read from the database even if the entity data was not modified.
Pessimistic locking goes further than optimistic locking. With pessimistic locking, the
persistence provider creates a transaction that obtains a long-term lock on the data
until the transaction is completed, which prevents other transactions from modifying
or deleting the data until the lock has ended. Pessimistic locking is a better strategy
than optimistic locking when the underlying data is frequently accessed and modified
by many transactions.
Controlling Concurrent Access to Entity Data with Locking
42-1
Lock Modes
Using pessimistic locks on entities that are not subject to
frequent modification may result in decreased application
performance.
Note:
42.1.1 Using Optimistic Locking
Use the javax.persistence.Version annotation to mark a persistent field or property
as a version attribute of an entity. The version attribute enables the entity for optimistic
concurrency control. The persistence provider reads and updates the version attribute
when an entity instance is modified during a transaction. The application may read the
version attribute, but must not modify the value.
Although some persistence providers may support
optimistic locking for entities that do not have version attributes,
portable applications should always use entities with version
attributes when using optimistic locking. If the application attempts
to lock an entity that does not have a version attribute, and the
persistence provider does not support optimistic locking for
non-versioned entities, a PersistenceException will be thrown.
Note:
The @Version annotation has the following requirements.
■
■
■
Only a single @Version attribute may be defined per entity.
The @Version attribute must be in the primary table for an entity mapped to
multiple tables.
The type of the @Version attribute must be one of the following: int, Integer,
long, Long, short, Short, or java.sql.Timestamp.
The following code snippet shows how to define a version attribute in an entity with
persistent fields:
@Version
protected int version;
The following code snippet shows how to define a version attribute in an entity with
persistent properties:
@Version
protected Short getVersion() { ... }
42.2 Lock Modes
The application may increase the level of locking for an entity by specifying the use of
lock modes. Lock modes may be specified to increase the level of optimistic locking or
to request the use of pessimistic locks.
The use of optimistic lock modes causes the persistence provider to check the version
attributes for entities that were read (but not modified) during a transaction as well as
for entities that were updated.
The use of pessimistic lock modes specifies that the persistence provider is to
immediately acquire long-term read or write locks for the database data corresponding
to entity state.
42-2 The Java EE 7 Tutorial
Lock Modes
You can set the lock mode for an entity operation by specifying one of the lock modes
defined in the javax.persistence.LockModeType enumerated type, listed in
Table 42–1.
Table 42–1
Lock Modes for Concurrent Entity Access
Lock Mode
Description
OPTIMISTIC
Obtain an optimistic read lock for all entities with version
attributes.
OPTIMISTIC_FORCE_INCREMENT
Obtain an optimistic read lock for all entities with version
attributes, and increment the version attribute value.
PESSIMISTIC_READ
Immediately obtain a long-term read lock on the data to
prevent the data from being modified or deleted. Other
transactions may read the data while the lock is
maintained, but may not modify or delete the data.
The persistence provider is permitted to obtain a database
write lock when a read lock was requested, but not vice
versa.
PESSIMISTIC_WRITE
Immediately obtain a long-term write lock on the data to
prevent the data from being read, modified, or deleted.
PESSIMISTIC_FORCE_INCREMENT
Immediately obtain a long-term lock on the data to
prevent the data from being modified or deleted, and
increment the version attribute of versioned entities.
READ
A synonym for OPTIMISTIC. Use of
LockModeType.OPTIMISTIC is to be preferred for new
applications.
WRITE
A synonym for OPTIMISTIC_FORCE_INCREMENT. Use of
LockModeType.OPTIMISTIC_FORCE_INCREMENT is to be
preferred for new applications.
NONE
No additional locking will occur on the data in the
database.
42.2.1 Setting the Lock Mode
To specify the lock mode, use one of the following techniques.
■
Call the EntityManager.lock method, passing in one of the lock modes:
EntityManager em = ...;
Person person = ...;
em.lock(person, LockModeType.OPTIMISTIC);
■
Call one of the EntityManager.find methods that take the lock mode as a
parameter:
EntityManager em = ...;
String personPK = ...;
Person person = em.find(Person.class, personPK,
LockModeType.PESSIMISTIC_WRITE);
■
Call one of the EntityManager.refresh methods that take the lock mode as a
parameter:
EntityManager em = ...;
String personPK = ...;
Person person = em.find(Person.class, personPK);
...
em.refresh(person, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
Controlling Concurrent Access to Entity Data with Locking
42-3
Lock Modes
■
Call the Query.setLockMode or TypedQuery.setLockMode method, passing the lock
mode as the parameter:
Query q = em.createQuery(...);
q.setLockMode(LockModeType.PESSIMISTIC_FORCE_INCREMENT);
■
Add a lockMode element to the @NamedQuery annotation:
@NamedQuery(name="lockPersonQuery",
query="SELECT p FROM Person p WHERE p.name LIKE :name",
lockMode=PESSIMISTIC_READ)
42.2.2 Using Pessimistic Locking
Versioned entities, as well as entities that do not have version attributes, can be locked
pessimistically.
To lock entities pessimistically, set the lock mode to PESSIMISTIC_READ, PESSIMISTIC_
WRITE, or PESSIMISTIC_FORCE_INCREMENT.
If a pessimistic lock cannot be obtained on the database rows, and the failure to lock
the data results in a transaction rollback, a PessimisticLockException is thrown. If a
pessimistic lock cannot be obtained, but the locking failure doesn't result in a
transaction rollback, a LockTimeoutException is thrown.
Pessimistically locking a versioned entity with PESSIMISTIC_FORCE_INCREMENT results
in the version attribute being incremented even if the entity data is unmodified. When
pessimistically locking a versioned entity, the persistence provider will perform the
version checks that occur during optimistic locking, and if the version check fails, an
OptimisticLockException will be thrown. An attempt to lock a non-versioned entity
with PESSIMISTIC_FORCE_INCREMENT is not portable and may result in a
PersistenceException if the persistence provider does not support optimistic locks
for non-versioned entities. Locking a versioned entity with PESSIMISTIC_WRITE results
in the version attribute being incremented if the transaction was successfully
committed.
42.2.2.1 Pessimistic Locking Timeouts
Use the javax.persistence.lock.timeout property to specify the length of time in
milliseconds the persistence provider should wait to obtain a lock on the database
tables. If the time it takes to obtain a lock exceeds the value of this property, a
LockTimeoutException will be thrown, but the current transaction will not be marked
for rollback. If you set this property to 0, the persistence provider should throw a
LockTimeoutException if it cannot immediately obtain a lock.
Portable applications should not rely on the setting of
javax.persistence.lock.timeout, because the locking strategy
and underlying database may mean that the timeout value cannot
be used. The value of javax.persistence.lock.timeout is a hint,
not a contract.
Note:
This property may be set programmatically by passing it to the EntityManager
methods that allow lock modes to be specified, the Query.setLockMode and
TypedQuery.setLockMode methods, the @NamedQuery annotation, and the
Persistence.createEntityManagerFactory method. It may also be set as a property
in the persistence.xml deployment descriptor.
42-4 The Java EE 7 Tutorial
Lock Modes
If javax.persistence.lock.timeout is set in multiple places, the value will be
determined in the following order:
1.
The argument to one of the EntityManager or Query methods
2.
The setting in the @NamedQuery annotation
3.
The argument to the Persistence.createEntityManagerFactory method
4.
The value in the persistence.xml deployment descriptor
Controlling Concurrent Access to Entity Data with Locking
42-5
Lock Modes
42-6 The Java EE 7 Tutorial
43
Creating Fetch Plans with Entity Graphs
43
This chapter explains how to use entity graphs to create fetch plans for Java
Persistence API operations and queries.
Entity graphs are templates for a particular Persistence query or operation. They are
used when creating fetch plans, or groups of persistent fields that are retrieved at the
same time. Application developers use fetch plans to group together related persistent
fields to improve runtime performance.
By default, entity fields or properties are fetched lazily. Developers specify fields or
properties as part of a fetch plan, and the persistence provider will fetch them eagerly.
For example, an email application that stores messages as EmailMessage entities
prioritizes fetching some fields over others. The sender, subject, and date will be
viewed the most often, in mailbox views and when the message is displayed. The
EmailMessage entity has a collection of related EmailAttachment entities. For
performance reasons the attachments should not be fetched until they are needed, but
the file names of the attachment are important. A developer working on this
application might make a fetch plan that eagerly fetches the important fields from
EmailMessage and EmailAttachment while fetching the lower priority data lazily.
The following topics are addressed here:
■
Entity Graph Basics
■
Using Named Entity Graphs
■
Using Entity Graphs in Query Operations
43.1 Entity Graph Basics
You can create entity graphs statically by using annotations or a deployment
descriptor, or dynamically by using standard interfaces.
You can use an entity graph with the EntityManager.find method or as part of a JPQL
or Criteria API query by specifying the entity graph as a hint to the operation or query.
Entity graphs have attributes that correspond to the fields that will be eagerly fetched
during a find or query operation. The primary key and version fields of the entity
class are always fetched and do not need to be explicitly added to an entity graph.
43.1.1 The Default Entity Graph
By default, all fields in an entity are fetched lazily unless the fetch attribute of the
entity metadata is set to javax.persistence.FetchType.EAGER. The default entity
graph consists of all the fields of an entity whose fields are set to be eagerly fetched.
Creating Fetch Plans with Entity Graphs 43-1
Entity Graph Basics
For example, the following EmailMessage entity specifies that some fields will be
fetched eagerly:
@Entity
public class EmailMessage implements Serializable {
@Id
String messageId;
@Basic(fetch=EAGER)
String subject;
String body;
@Basic(fetch=EAGER)
String sender;
@OneToMany(mappedBy="message", fetch=LAZY)
Set<EmailAttachment> attachments;
...
}
The default entity graph for this entity would contain the messageId, subject, and
sender fields, but not the body or attachments fields.
43.1.2 Using Entity Graphs in Persistence Operations
Entity graphs are used by creating an instance of the javax.persistence.EntityGraph
interface by calling either EntityManager.getEntityGraph for named entity graphs or
EntityManager.createEntityGraph for creating dynamic entity graphs.
A named entity graph is an entity graph specified by the @NamedEntityGraph
annotation applied to entity classes, or the named-entity-graph element in the
application's deployment descriptors. Named entity graphs defined within the
deployment descriptor override any annotation-based entity graphs with the same
name.
The created entity graph can be either a fetch graph or a load graph.
43.1.2.1 Fetch Graphs
To specify a fetch graph, set the javax.persistence.fetchgraph property when you
execute an EntityManager.find or query operation. A fetch graph consists of only the
fields explicitly specified in the EntityGraph instance, and ignores the default entity
graph settings.
In the following example, the default entity graph is ignored, and only the body field is
included in the dynamically created fetch graph:
EntityGraph<EmailMessage> eg = em.createEntityGraph(EmailMessage.class);
eg.addAttributeNodes("body");
...
Properties props = new Properties();
props.put("javax.persistence.fetchgraph", eg);
EmailMessage message = em.find(EmailMessage.class, id, props);
43.1.2.2 Load Graphs
To specify a load graph, set the javax.persistence.loadgraph property when you
execute an EntityManager.find or query operation. A load graph consists of the fields
explicitly specified in the EntityGraph instance plus any fields in the default entity
graph.
In the following example, the dynamically created load graph contains all the fields in
the default entity graph plus the body field:
43-2 The Java EE 7 Tutorial
Using Named Entity Graphs
EntityGraph<EmailMessage> eg = em.createEntityGraph(EmailMessage.class);
eg.addAttributeNodes("body");
...
Properties props = new Properties();
props.put("javax.persistence.loadgraph", eg);
EmailMessage message = em.find(EmailMessage.class, id, props);
43.2 Using Named Entity Graphs
Named entity graphs are created using annotations applied to entity classes or the
named-entity-graph element and its sub-elements in the application's deployment
descriptor. The persistence provider will scan for all named entity graphs, defined in
both annotations and in XML, within an application. A named entity graph set using
an annotation may be overridden using named-entity-graph.
43.2.1 Applying Named Entity Graph Annotations to Entity Classes
The javax.persistence.NamedEntityGraph annotation defines a single named entity
graph and is applied at the class level. Multiple @NamedEntityGraph annotations may
be defined for a class by adding them within a
javax.persistence.NamedEntityGraphs class-level annotation.
The @NamedEntityGraph annotation must be applied on the root of the graph of
entities. That is, if the EntityManager.find or query operation has as its root entity the
EmailMessage class, the named entity graph used in the operation must be defined in
the EmailMessage class:
@NamedEntityGraph
@Entity
public class EmailMessage {
@Id
String messageId;
String subject;
String body;
String sender;
}
In this example, the EmailMessage class has a @NamedEntityGraph annotation to define
a named entity graph that defaults to the name of the class, EmailMessage. No fields
are included in the @NamedEntityGraph annotation as attribute nodes, and the fields
are not annotated with metadata to set the fetch type, so the only field that will be
eagerly fetched in either a load graph or fetch graph is messageId.
The attributes of a named entity graph are the fields of the entity that should be
included in the entity graph. Add the fields to the entity graph by specifying them in
the attributeNodes element of @NamedEntityGraph with a
javax.persistence.NamedAttributeNode annotation:
@NamedEntityGraph(name="emailEntityGraph", attributeNodes={
@NamedAttributeNode("subject"),
@NamedAttributeNode("sender")
})
@Entity
public class EmailMessage { ... }
In this example, the name of the named entity graph is emailEntityGraph and
includes the subject and sender fields.
Creating Fetch Plans with Entity Graphs 43-3
Using Entity Graphs in Query Operations
Multiple @NamedEntityGraph definitions may be applied to a class by grouping them
within a @NamedEntityGraphs annotation.
In the following example, two entity graphs are defined on the EmailMessage class.
One is for a preview pane, which fetches only the sender, subject, and body of the
message. The other is for a full view of the message, including any message
attachments:
@NamedEntityGraphs({
@NamedEntityGraph(name="previewEmailEntityGraph", attributeNodes={
@NamedAttributeNode("subject"),
@NamedAttributeNode("sender"),
@NamedAttributeNode("body")
}),
@NamedEntityGraph(name="fullEmailEntityGraph", attributeNodes={
@NamedAttributeNode("sender"),
@NamedAttributeNode("subject"),
@NamedAttributeNode("body"),
@NamedAttributeNode("attachments")
})
})
@Entity
public class EmailMessage { ... }
43.2.2 Obtaining EntityGraph Instances from Named Entity Graphs
Use the EntityManager.getEntityGraph method, passing in the named entity graph
name, to obtain EntityGraph instances for a named entity graph:
EntityGraph<EmailMessage> eg = em.getEntityGraph("emailEntityGraph");
43.3 Using Entity Graphs in Query Operations
To specify entity graphs for both typed and untyped queries, call the setHint method
on the query object and specify either javax.persistence.loadgraph or
javax.persistence.fetchgraph as the property name and an EntityGraph instance as
the value:
EntityGraph<EmailMessage> eg = em.getEntityGraph("previewEmailEntityGraph");
List<EmailMessage> messages = em.createNamedQuery("findAllEmailMessages")
.setParameter("mailbox", "inbox")
.setHint("javax.persistence.loadgraph", eg)
.getResultList();
In this example, the previewEmailEntityGraph is used for the findAllEmailMessages
named query.
Typed queries use the same technique:
EntityGraph<EmailMessage> eg = em.getEntityGraph("previewEmailEntityGraph");
CriteriaQuery<EmailMessage> cq = cb.createQuery(EmailMessage.class);
Root<EmailMessage> message = cq.from(EmailMessage.class);
TypedQuery<EmailMessage> q = em.createQuery(cq);
q.setHint("javax.persistence.loadgraph", eg);
List<EmailMessage> messages = q.getResultList();
43-4 The Java EE 7 Tutorial
44
Using a Second-Level Cache with Java
Persistence API Applications
44
This chapter explains how to modify the second-level cache mode settings to improve
the performance of applications that use the Java Persistence API.
The following topics are addressed here:
■
Overview of the Second-Level Cache
■
Specifying the Cache Mode Settings to Improve Performance
44.1 Overview of the Second-Level Cache
A second-level cache is a local store of entity data managed by the persistence
provider to improve application performance. A second-level cache helps improve
performance by avoiding expensive database calls, keeping the entity data local to the
application. A second-level cache is typically transparent to the application, as it is
managed by the persistence provider and underlies the persistence context of an
application. That is, the application reads and commits data through the normal entity
manager operations without knowing about the cache.
Persistence providers are not required to support a
second-level cache. Portable applications should not rely on
support by persistence providers for a second-level cache.
Note:
The second-level cache for a persistence unit may be configured to one of several
second-level cache modes. The following cache mode settings are defined by the Java
Persistence API.
Table 44–1
Cache Mode Settings for the Second-Level Cache
Cache Mode Setting
Description
ALL
All entity data is stored in the second-level cache for this
persistence unit.
NONE
No data is cached in the persistence unit. The persistence provider
must not cache any data.
ENABLE_SELECTIVE
Enable caching for entities that have been explicitly set with the
@Cacheable annotation.
DISABLE_SELECTIVE
Enable caching for all entities except those that have been explicitly
set with the @Cacheable(false) annotation.
Using a Second-Level Cache with Java Persistence API Applications 44-1
Overview of the Second-Level Cache
Table 44–1 (Cont.) Cache Mode Settings for the Second-Level Cache
Cache Mode Setting
Description
UNSPECIFIED
The caching behavior for the persistence unit is undefined. The
persistence provider's default caching behavior will be used.
One consequence of using a second-level cache in an application is that the underlying
data may have changed in the database tables, while the value in the cache has not, a
circumstance called a stale read. To avoid stale reads, use any of these strategies:
■
■
■
Change the second-level cache to one of the cache mode settings
Control which entities may be cached (see Controlling whether Entities May Be
Cached)
Change the cache's retrieval or store modes (see Setting the Cache Retrieval and
Store Modes)
Which of these strategies works best to avoid stale reads depends upon the
application.
44.1.1 Controlling whether Entities May Be Cached
The javax.persistence.Cacheable annotation is used to specify that an entity class,
and any subclasses, may be cached when using the ENABLE_SELECTIVE or DISABLE_
SELECTIVE cache modes. Subclasses may override the @Cacheable setting by adding a
@Cacheable annotation and changing the value.
To specify that an entity may be cached, add a @Cacheable annotation at the class level:
@Cacheable
@Entity
public class Person { ... }
By default, the @Cacheable annotation is true. The following example is equivalent:
@Cacheable(true)
@Entity
public class Person{ ... }
To specify that an entity must not be cached, add a @Cacheable annotation and set it to
false:
@Cacheable(false)
@Entity
public class OrderStatus { ... }
When the ENABLE_SELECTIVE cache mode is set, the persistence provider will cache any
entities that have the @Cacheable(true) annotation and any subclasses of that entity
that have not been overridden. The persistence provider will not cache entities that
have @Cacheable(false) or have no @Cacheable annotation. That is, the ENABLE_
SELECTIVE mode will cache only entities that have been explicitly marked for the cache
using the @Cacheable annotation.
When the DISABLE_SELECTIVE cache mode is set, the persistence provider will cache
any entities that do not have the @Cacheable(false) annotation. Entities that do not
have @Cacheable annotations, and entities with the @Cacheable(true) annotation, will
be cached. That is, the DISABLE_SELECTIVE mode will cache all entities that have not
been explicitly prevented from being cached.
44-2 The Java EE 7 Tutorial
Specifying the Cache Mode Settings to Improve Performance
If the cache mode is set to UNDEFINED, or is left unset, the behavior of entities annotated
with @Cacheable is undefined. If the cache mode is set to ALL or NONE, the value of the
@Cacheable annotation is ignored by the persistence provider.
44.2 Specifying the Cache Mode Settings to Improve Performance
To adjust the cache mode settings for a persistence unit, specify one of the cache modes
as the value of the shared-cache-mode element in the persistence.xml deployment
descriptor (shown in bold):
<persistence-unit name="examplePU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:comp/DefaultDataSource</jta-data-source>
<shared-cache-mode>DISABLE_SELECTIVE</shared-cache-mode>
</persistence-unit>
Because support for a second-level cache is not required by
the Java Persistence API specification, setting the second-level
cache mode in persistence.xml will have no effect when you use a
persistence provider that does not implement a second-level cache.
Note:
Alternatively, you can specify the shared cache mode by setting the
javax.persistence.sharedCache.mode property to one of the shared cache mode
settings:
EntityManagerFactory emf =
Persistence.createEntityManagerFactory(
"myExamplePU", new Properties().add(
"javax.persistence.sharedCache.mode", "ENABLE_SELECTIVE"));
44.2.1 Setting the Cache Retrieval and Store Modes
If you have enabled the second-level cache for a persistence unit by setting the shared
cache mode, you can further modify the behavior of the second-level cache by setting
the javax.persistence.cache.retrieveMode and
javax.persistence.cache.storeMode properties. You can set these properties at the
persistence context level by passing the property name and value to the
EntityManager.setProperty method, or you can set them on a per-EntityManager
operation (EntityManager.find or EntityManager.refresh) or on a per-query level.
44.2.1.1 Cache Retrieval Mode
The cache retrieval mode, set by the javax.persistence.retrieveMode property,
controls how data is read from the cache for calls to the EntityManager.find method
and from queries.
You can set the retrieveMode property to one of the constants defined by the
javax.persistence.CacheRetrieveMode enumerated type, either USE (the default) or
BYPASS.
When the property is set to USE, data is retrieved from the second-level cache, if
available. If the data is not in the cache, the persistence provider will read it from the
database.
When the property is set to BYPASS, the second-level cache is bypassed and a call to the
database is made to retrieve the data.
Using a Second-Level Cache with Java Persistence API Applications 44-3
Specifying the Cache Mode Settings to Improve Performance
44.2.1.2 Cache Store Mode
The cache store mode, set by the javax.persistence.storeMode property, controls
how data is stored in the cache.
The storeMode property can be set to one of the constants defined by the
javax.persistence.CacheStoreMode enumerated type: either USE (the default),
BYPASS, or REFRESH.
When the property is set to USE, the cache data is created or updated when data is read
from or committed to the database. If data is already in the cache, setting the store
mode to USE will not force a refresh when data is read from the database.
When the property is set to BYPASS, data read from or committed to the database is not
inserted or updated in the cache. That is, the cache is unchanged.
When the property is set to REFRESH, the cache data is created or updated when data is
read from or committed to the database, and a refresh is forced on data in the cache
upon database reads.
44.2.1.3 Setting the Cache Retrieval or Store Mode
To set the cache retrieval or store mode for the persistence context, call the
EntityManager.setProperty method with the property name and value pair:
EntityManager em = ...;
em.setProperty("javax.persistence.cache.storeMode", "BYPASS");
To set the cache retrieval or store mode when calling the EntityManager.find or
EntityManager.refresh methods, first create a Map<String, Object> instance and
add a name/value pair as follows:
EntityManager em = ...;
Map<String, Object> props = new HashMap<String, Object>();
props.put("javax.persistence.cache.retrieveMode", "BYPASS");
String personPK = ...;
Person person = em.find(Person.class, personPK, props);
The cache retrieval mode is ignored when calling the
EntityManager.refresh method, as calls to refresh always result
in data being read from the database, not the cache.
Note:
To set the retrieval or store mode when using queries, call the Query.setHint or
TypedQuery.setHint methods, depending on the type of query:
EntityManager em = ...;
CriteriaQuery<Person> cq = ...;
TypedQuery<Person> q = em.createQuery(cq);
q.setHint("javax.persistence.cache.storeMode", "REFRESH");
...
Setting the store or retrieve mode in a query or when calling the EntityManager.find
or EntityManager.refresh method overrides the setting of the entity manager.
44.2.2 Controlling the Second-Level Cache Programmatically
The javax.persistence.Cache interface defines methods for interacting with the
second-level cache programmatically. The Cache interface defines methods to do the
following:
44-4 The Java EE 7 Tutorial
Specifying the Cache Mode Settings to Improve Performance
■
Check whether a particular entity has cached data
■
Remove a particular entity from the cache
■
Remove all instances (and instances of subclasses) of an entity class from the cache
■
Clear the cache of all entity data
If the second-level cache has been disabled, calls to the
Cache interface's methods have no effect, except for contains,
which will always return false.
Note:
44.2.2.1 Checking whether an Entity's Data Is Cached
Call the Cache.contains method to find out whether a given entity is currently in the
second-level cache. The contains method returns true if the entity's data is cached,
and false if the data is not in the cache:
EntityManager em = ...;
Cache cache = em.getEntityManagerFactory().getCache();
String personPK = ...;
if (cache.contains(Person.class, personPK)) {
// the data is cached
} else {
// the data is NOT cached
}
44.2.2.2 Removing an Entity from the Cache
Call one of the Cache.evict methods to remove a particular entity or all entities of a
given type from the second-level cache. To remove a particular entity from the cache,
call the evict method and pass in the entity class and the primary key of the entity:
EntityManager em = ...;
Cache cache = em.getEntityManagerFactory().getCache();
String personPK = ...;
cache.evict(Person.class, personPK);
To remove all instances of a particular entity class, including subclasses, call the evict
method and specify the entity class:
EntityManager em = ...;
Cache cache = em.getEntityManagerFactory().getCache();
cache.evict(Person.class);
All instances of the Person entity class will be removed from the cache. If the Person
entity has a subclass, Student, calls to the above method will remove all instances of
Student from the cache as well.
44.2.2.3 Removing All Data from the Cache
Call the Cache.evictAll method to completely clear the second-level cache:
EntityManager em = ...;
Cache cache = em.getEntityManagerFactory().getCache();
cache.evictAll();
Using a Second-Level Cache with Java Persistence API Applications 44-5
Specifying the Cache Mode Settings to Improve Performance
44-6 The Java EE 7 Tutorial
Part IX
Part IX
Messaging
Part IX introduces messaging. This part contains the following chapters:
■
Chapter 45, "Java Message Service Concepts"
■
Chapter 46, "Java Message Service Examples"
45
45
Java Message Service Concepts
This chapter provides an introduction to the Java Message Service (JMS) API, a Java
API that allows applications to create, send, receive, and read messages using reliable,
asynchronous, loosely coupled communication. It covers the following topics:
■
Overview of the JMS API
■
Basic JMS API Concepts
■
The JMS API Programming Model
■
Using Advanced JMS Features
■
Using the JMS API in Java EE Applications
■
Further Information about JMS
45.1 Overview of the JMS API
This overview defines the concept of messaging, describes the JMS API and where it
can be used, and explains how the JMS API works within the Java EE platform.
45.1.1 What Is Messaging?
Messaging is a method of communication between software components or
applications. A messaging system is a peer-to-peer facility: A messaging client can
send messages to, and receive messages from, any other client. Each client connects to
a messaging agent that provides facilities for creating, sending, receiving, and reading
messages.
Messaging enables distributed communication that is loosely coupled. A component
sends a message to a destination, and the recipient can retrieve the message from the
destination. What makes the communication loosely coupled is that the destination is
all that the sender and receiver have in common. The sender and the receiver do not
have to be available at the same time in order to communicate. In fact, the sender does
not need to know anything about the receiver; nor does the receiver need to know
anything about the sender. The sender and the receiver need to know only which
message format and which destination to use. In this respect, messaging differs from
tightly coupled technologies, such as Remote Method Invocation (RMI), which require
an application to know a remote application's methods.
Messaging also differs from electronic mail (email), which is a method of
communication between people or between software applications and people.
Messaging is used for communication between software applications or software
components.
Java Message Service Concepts 45-1
Overview of the JMS API
45.1.2 What Is the JMS API?
The Java Message Service is a Java API that allows applications to create, send, receive,
and read messages. The JMS API defines a common set of interfaces and associated
semantics that allow programs written in the Java programming language to
communicate with other messaging implementations.
The JMS API minimizes the set of concepts a programmer must learn in order to use
messaging products but provides enough features to support sophisticated messaging
applications. It also strives to maximize the portability of JMS applications across JMS
providers.
JMS enables communication that is not only loosely coupled but also
■
■
Asynchronous: A receiving client does not have to receive messages at the same
time the sending client sends them. The sending client can send them and go on to
other tasks; the receiving client can receive them much later.
Reliable: A messaging provider that implements the JMS API can ensure that a
message is delivered once and only once. Lower levels of reliability are available
for applications that can afford to miss messages or to receive duplicate messages.
The current version of the JMS specification is Version 2.0. You can download a copy of
the specification from the Java Community Process website:
http://www.jcp.org/en/jsr/detail?id=343.
45.1.3 When Can You Use the JMS API?
An enterprise application provider is likely to choose a messaging API over a tightly
coupled API, such as a remote procedure call (RPC), under the following
circumstances.
■
■
■
The provider wants the components not to depend on information about other
components' interfaces, so components can be easily replaced.
The provider wants the application to run whether or not all components are up
and running simultaneously.
The application business model allows a component to send information to
another and to continue to operate without receiving an immediate response.
For example, components of an enterprise application for an automobile manufacturer
can use the JMS API in situations like the following.
■
■
■
■
■
The inventory component can send a message to the factory component when the
inventory level for a product goes below a certain level so the factory can make
more cars.
The factory component can send a message to the parts components so the factory
can assemble the parts it needs.
The parts components in turn can send messages to their own inventory and order
components to update their inventories and to order new parts from suppliers.
Both the factory and the parts components can send messages to the accounting
component to update budget numbers.
The business can publish updated catalog items to its sales force.
Using messaging for these tasks allows the various components to interact with one
another efficiently, without tying up network or other resources. Figure 45–1 illustrates
how this simple example might work.
45-2 The Java EE 7 Tutorial
Basic JMS API Concepts
Figure 45–1 Messaging in an Enterprise Application
Parts Inventory
Inventory
Factory
Parts
Parts Order
Sales
Accounting
Manufacturing is only one example of how an enterprise can use the JMS API. Retail
applications, financial services applications, health services applications, and many
others can make use of messaging.
45.1.4 How Does the JMS API Work with the Java EE Platform?
When the JMS API was first introduced, its most important purpose was to allow Java
applications to access existing messaging-oriented middleware (MOM) systems. Since
that time, many vendors have adopted and implemented the JMS API, so a JMS
product can now provide a complete messaging capability for an enterprise.
The JMS API is an integral part of the Java EE platform, and application developers
can use messaging with Java EE components. JMS 2.0 is part of the Java EE 7 release.
The JMS API in the Java EE platform has the following features.
■
■
■
Application clients, Enterprise JavaBeans (EJB) components, and web components
can send or synchronously receive a JMS message. Application clients can in
addition set a message listener that allows JMS messages to be delivered to it
asynchronously by being notified when a message is available.
Message-driven beans, which are a kind of enterprise bean, enable the
asynchronous consumption of messages in the EJB container. An application
server typically pools message-driven beans to implement concurrent processing
of messages.
Message send and receive operations can participate in Java Transaction API (JTA)
transactions, which allow JMS operations and database accesses to take place
within a single transaction.
The JMS API enhances the other parts of the Java EE platform by simplifying
enterprise development, allowing loosely coupled, reliable, asynchronous interactions
among Java EE components and legacy systems capable of messaging. A developer
can easily add new behavior to a Java EE application that has existing business events
by adding a new message-driven bean to operate on specific business events. The Java
EE platform, moreover, enhances the JMS API by providing support for JTA
transactions and allowing for the concurrent consumption of messages. For more
information, see the Enterprise JavaBeans specification, v3.2.
The JMS provider can be integrated with the application server using the Java EE
Connector architecture. You access the JMS provider through a resource adapter. This
capability allows vendors to create JMS providers that can be plugged in to multiple
application servers, and it allows application servers to support multiple JMS
providers. For more information, see the Java EE Connector architecture specification,
v1.7.
45.2 Basic JMS API Concepts
This section introduces the most basic JMS API concepts, the ones you must know to
get started writing simple application clients that use the JMS API.
Java Message Service Concepts 45-3
Basic JMS API Concepts
The next section introduces the JMS API programming model. Later sections cover
more advanced concepts, including the ones you need in order to write applications
that use message-driven beans.
45.2.1 JMS API Architecture
A JMS application is composed of the following parts.
■
■
A JMS provider is a messaging system that implements the JMS interfaces and
provides administrative and control features. An implementation of the Java EE
platform that supports the full profile includes a JMS provider.
JMS clients are the programs or components, written in the Java programming
language, that produce and consume messages. Any Java EE application
component can act as a JMS client.
Java SE applications can also act as JMS clients; the Message Queue Developer’s
Guide for Java Clients in the GlassFish Server documentation
(https://glassfish.java.net/docs/) explains how to make this work.
■
■
Messages are the objects that communicate information between JMS clients.
Administered objects are JMS objects configured for the use of clients. The two
kinds of JMS administered objects are destinations and connection factories,
described in JMS Administered Objects. An administrator can create objects that
are available to all applications that use a particular installation of GlassFish
Server; alternatively, a developer can use annotations to create objects that are
specific to a particular application.
Figure 45–2 illustrates the way these parts interact. Administrative tools or annotations
allow you to bind destinations and connection factories into a JNDI namespace. A JMS
client can then use resource injection to access the administered objects in the
namespace and then establish a logical connection to the same objects through the JMS
provider.
Figure 45–2 JMS API Architecture
JNDI Namespace
Administrative Tool
Bind
CF
D
Inject Resource
JMS Client
Logical Connection
JMS Provider
45.2.2 Messaging Styles
Before the JMS API existed, most messaging products supported either the
point-to-point or the publish/subscribe style of messaging. The JMS specification
defines compliance for each style. A JMS provider must implement both styles, and
the JMS API provides interfaces that are specific to each. The following subsections
describe these messaging styles.
The JMS API, however, makes it unnecessary to use only one of the two styles. It
allows you to use the same code to send and receive messages using either the PTP or
the pub/sub style. The destinations you use remain specific to one style, and the
behavior of the application will depend in part on whether you are using a queue or a
45-4 The Java EE 7 Tutorial
Basic JMS API Concepts
topic. However, the code itself can be common to both styles, making your
applications flexible and reusable. This tutorial describes and illustrates this coding
approach, using the greatly simplified API provided by JMS 2.0.
45.2.2.1 Point-to-Point Messaging Style
A point-to-point (PTP) product or application is built on the concept of message
queues, senders, and receivers. Each message is addressed to a specific queue, and
receiving clients extract messages from the queues established to hold their messages.
Queues retain all messages sent to them until the messages are consumed or expire.
PTP messaging, illustrated in Figure 45–3, has the following characteristics.
■
■
Each message has only one consumer.
The receiver can fetch the message whether or not it was running when the client
sent the message.
Figure 45–3 Point-to-Point Messaging
Client 1
Msg
Msg
Sends
Consumes
Acknowledges
Client 2
Queue
Use PTP messaging when every message you send must be processed successfully by
one consumer.
45.2.2.2 Publish/Subscribe Messaging Style
In a publish/subscribe (pub/sub) product or application, clients address messages to
a topic, which functions somewhat like a bulletin board. Publishers and subscribers
can dynamically publish or subscribe to the topic. The system takes care of
distributing the messages arriving from a topic's multiple publishers to its multiple
subscribers. Topics retain messages only as long as it takes to distribute them to
subscribers.
With pub/sub messaging, it is important to distinguish between the consumer that
subscribes to a topic (the subscriber) and the subscription that is created. The
consumer is a JMS object within an application, while the subscription is an entity
within the JMS provider. Normally, a topic can have many consumers, but a
subscription has only one subscriber. It is possible, however, to create shared
subscriptions; see Creating Shared Subscriptions for details. See Consuming Messages
from Topics for details on the semantics of pub/sub messaging.
Pub/sub messaging has the following characteristics.
■
■
Each message can have multiple consumers.
A client that subscribes to a topic can consume only messages sent after the client
has created a subscription, and the consumer must continue to be active in order
for it to consume messages.
The JMS API relaxes this requirement to some extent by allowing applications to
create durable subscriptions, which receive messages sent while the consumers
are not active. Durable subscriptions provide the flexibility and reliability of
Java Message Service Concepts 45-5
The JMS API Programming Model
queues but still allow clients to send messages to many recipients. For more
information about durable subscriptions, see Creating Durable Subscriptions.
Use pub/sub messaging when each message can be processed by any number of
consumers (or none). Figure 45–4 illustrates pub/sub messaging.
Figure 45–4 Publish/Subscribe Messaging
Msg
Topic
Subscribes
Client 2
Delivers
Client 1
Msg
Publishes
Subscribes
Delivers
Client 3
45.2.3 Message Consumption
Messaging products are inherently asynchronous: There is no fundamental timing
dependency between the production and the consumption of a message. However, the
JMS specification uses this term in a more precise sense. Messages can be consumed in
either of two ways.
■
■
Synchronously: A consumer explicitly fetches the message from the destination
by calling the receive method. The receive method can block until a message
arrives or can time out if a message does not arrive within a specified time limit.
Asynchronously: An application client or a Java SE client can register a message
listener with a consumer. A message listener is similar to an event listener.
Whenever a message arrives at the destination, the JMS provider delivers the
message by calling the listener's onMessage method, which acts on the contents of
the message. In a Java EE application, a message-driven bean serves as a message
listener (it too has an onMessage method), but a client does not need to register it
with a consumer.
45.3 The JMS API Programming Model
The basic building blocks of a JMS application are
■
Administered objects: connection factories and destinations
■
Connections
■
Sessions
■
JMSContext objects, which combine a connection and a session in one object
■
Message producers
■
Message consumers
■
Messages
Figure 45–5 shows how all these objects fit together in a JMS client application.
45-6 The Java EE 7 Tutorial
The JMS API Programming Model
Figure 45–5 The JMS API Programming Model
Connection
Factory
Creates
JMSContext
Connection
Creates
Message
Producer
Creates
Session
Creates
Message
Consumer
Sends
To
Creates
Receives
From
Destination
Msg
Destination
JMS also provides queue browsers, objects that allow an application to browse
messages on a queue.
This section describes all these objects briefly and provides sample commands and
code snippets that show how to create and use the objects. The last subsection briefly
describes JMS API exception handling.
Examples that show how to combine all these objects in applications appear in
Chapter 46, "Java Message Service Examples," beginning with Writing Simple JMS
Applications. For more detail, see the JMS API documentation, part of the Java EE API
documentation.
45.3.1 JMS Administered Objects
Two parts of a JMS application, destinations and connection factories, are commonly
maintained administratively rather than programmatically. The technology underlying
these objects is likely to be very different from one implementation of the JMS API to
another. Therefore, the management of these objects belongs with other administrative
tasks that vary from provider to provider.
JMS clients access administered objects through interfaces that are portable, so a client
application can run with little or no change on more than one implementation of the
JMS API. Ordinarily, an administrator configures administered objects in a JNDI
namespace, and JMS clients then access them by using resource injection.
With GlassFish Server, you can use the asadmin create-jms-resource command or
the Administration Console to create JMS administered objects in the form of
connector resources. You can also specify the resources in a file named
glassfish-resources.xml that you can bundle with an application.
NetBeans IDE provides a wizard that allows you to create JMS resources for GlassFish
Server. See Creating JMS Administered Objects for details.
Java Message Service Concepts 45-7
The JMS API Programming Model
The Java EE platform specification allows a developer to create administered objects
using annotations or deployment descriptor elements. Objects created in this way are
specific to the application for which they are created. See Creating Resources for Java
EE Applications for details. Definitions in a deployment descriptor override those
specified by annotations.
45.3.1.1 JMS Connection Factories
A connection factory is the object a client uses to create a connection to a provider. A
connection factory encapsulates a set of connection configuration parameters that has
been defined by an administrator. Each connection factory is an instance of the
ConnectionFactory, QueueConnectionFactory, or TopicConnectionFactory interface.
To learn how to create connection factories, see Creating JMS Administered Objects.
At the beginning of a JMS client program, you usually inject a connection factory
resource into a ConnectionFactory object. A Java EE server must provide a JMS
connection factory with the logical JNDI name
java:comp/DefaultJMSConnectionFactory. The actual JNDI name will be
implementation-specific.
For example, the following code fragment looks up the default JMS connection factory
and assigns it to a ConnectionFactory object:
@Resource(lookup = "java:comp/DefaultJMSConnectionFactory")
private static ConnectionFactory connectionFactory;
45.3.1.2 JMS Destinations
A destination is the object a client uses to specify the target of messages it produces
and the source of messages it consumes. In the PTP messaging style, destinations are
called queues. In the pub/sub messaging style, destinations are called topics. A JMS
application can use multiple queues or topics (or both). To learn how to create
destination resources, see Creating JMS Administered Objects.
To create a destination using GlassFish Server, you create a JMS destination resource
that specifies a JNDI name for the destination.
In the GlassFish Server implementation of JMS, each destination resource refers to a
physical destination. You can create a physical destination explicitly, but if you do not,
the Application Server creates it when it is needed and deletes it when you delete the
destination resource.
In addition to injecting a connection factory resource into a client program, you
usually inject a destination resource. Unlike connection factories, destinations are
specific to either the PTP or pub/sub messaging style. To create an application that
allows you to use the same code for both topics and queues, you assign the destination
to a Destination object.
The following code specifies two resources, a queue and a topic. The resource names
are mapped to destination resources created in the JNDI namespace:
@Resource(lookup = "jms/MyQueue")
private static Queue queue;
@Resource(lookup = "jms/MyTopic")
private static Topic topic;
In a Java EE application, JMS administered objects are normally placed in the jms
naming subcontext.
45-8 The Java EE 7 Tutorial
The JMS API Programming Model
With the common interfaces, you can mix or match connection factories and
destinations. That is, in addition to using the ConnectionFactory interface, you can
inject a QueueConnectionFactory resource and use it with a Topic, and you can inject a
TopicConnectionFactory resource and use it with a Queue. The behavior of the
application will depend on the kind of destination you use and not on the kind of
connection factory you use.
45.3.2 Connections
A connection encapsulates a virtual connection with a JMS provider. For example, a
connection could represent an open TCP/IP socket between a client and a provider
service daemon. You use a connection to create one or more sessions.
In the Java EE platform, the ability to create multiple sessions
from a single connection is limited to application clients. In web and
enterprise bean components, a connection can create no more than one
session.
Note:
You normally create a connection by creating a JMSContext object. See JMSContext
Objects for details.
45.3.3 Sessions
A session is a single-threaded context for producing and consuming messages.
You normally create a session (as well as a connection) by creating a JMSContext
object. See JMSContext Objects for details. You use sessions to create message
producers, message consumers, messages, queue browsers, and temporary
destinations.
Sessions serialize the execution of message listeners; for details, see JMS Message
Listeners.
A session provides a transactional context with which to group a set of sends and
receives into an atomic unit of work. For details, see Using JMS Local Transactions.
45.3.4 JMSContext Objects
A JMSContext object combines a connection and a session in a single object. That is, it
provides both an active connection to a JMS provider and a single-threaded context for
sending and receiving messages.
You use the JMSContext to create the following objects:
■
Message producers
■
Message consumers
■
Messages
■
Queue browsers
■
Temporary queues and topics (see Creating Temporary Destinations)
You can create a JMSContext in a try-with-resources block.
To create a JMSContext, call the createContext method on the connection factory:
JMSContext context = connectionFactory.createContext();
Java Message Service Concepts 45-9
The JMS API Programming Model
When called with no arguments from an application client or a Java SE client, or from
the Java EE web or EJB container when there is no active JTA transaction in progress,
the createContext method creates a non-transacted session with an acknowledgment
mode of JMSContext.AUTO_ACKNOWLEDGE. When called with no arguments from the
web or EJB container when there is an active JTA transaction in progress, the
createContext method creates a transacted session. For information about the way
JMS transactions work in Java EE applications, see Using the JMS API in Java EE
Applications.
From an application client or a Java SE client, you can also call the createContext
method with the argument JMSContext.SESSION_TRANSACTED to create a transacted
session:
JMSContext context =
connectionFactory.createContext(JMSContext.SESSION_TRANSACTED);
The session uses local transactions; see Using JMS Local Transactions for details.
Alternatively, you can specify a non-default acknowledgment mode; see Controlling
Message Acknowledgment for more information.
When you use a JMSContext, message delivery normally begins as soon as you create a
consumer. See JMS Message Consumers for more information.
If you create a JMSContext in a try-with-resources block, you do not need to close it
explicitly. It will be closed when the try block comes to an end. Make sure that your
application completes all its JMS activity within the try-with-resources block. If you
do not use a try-with-resources block, you must call the close method on the
JMSContext to close the connection when the application has finished its work.
45.3.5 JMS Message Producers
A message producer is an object that is created by a JMSContext or a session and used
for sending messages to a destination. A message producer created by a JMSContext
implements the JMSProducer interface. You could create it this way:
try (JMSContext context = connectionFactory.createContext();) {
JMSProducer producer = context.createProducer();
...
However, a JMSProducer is a lightweight object that does not consume significant
resources. For this reason, you do not need to save the JMSProducer in a variable; you
can create a new one each time you send a message. You send messages to a specific
destination by using the send method. For example:
context.createProducer().send(dest, message);
You can create the message in a variable before sending it, as shown here, or you can
create it within the send call. See JMS Messages for more information.
45.3.6 JMS Message Consumers
A message consumer is an object that is created by a JMSContext or a session and used
for receiving messages sent to a destination. A message producer created by a
JMSContext implements the JMSConsumer interface. The simplest way to create a
message consumer is to use the JMSContext.createConsumer method:
try (JMSContext context = connectionFactory.createContext();) {
JMSConsumer consumer = context.createConsumer(dest);
...
45-10 The Java EE 7 Tutorial
The JMS API Programming Model
A message consumer allows a JMS client to register interest in a destination with a JMS
provider. The JMS provider manages the delivery of messages from a destination to
the registered consumers of the destination.
When you use a JMSContext to create a message consumer, message delivery begins as
soon as you have created the consumer. You can disable this behavior by calling
setAutoStart(false) when you create the JMSContext and then calling the start
method explicitly to start message delivery. If you want to stop message delivery
temporarily without closing the connection, you can call the stop method; to restart
message delivery, call start.
You use the receive method to consume a message synchronously. You can use this
method at any time after you create the consumer.
If you specify no arguments or an argument of 0, the method blocks indefinitely until a
message arrives:
Message m = consumer.receive();
Message m = consumer.receive(0);
For a simple client, this may not matter. But if it is possible that a message might not
be available, use a synchronous receive with a timeout: Call the receive method with
a timeout argument greater than 0. One second is a recommended timeout value:
Message m = consumer.receive(1000); // time out after a second
To enable asynchronous message delivery from an application client or a Java SE
client, you use a message listener, as described in the next section.
You can use the JMSContext.createDurableConsumer method to create a durable topic
subscription. This method is valid only if you are using a topic. For details, see
Creating Durable Subscriptions. For topics, you can also create shared consumers; see
Creating Shared Subscriptions.
45.3.6.1 JMS Message Listeners
A message listener is an object that acts as an asynchronous event handler for
messages. This object implements the MessageListener interface, which contains one
method, onMessage. In the onMessage method, you define the actions to be taken when
a message arrives.
From an application client or a Java SE client, you register the message listener with a
specific message consumer by using the setMessageListener method. For example, if
you define a class named Listener that implements the MessageListener interface,
you can register the message listener as follows:
Listener myListener = new Listener();
consumer.setMessageListener(myListener);
When message delivery begins, the JMS provider automatically calls the message
listener's onMessage method whenever a message is delivered. The onMessage method
takes one argument of type Message, which your implementation of the method can
cast to another message subtype as needed (see Message Bodies).
In the Java EE web or EJB container, you use message-driven beans for asynchronous
message delivery. A message-driven bean also implements the MessageListener
interface and contains an onMessage method. For details, see Using Message-Driven
Beans to Receive Messages Asynchronously.
Java Message Service Concepts
45-11
The JMS API Programming Model
Your onMessage method should handle all exceptions. Throwing a RuntimeException
is considered a programming error.
For a simple example of the use of a message listener, see Using a Message Listener for
Asynchronous Message Delivery. Chapter 46, "Java Message Service Examples,"
contains several more examples of message listeners and message-driven beans.
45.3.6.2 JMS Message Selectors
If your messaging application needs to filter the messages it receives, you can use a
JMS message selector, which allows a message consumer for a destination to specify
the messages that interest it. Message selectors assign the work of filtering messages to
the JMS provider rather than to the application. For an example of an application that
uses a message selector, see Sending Messages from a Session Bean to an MDB.
A message selector is a String that contains an expression. The syntax of the
expression is based on a subset of the SQL92 conditional expression syntax. The
message selector in the example selects any message that has a NewsType property that
is set to the value 'Sports' or 'Opinion':
NewsType = 'Sports' OR NewsType = 'Opinion'
The createConsumer and createDurableConsumer methods, as well as the methods for
creating shared consumers, allow you to specify a message selector as an argument
when you create a message consumer.
The message consumer then receives only messages whose headers and properties
match the selector. (See Message Headers and Message Properties.) A message selector
cannot select messages on the basis of the content of the message body.
45.3.6.3 Consuming Messages from Topics
The semantics of consuming messages from topics are more complex than the
semantics of consuming messages from queues.
An application consumes messages from a topic by creating a subscription on that
topic and creating a consumer on that subscription. Subscriptions may be durable or
nondurable, and they may be shared or unshared.
A subscription may be thought of as an entity within the JMS provider itself, whereas
a consumer is a JMS object within the application.
A subscription will receive a copy of every message that is sent to the topic after the
subscription is created, unless a message selector is specified. If a message selector is
specified, only those messages whose properties match the message selector will be
added to the subscription.
Unshared subscriptions are restricted to a single consumer. In this case, all the
messages in the subscription are delivered to that consumer. Shared subscriptions
allow multiple consumers. In this case, each message in the subscription is delivered to
only one consumer. JMS does not define how messages are distributed between
multiple consumers on the same subscription.
Subscriptions may be durable or nondurable.
A nondurable subscription exists only as long as there is an active consumer on the
subscription. This means that any messages sent to the topic will be added to the
subscription only while a consumer exists and is not closed.
A nondurable subscription may be either unshared or shared.
45-12 The Java EE 7 Tutorial
The JMS API Programming Model
■
An unshared nondurable subscription does not have a name and may have only a
single consumer object associated with it. It is created automatically when the
consumer object is created. It is not persisted and is deleted automatically when
the consumer object is closed.
The JMSContext.createConsumer method creates a consumer on an unshared
nondurable subscription if a topic is specified as the destination.
■
A shared nondurable subscription is identified by name and an optional client
identifier, and may have several consumer objects consuming messages from it. It
is created automatically when the first consumer object is created. It is not
persisted and is deleted automatically when the last consumer object is closed. See
Creating Shared Subscriptions for more information.
At the cost of higher overhead, a subscription may be durable. A durable subscription
is persisted and continues to accumulate messages until explicitly deleted, even if
there are no consumer objects consuming messages from it. See Creating Durable
Subscriptions for details.
45.3.6.4 Creating Durable Subscriptions
To ensure that a pub/sub application receives all sent messages, use durable
subscriptions for the consumers on the topic.
Like a nondurable subscription, a durable subscription may be either unshared or
shared.
■
■
An unshared durable subscription is identified by name and client identifier
(which must be set) and may have only a single consumer object associated with
it.
A shared durable subscription is identified by name and an optional client
identifier, and may have several consumer objects consuming messages from it.
A durable subscription that exists but that does not currently have a non-closed
consumer object associated with it is described as being inactive.
You can use the JMSContext.createDurableConsumer method to create a consumer on
an unshared durable subscription. An unshared durable subscription can have only
one active consumer at a time.
A consumer identifies the durable subscription from which it consumes messages by
specifying a unique identity that is retained by the JMS provider. Subsequent
consumer objects that have the same identity resume the subscription in the state in
which it was left by the preceding consumer. If a durable subscription has no active
consumer, the JMS provider retains the subscription's messages until they are received
by the subscription or until they expire.
You establish the unique identity of an unshared durable subscription by setting the
following:
■
A client ID for the connection
■
A topic and a subscription name for the subscription
You can set the client ID administratively for a client-specific connection factory using
either the command line or the Administration Console. (In an application client or a
Java SE client, you can instead call JMSContext.setClientID.)
After using this connection factory to create the JMSContext, you call the
createDurableConsumer method with two arguments: the topic and a string that
specifies the name of the subscription:
Java Message Service Concepts
45-13
The JMS API Programming Model
String subName = "MySub";
JMSConsumer consumer = context.createDurableConsumer(myTopic, subName);
The subscription becomes active after you create the consumer. Later, you might close
the consumer:
consumer.close();
The JMS provider stores the messages sent to the topic, as it would store messages sent
to a queue. If the program or another application calls createDurableConsumer using
the same connection factory and its client ID, the same topic, and the same
subscription name, then the subscription is reactivated and the JMS provider delivers
the messages that were sent while the subscription was inactive.
To delete a durable subscription, first close the consumer, then call the unsubscribe
method with the subscription name as the argument:
consumer.close();
context.unsubscribe(subName);
The unsubscribe method deletes the state the provider maintains for the subscription.
Figure 45–6 and Figure 45–7 show the difference between a nondurable and a durable
subscription. With an ordinary, nondurable subscription, the consumer and the
subscription begin and end at the same point and are, in effect, identical. When the
consumer is closed, the subscription also ends. Here, create stands for a call to
JMSContext.createConsumer with a Topic argument, and close stands for a call to
JMSConsumer.close. Any messages sent to the topic between the time of the first close
and the time of the second create are not added to either subscription. In Figure 45–6,
the consumers receive messages M1, M2, M5, and M6, but they do not receive
messages M3 and M4.
Figure 45–6 Nondurable Subscriptions and Consumers
M1
M2
M3
Subscription
M4
M5
Subscription
Consumer
create
M6
Consumer
close
create
close
With a durable subscription, the consumer can be closed and re-created, but the
subscription continues to exist and to hold messages until the application calls the
unsubscribe method. In Figure 45–7, create stands for a call to
JMSContext.createDurableConsumer, close stands for a call to JMSConsumer.close,
and unsubscribe stands for a call to JMSContext.unsubscribe. Messages sent after the
first consumer is closed are received when the second consumer is created (on the
same durable subscription), so even though messages M2, M4, and M5 arrive while
there is no consumer, they are not lost.
45-14 The Java EE 7 Tutorial
The JMS API Programming Model
Figure 45–7 Consumers on a Durable Subscription
M1
M2
M3
M4
M5
M6
create
unsubscribe
Consumer
create
Consumer
close
create
Consumer
close
create
close
A shared durable subscription allows you to use multiple consumers to receive
messages from a durable subscription. If you use a shared durable subscription, the
connection factory you use does not need to have a client identifier. To create a shared
durable subscription, call the JMSContext.createSharedDurableConsumer method,
specifying the topic and subscription name:
JMSConsumer consumer =
context.createSharedDurableConsumer(topic, "MakeItLast");
See Acknowledging Messages, Using Durable Subscriptions, Using Shared Durable
Subscriptions, and Sending Messages from a Session Bean to an MDB for examples of
Java EE applications that use durable subscriptions.
45.3.6.5 Creating Shared Subscriptions
A topic subscription created by the createConsumer or createDurableConsumer
method can have only one consumer (although a topic can have many). Multiple
clients consuming from the same topic have, by definition, multiple subscriptions to
the topic, and all the clients receive all the messages sent to the topic (unless they filter
them with message selectors).
It is, however, possible to create a nondurable shared subscription to a topic by using
the createSharedConsumer method and specifying not only a destination but a
subscription name:
consumer = context.createSharedConsumer(topicName, "SubName");
With a shared subscription, messages will be distributed among multiple clients that
use the same topic and subscription name. Each message sent to the topic will be
added to every subscription (subject to any message selectors), but each message
added to a subscription will be delivered to only one of the consumers on that
subscription, so it will be received by only one of the clients. A shared subscription can
be useful if you want to share the message load among several consumers on the
subscription rather than having just one consumer on the subscription receive each
message. This feature can improve the scalability of Java EE application client
applications and Java SE applications. (Message-driven beans share the work of
processing messages from a topic among multiple threads.)
See Using Shared Nondurable Subscriptions for a simple example of using shared
nondurable consumers.
You can also create shared durable subscriptions by using the
JMSContext.createSharedDurableConsumer method. For details, see Creating Durable
Subscriptions.
Java Message Service Concepts
45-15
The JMS API Programming Model
45.3.7 JMS Messages
The ultimate purpose of a JMS application is to produce and consume messages that
can then be used by other software applications. JMS messages have a basic format
that is simple but highly flexible, allowing you to create messages that match formats
used by non-JMS applications on heterogeneous platforms.
A JMS message can have three parts: a header, properties, and a body. Only the header
is required. The following sections describe these parts.
For complete documentation of message headers, properties, and bodies, see the
documentation of the Message interface in the API documentation. For a list of
possible message types, see Message Bodies.
45.3.7.1 Message Headers
A JMS message header contains a number of predefined fields that contain values
used by both clients and providers to identify and route messages. Table 45–1 lists and
describes the JMS message header fields and indicates how their values are set. For
example, every message has a unique identifier, which is represented in the header
field JMSMessageID. The value of another header field, JMSDestination, represents the
queue or the topic to which the message is sent. Other fields include a timestamp and
a priority level.
Each header field has associated setter and getter methods, which are documented in
the description of the Message interface. Some header fields are intended to be set by a
client, but many are set automatically by the send method, which overrides any
client-set values.
Table 45–1
How JMS Message Header Field Values Are Set
Header Field
Description
Set By
JMSDestination
Destination to which the message is
being sent
JMS provider send method
JMSDeliveryMode
Delivery mode specified when the
message was sent (see Specifying
Message Persistence)
JMS provider send method
JMSDeliveryTime
The time the message was sent plus the JMS provider send method
delivery delay specified when the
message was sent (see Specifying a
Delivery Delay
JMSExpiration
Expiration time of the message (see
Allowing Messages to Expire)
JMSPriority
The priority of the message (see Setting JMS provider send method
Message Priority Levels)
JMSMessageID
Value that uniquely identifies each
message sent by a provider
JMS provider send method
JMSTimestamp
The time the message was handed off
to a provider to be sent
JMS provider send method
JMSCorrelationID
Value that links one message to
another; commonly the JMSMessageID
value is used
Client application
JMSReplyTo
Destination where replies to the
message should be sent
Client application
JMSType
Type identifier supplied by client
application
Client application
45-16 The Java EE 7 Tutorial
JMS provider send method
The JMS API Programming Model
Table 45–1 (Cont.) How JMS Message Header Field Values Are Set
Header Field
Description
Set By
JMSRedelivered
Whether the message is being
redelivered
JMS provider prior to delivery
45.3.7.2 Message Properties
You can create and set properties for messages if you need values in addition to those
provided by the header fields. You can use properties to provide compatibility with
other messaging systems, or you can use them to create message selectors (see JMS
Message Selectors). For an example of setting a property to be used as a message
selector, see Sending Messages from a Session Bean to an MDB.
The JMS API provides some predefined property names that begin with JMSX. A JMS
provider is required to implement only one of these, JMSXDeliveryCount (which
specifies the number of times a message has been delivered); the rest are optional. The
use of these predefined properties or of user-defined properties in applications is
optional.
45.3.7.3 Message Bodies
The JMS API defines six different types of messages. Each message type corresponds
to a different message body. These message types allow you to send and receive data
in many different forms. Table 45–2 describes these message types.
Table 45–2
JMS Message Types
Message Type
Body Contains
TextMessage
A java.lang.String object (for example, the contents of an XML file).
MapMessage
A set of name-value pairs, with names as String objects and values as
primitive types in the Java programming language. The entries can be
accessed sequentially by enumerator or randomly by name. The order
of the entries is undefined.
BytesMessage
A stream of uninterpreted bytes. This message type is for literally
encoding a body to match an existing message format.
StreamMessage
A stream of primitive values in the Java programming language, filled
and read sequentially.
ObjectMessage
A Serializable object in the Java programming language.
Message
Nothing. Composed of header fields and properties only. This message
type is useful when a message body is not required.
The JMS API provides methods for creating messages of each type and for filling in
their contents. For example, to create and send a TextMessage, you might use the
following statements:
TextMessage message = context.createTextMessage();
message.setText(msg_text);
// msg_text is a String
context.createProducer().send(message);
At the consuming end, a message arrives as a generic Message object. You can then cast
the object to the appropriate message type and use more specific methods to access the
body and extract the message contents (and its headers and properties if needed). For
example, you might use the stream-oriented read methods of BytesMessage. You must
always cast to the appropriate message type to retrieve the body of a StreamMessage.
Java Message Service Concepts
45-17
The JMS API Programming Model
Instead of casting the message to a message type, you can call the getBody method on
the Message, specifying the type of the message as an argument. For example, you can
retrieve a TextMessage as a String. The following code fragment uses the getBody
method:
Message m = consumer.receive();
if (m instanceof TextMessage) {
String message = m.getBody(String.class);
System.out.println("Reading message: " + message);
} else {
// Handle error or process another message type
}
The JMS API provides shortcuts for creating and receiving a TextMessage,
BytesMessage, MapMessage, or ObjectMessage. For example, you do not have to wrap a
string in a TextMessage; instead, you can send and receive the string directly. For
example, you can send a string as follows:
String message = "This is a message";
context.createProducer().send(dest, message);
You can receive the message by using the receiveBody method:
String message = receiver.receiveBody(String.class);
You can use the receiveBody method to receive any type of message except
StreamMessage and Message, as long as the body of the message can be assigned to a
particular type.
An empty Message can be useful if you want to send a message that is simply a signal
to the application. Some of the examples in Chapter 46, "Java Message Service
Examples," send an empty message after sending a series of text messages. For
example:
context.createProducer().send(dest, context.createMessage());
The consumer code can then interpret a non-text message as a signal that all the
messages sent have now been received.
The examples in Chapter 46, "Java Message Service Examples," use messages of type
TextMessage, MapMessage, and Message.
45.3.8 JMS Queue Browsers
Messages sent to a queue remain in the queue until the message consumer for that
queue consumes them. The JMS API provides a QueueBrowser object that allows you
to browse the messages in the queue and display the header values for each message.
To create a QueueBrowser object, use the JMSContext.createBrowser method. For
example:
QueueBrowser browser = context.createBrowser(queue);
See Browsing Messages on a Queue for an example of using a QueueBrowser object.
The createBrowser method allows you to specify a message selector as a second
argument when you create a QueueBrowser. For information on message selectors, see
JMS Message Selectors.
The JMS API provides no mechanism for browsing a topic. Messages usually
disappear from a topic as soon as they appear: If there are no message consumers to
consume them, the JMS provider removes them. Although durable subscriptions allow
45-18 The Java EE 7 Tutorial
Using Advanced JMS Features
messages to remain on a topic while the message consumer is not active, JMS does not
define any facility for examining them.
45.3.9 JMS Exception Handling
The root class for all checked exceptions in the JMS API is JMSException. The root
cause for all unchecked exceptions in the JMS API is JMSRuntimeException.
Catching JMSException and JMSRuntimeException provides a generic way of handling
all exceptions related to the JMS API.
The JMSException and JMSRuntimeException classes include the following subclasses,
described in the API documentation:
■
IllegalStateException, IllegalStateRuntimeException
■
InvalidClientIDException, InvalidClientIDRuntimeException
■
InvalidDestinationException, InvalidDestinationRuntimeException
■
InvalidSelectorException, InvalidSelectorRuntimeException
■
JMSSecurityException, JMSSecurityRuntimeException
■
MessageEOFException
■
MessageFormatException, MessageFormatRuntimeException
■
MessageNotReadableException
■
MessageNotWriteableException, MessageNotWriteableRuntimeException
■
ResourceAllocationException, ResourceAllocationRuntimeException
■
TransactionInProgressException, TransactionInProgressRuntimeException
■
TransactionRolledBackException, TransactionRolledBackRuntimeException
All the examples in the tutorial catch and handle JMSException or
JMSRuntimeException when it is appropriate to do so.
45.4 Using Advanced JMS Features
This section explains how to use features of the JMS API to achieve the level of
reliability and performance your application requires. Many people use JMS in their
applications because they cannot tolerate dropped or duplicate messages and because
they require that every message be received once and only once. The JMS API
provides this functionality.
The most reliable way to produce a message is to send a PERSISTENT message, and to
do so within a transaction.
JMS messages are PERSISTENT by default; PERSISTENT messages will not be lost in the
event of JMS provider failure. For details, see Specifying Message Persistence.
Transactions allow multiple messages to be sent or received in an atomic operation. In
the Java EE platform they also allow message sends and receives to be combined with
database reads and writes in an atomic transaction. A transaction is a unit of work into
which you can group a series of operations, such as message sends and receives, so
that the operations either all succeed or all fail. For details, see Using JMS Local
Transactions.
The most reliable way to consume a message is to do so within a transaction, either
from a queue or from a durable subscription to a topic. For details, see Creating
Java Message Service Concepts
45-19
Using Advanced JMS Features
Durable Subscriptions, Creating Temporary Destinations, and Using JMS Local
Transactions.
Some features primarily allow an application to improve performance. For example,
you can set messages to expire after a certain length of time (see Allowing Messages to
Expire), so that consumers do not receive unnecessary outdated information. You can
send messages asynchronously; see Sending Messages Asynchronously.
You can also specify various levels of control over message acknowledgment; see
Controlling Message Acknowledgment.
Other features can provide useful capabilities unrelated to reliability. For example, you
can create temporary destinations that last only for the duration of the connection in
which they are created. See Creating Temporary Destinations for details.
The following sections describe these features as they apply to application clients or
Java SE clients. Some of the features work differently in the Java EE web or EJB
container; in these cases, the differences are noted here and are explained in detail in
Using the JMS API in Java EE Applications.
45.4.1 Controlling Message Acknowledgment
Until a JMS message has been acknowledged, it is not considered to be successfully
consumed. The successful consumption of a message ordinarily takes place in three
stages.
1.
The client receives the message.
2.
The client processes the message.
3.
The message is acknowledged. Acknowledgment is initiated either by the JMS
provider or by the client, depending on the session acknowledgment mode.
In locally transacted sessions (see Using JMS Local Transactions), a message is
acknowledged when the session is committed. If a transaction is rolled back, all
consumed messages are redelivered.
In a JTA transaction (in the Java EE web or EJB container) a message is acknowledged
when the transaction is committed.
In nontransacted sessions, when and how a message is acknowledged depend on a
value that may be specified as an argument of the createContext method. The
possible argument values are as follows.
■
JMSContext.AUTO_ACKNOWLEDGE: This setting is the default for application clients
and Java SE clients. The JMSContext automatically acknowledges a client's receipt
of a message either when the client has successfully returned from a call to
receive or when the MessageListener it has called to process the message returns
successfully.
A synchronous receive in a JMSContext that is configured to use
auto-acknowledgment is the one exception to the rule that message consumption
is a three-stage process as described earlier. In this case, the receipt and
acknowledgment take place in one step, followed by the processing of the
message.
■
JMSContext.CLIENT_ACKNOWLEDGE: A client acknowledges a message by calling the
message's acknowledge method. In this mode, acknowledgment takes place on the
session level: Acknowledging a consumed message automatically acknowledges
the receipt of all messages that have been consumed by its session. For example, if
a message consumer consumes ten messages and then acknowledges the fifth
message delivered, all ten messages are acknowledged.
45-20 The Java EE 7 Tutorial
Using Advanced JMS Features
In the Java EE platform, the JMSContext.CLIENT_ACKNOWLEDGE
setting can be used only in an application client, not in a web
component or enterprise bean.
Note:
■
JMSContext.DUPS_OK_ACKNOWLEDGE: This option instructs the JMSContext to lazily
acknowledge the delivery of messages. This is likely to result in the delivery of
some duplicate messages if the JMS provider fails, so it should be used only by
consumers that can tolerate duplicate messages. (If the JMS provider redelivers a
message, it must set the value of the JMSRedelivered message header to true.)
This option can reduce session overhead by minimizing the work the session does
to prevent duplicates.
If messages have been received from a queue but not acknowledged when a
JMSContext is closed, the JMS provider retains them and redelivers them when a
consumer next accesses the queue. The provider also retains unacknowledged
messages if an application closes a JMSContext that has been consuming messages
from a durable subscription. (See Creating Durable Subscriptions.) Unacknowledged
messages that have been received from a nondurable subscription will be dropped
when the JMSContext is closed.
If you use a queue or a durable subscription, you can use the JMSContext.recover
method to stop a nontransacted JMSContext and restart it with its first
unacknowledged message. In effect, the JMSContext's series of delivered messages is
reset to the point after its last acknowledged message. The messages it now delivers
may be different from those that were originally delivered, if messages have expired or
if higher-priority messages have arrived. For a consumer on a nondurable
subscription, the provider may drop unacknowledged messages when the
JMSContext.recover method is called.
The sample program in Acknowledging Messages demonstrates two ways to ensure
that a message will not be acknowledged until processing of the message is complete.
45.4.2 Specifying Options for Sending Messages
You can set a number of options when you send a message. These options enable you
to perform the following tasks:
■
■
■
■
Specify that messages are persistent, meaning they must not be lost in the event of
a provider failure (Specifying Message Persistence)
Set priority levels for messages, which can affect the order in which the messages
are delivered (Setting Message Priority Levels)
Specify an expiration time for messages so they will not be delivered if they are
obsolete (Allowing Messages to Expire)
Specify a delivery delay for messages so that they will not be delivered until a
specified amount of time has expired (Specifying a Delivery Delay)
Method chaining allows you to specify more than one of these options when you
create a producer and call the send method; see Using JMSProducer Method Chaining.
45.4.2.1 Specifying Message Persistence
The JMS API supports two delivery modes specifying whether messages are lost if the
JMS provider fails. These delivery modes are fields of the DeliveryMode interface.
Java Message Service Concepts
45-21
Using Advanced JMS Features
■
■
The default delivery mode, PERSISTENT, instructs the JMS provider to take extra
care to ensure that a message is not lost in transit in case of a JMS provider failure.
A message sent with this delivery mode is logged to stable storage when it is sent.
The NON_PERSISTENT delivery mode does not require the JMS provider to store the
message or otherwise guarantee that it is not lost if the provider fails.
To specify the delivery mode, use the setDeliveryMode method of the JMSProducer
interface to set the delivery mode for all messages sent by that producer.
You can use method chaining to set the delivery mode when you create a producer
and send a message. The following call creates a producer with a NON_PERSISTENT
delivery mode and uses it to send a message:
context.createProducer()
.setDeliveryMode(DeliveryMode.NON_PERSISTENT).send(dest, msg);
If you do not specify a delivery mode, the default is PERSISTENT. Using the NON_
PERSISTENT delivery mode may improve performance and reduce storage overhead,
but you should use it only if your application can afford to miss messages.
45.4.2.2 Setting Message Priority Levels
You can use message priority levels to instruct the JMS provider to deliver urgent
messages first. Use the setPriority method of the JMSProducer interface to set the
priority level for all messages sent by that producer.
You can use method chaining to set the priority level when you create a producer and
send a message. For example, the following call sets a priority level of 7 for a producer
and then sends a message:
context.createProducer().setPriority(7).send(dest, msg);
The ten levels of priority range from 0 (lowest) to 9 (highest). If you do not specify a
priority level, the default level is 4. A JMS provider tries to deliver higher-priority
messages before lower-priority ones, but does not have to deliver messages in exact
order of priority.
45.4.2.3 Allowing Messages to Expire
By default, a message never expires. If a message will become obsolete after a certain
period, however, you may want to set an expiration time. Use the setTimeToLive
method of the JMSProducer interface to set a default expiration time for all messages
sent by that producer.
For example, a message that contains rapidly changing data such as a stock price will
become obsolete after a few minutes, so you might configure messages to expire after
that time.
You can use method chaining to set the time to live when you create a producer and
send a message. For example, the following call sets a time to live of five minutes for a
producer and then sends a message:
context.createProducer().setTimeToLive(300000).send(dest, msg);
If the specified timeToLive value is 0, the message never expires.
When the message is sent, the specified timeToLive is added to the current time to
give the expiration time. Any message not delivered before the specified expiration
time is destroyed. The destruction of obsolete messages conserves storage and
computing resources.
45-22 The Java EE 7 Tutorial
Using Advanced JMS Features
45.4.2.4 Specifying a Delivery Delay
You can specify a length of time that must elapse after a message is sent before the JMS
provider delivers the message. Use the setDeliveryDelay method of the JMSProducer
interface to set a delivery delay for all messages sent by that producer.
You can use method chaining to set the delivery delay when you create a producer and
send a message. For example, the following call sets a delivery delay of 3 seconds for a
producer and then sends a message:
context.createProducer().setDeliveryDelay(3000).send(dest, msg);
45.4.2.5 Using JMSProducer Method Chaining
The setter methods on the JMSProducer interface return JMSProducer objects, so you
can use method chaining to create a producer, set multiple properties, and send a
message. For example, the following chained method calls create a producer, set a
user-defined property, set the expiration, delivery mode, and priority for the message,
and then send a message to a queue:
context.createProducer()
.setProperty("MyProperty", "MyValue")
.setTimeToLive(10000)
.setDeliveryMode(NON_PERSISTENT)
.setPriority(2)
.send(queue, body);
You can also call the JMSProducer methods to set properties on a message and then
send the message in a separate send method call. You can also set message properties
directly on a message.
45.4.3 Creating Temporary Destinations
Normally, you create JMS destinations (queues and topics) administratively rather
than programmatically. Your JMS provider includes a tool to create and remove
destinations, and it is common for destinations to be long-lasting.
The JMS API also enables you to create destinations (TemporaryQueue and
TemporaryTopic objects) that last only for the duration of the connection in which they
are created. You create these destinations dynamically using the
JMSContext.createTemporaryQueue and the JMSContext.createTemporaryTopic
methods, as in the following example:
TemporaryTopic replyTopic = context.createTemporaryTopic();
The only message consumers that can consume from a temporary destination are those
created by the same connection that created the destination. Any message producer
can send to the temporary destination. If you close the connection to which a
temporary destination belongs, the destination is closed and its contents are lost.
You can use temporary destinations to implement a simple request/reply mechanism.
If you create a temporary destination and specify it as the value of the JMSReplyTo
message header field when you send a message, then the consumer of the message can
use the value of the JMSReplyTo field as the destination to which it sends a reply. The
consumer can also reference the original request by setting the JMSCorrelationID
header field of the reply message to the value of the JMSMessageID header field of the
request. For example, an onMessage method can create a JMSContext so that it can send
a reply to the message it receives. It can use code such as the following:
replyMsg = context.createTextMessage("Consumer processed message: "
+ msg.getText());
Java Message Service Concepts
45-23
Using Advanced JMS Features
replyMsg.setJMSCorrelationID(msg.getJMSMessageID());
context.createProducer().send((Topic) msg.getJMSReplyTo(), replyMsg);
For an example, see Using an Entity to Join Messages from Two MDBs.
45.4.4 Using JMS Local Transactions
A transaction groups a series of operations into an atomic unit of work. If any one of
the operations fails, the transaction can be rolled back, and the operations can be
attempted again from the beginning. If all the operations succeed, the transaction can
be committed.
In an application client or a Java SE client, you can use local transactions to group
message sends and receives. You use the JMSContext.commit method to commit a
transaction. You can send multiple messages in a transaction, and the messages will
not be added to the queue or topic until the transaction is committed. If you receive
multiple messages in a transaction, they will not be acknowledged until the
transaction is committed.
You can use the JMSContext.rollback method to roll back a transaction. A transaction
rollback means that all produced messages are destroyed and all consumed messages
are recovered and redelivered unless they have expired (see Allowing Messages to
Expire).
A transacted session is always involved in a transaction. To create a transacted session,
call the createContext method as follows:
JMSContext context =
connectionFactory.createContext(JMSContext.SESSION_TRANSACTED);
As soon as the commit or the rollback method is called, one transaction ends and
another transaction begins. Closing a transacted session rolls back its transaction in
progress, including any pending sends and receives.
In an application running in the Java EE web or EJB container, you cannot use local
transactions. Instead, you use JTA transactions, described in Using the JMS API in Java
EE Applications.
You can combine several sends and receives in a single JMS local transaction, so long
as they are all performed using the same JMSContext.
Do not use a single transaction if you use a request/reply mechanism, in which you
send a message and then receive a reply to that message. If you try to use a single
transaction, the program will hang, because the send cannot take place until the
transaction is committed. The following code fragment illustrates the problem:
// Don't do this!
outMsg.setJMSReplyTo(replyQueue);
context.createProducer().send(outQueue, outMsg);
consumer = context.createConsumer(replyQueue);
inMsg = consumer.receive();
context.commit();
Because a message sent during a transaction is not actually sent until the transaction is
committed, the transaction cannot contain any receives that depend on that message's
having been sent.
The production and the consumption of a message cannot both be part of the same
transaction. The reason is that the transactions take place between the clients and the
JMS provider, which intervenes between the production and the consumption of the
message. Figure 45–8 illustrates this interaction.
45-24 The Java EE 7 Tutorial
Using Advanced JMS Features
Figure 45–8 Using JMS Local Transactions
Client 1
Sends
Client 2
Consumes
Queue
Transaction 1
Transaction 2
The sending of one or more messages to one or more destinations by Client 1 can form
a single transaction, because it forms a single set of interactions with the JMS provider
using a single JMSContext. Similarly, the receiving of one or more messages from one
or more destinations by Client 2 also forms a single transaction using a single
JMSContext. But because the two clients have no direct interaction and are using two
different JMSContext objects, no transactions can take place between them.
Another way of putting this is that a transaction is a contract between a client and a
JMS provider that defines whether a message is sent to a destination or whether a
message is received from the destination. It is not a contract between the sending client
and the receiving client.
This is the fundamental difference between messaging and synchronized processing.
Instead of tightly coupling the sender and the receiver of a message, JMS couples the
sender of a message with the destination, and it separately couples the destination
with the receiver of the message. Therefore, while the sends and receives each have a
tight coupling with the JMS provider, they do not have any coupling with each other.
When you create a JMSContext, you can specify whether it is transacted by using the
JMSContext.SESSION_TRANSACTED argument to the createContext method. For
example:
try (JMSContext context = connectionFactory.createContext(
JMSContext.SESSION_TRANSACTED);) {
...
The commit and the rollback methods for local transactions are associated with the
session that underlies the JMSContext. You can combine operations on more than one
queue or topic, or on a combination of queues and topics, in a single transaction if you
use the same session to perform the operations. For example, you can use the same
JMSContext to receive a message from a queue and send a message to a topic in the
same transaction.
The example in Using Local Transactions shows how to use JMS local transactions.
45.4.5 Sending Messages Asynchronously
Normally, when you send a persistent message, the send method blocks until the JMS
provider confirms that the message was sent successfully. The asynchronous send
mechanism allows your application to send a message and continue work while
waiting to learn whether the send completed.
This feature is currently available only in application clients and Java SE clients.
Sending a message asynchronously involves supplying a callback object. You specify a
CompletionListener with an onCompletion method. For example, the following code
instantiates a CompletionListener named SendListener. It then calls the setAsync
method to specify that sends from this producer should be asynchronous and should
use the specified listener:
CompletionListener listener = new SendListener();
context.createProducer().setAsync(listener).send(dest, message);
Java Message Service Concepts
45-25
Using the JMS API in Java EE Applications
The CompletionListener class must implement two methods, onCompletion and
onException. The onCompletion method is called if the send succeeds, and the
onException method is called if it fails. A simple implementation of these methods
might look like this:
@Override
public void onCompletion(Message message) {
System.out.println("onCompletion method: Send has completed.");
}
@Override
public void onException(Message message, Exception e) {
System.out.println("onException method: send failed: " + e.toString());
System.out.println("Unsent message is: \n" + message);
}
45.5 Using the JMS API in Java EE Applications
This section describes how using the JMS API in enterprise bean applications or web
applications differs from using it in application clients.
A general rule in the Java EE platform specification applies to all Java EE components
that use the JMS API within EJB or web containers: Application components in the
web and EJB containers must not attempt to create more than one active (not closed)
Session object per connection. Multiple JMSContext objects are permitted, however,
since they combine a single connection and a single session.
This rule does not apply to application clients. The application client container
supports the creation of multiple sessions for each connection.
45.5.1 Creating Resources for Java EE Applications
You can use annotations to create application-specific connection factories and
destinations for Java EE enterprise bean or web components. The resources you create
in this way are visible only to the application for which you create them.
You can also use deployment descriptor elements to create these resources. Elements
specified in the deployment descriptor override elements specified in annotations. See
Packaging Applications for basic information about deployment descriptors. You must
use a deployment descriptor to create application-specific resources for application
clients.
To create a destination, use a @JMSDestinationDefinition annotation like the
following on a class:
@JMSDestinationDefinition(
name = "java:app/jms/myappTopic",
interfaceName = "javax.jms.Topic",
destinationName = "MyPhysicalAppTopic"
)
The name, interfaceName, and destinationName elements are required. You can
optionally specify a description element. To create multiple destinations, enclose
them in a @JMSDestinationDefinitions annotation, separated by commas.
To create a connection factory, use a @JMSConnectionFactoryDefinition annotation
like the following on a class:
@JMSConnectionFactoryDefinition(
45-26 The Java EE 7 Tutorial
Using the JMS API in Java EE Applications
name="java:app/jms/MyConnectionFactory"
)
The name element is required. You can optionally specify a number of other elements,
such as clientId if you want to use the connection factory for durable subscriptions,
or description. If you do not specify the interfaceName element, the default interface
is javax.jms.ConnectionFactory. To create multiple connection factories, enclose
them in a @JMSConnectionFactoryDefinitions annotation, separated by commas.
You need to specify the annotation only once for a given application, in any of the
components.
If your application contains one or more message-driven
beans, you may want to place the annotation on one of the
message-driven beans. If you place the annotation on a sending
component such as an application client, you need to specify the
mappedName element to look up the topic, instead of using the
destinationLookup property of the activation configuration
specification.
Note:
When you inject the resource into a component, use the value of the name element in
the definition annotation as the value of the lookup element in the @Resource
annotation:
@Resource(lookup = "java:app/jms/myappTopic")
private Topic topic;
The following portable JNDI namespaces are available. Which ones you can use
depends on how your application is packaged.
■
■
■
■
java:global: Makes the resource available to all deployed applications
java:app: Makes the resource available to all components in all modules in a
single application
java:module: Makes the resource available to all components within a given
module (for example, all enterprise beans within an EJB module)
java:comp: Makes the resource available to a single component only (except in a
web application, where it is equivalent to java:module)
See the API documentation for details on these annotations. The examples in Sending
and Receiving Messages Using a Simple Web Application, Sending Messages from a
Session Bean to an MDB, and Using an Entity to Join Messages from Two MDBs all use
the @JMSDestinationDefinition annotation. The other JMS examples do not use these
annotations. The examples that consist only of application clients are not deployed in
the application server and must therefore communicate with each other using
administratively created resources that exist outside of individual applications.
45.5.2 Using Resource Injection in Enterprise Bean or Web Components
You may use resource injection to inject both administered objects and JMSContext
objects in Java EE applications.
45.5.2.1 Injecting a ConnectionFactory, Queue, or Topic
Normally, you use the @Resource annotation to inject a ConnectionFactory, Queue, or
Topic into your Java EE application. These objects must be created administratively
Java Message Service Concepts
45-27
Using the JMS API in Java EE Applications
before you deploy your application. You may want to use the default connection
factory, whose JNDI name is java:comp/DefaultJMSConnectionFactory.
When you use resource injection in an application client component, you normally
declare the JMS resource static:
@Resource(lookup = "java:comp/DefaultJMSConnectionFactory")
private static ConnectionFactory connectionFactory;
@Resource(lookup = "jms/MyQueue")
private static Queue queue;
However, when you use this annotation in a session bean, a message-driven bean, or a
web component, do not declare the resource static:
@Resource(lookup = "java:comp/DefaultJMSConnectionFactory")
private ConnectionFactory connectionFactory;
@Resource(lookup = "jms/MyTopic")
private Topic topic;
If you declare the resource static in these components, runtime errors will result.
45.5.2.2 Injecting a JMSContext Object
To access a JMSContext object in an enterprise bean or web component, instead of
injecting the ConnectionFactory resource and then creating a JMSContext, you can use
the @Inject and @JMSConnectionFactory annotations to inject a JMSContext. To use
the default connection factory, use code like the following:
@Inject
private JMSContext context1;
To use your own connection factory, use code like the following:
@Inject
@JMSConnectionFactory("jms/MyConnectionFactory")
private JMSContext context2;
45.5.3 Using Java EE Components to Produce and to Synchronously Receive
Messages
An application that produces messages or synchronously receives them can use a Java
EE web or EJB component, such as a managed bean, a servlet, or a session bean, to
perform these operations. The example in Sending Messages from a Session Bean to an
MDB uses a stateless session bean to send messages to a topic. The example in Sending
and Receiving Messages Using a Simple Web Application uses managed beans to
produce and to consume messages.
Because a synchronous receive with no specified timeout ties up server resources, this
mechanism usually is not the best application design for a web or EJB component.
Instead, use a synchronous receive that specifies a timeout value, or use a
message-driven bean to receive messages asynchronously. For details about
synchronous receives, see JMS Message Consumers.
Using the JMS API in a Java EE component is in many ways similar to using it in an
application client. The main differences are the areas of resource management and
transactions.
45-28 The Java EE 7 Tutorial
Using the JMS API in Java EE Applications
45.5.3.1 Managing JMS Resources in Web and EJB Components
The JMS resources are a connection and a session, usually combined in a JMSContext
object. In general, it is important to release JMS resources when they are no longer
being used. Here are some useful practices to follow.
■
■
■
If you wish to maintain a JMS resource only for the life span of a business method,
use a try-with-resources statement to create the JMSContext so that it will be
closed automatically at the end of the try block.
To maintain a JMS resource for the duration of a transaction or request, inject the
JMSContext as described in Injecting a JMSContext Object. This will also cause the
resource to be released when it is no longer needed.
If you would like to maintain a JMS resource for the life span of an enterprise bean
instance, you can use a @PostConstruct callback method to create the resource
and a @PreDestroy callback method to close the resource. However, there is
normally no need to do this, since application servers usually maintain a pool of
connections. If you use a stateful session bean and you wish to maintain the JMS
resource in a cached state, you must close the resource in a @PrePassivate callback
method and set its value to null, and you must create it again in a @PostActivate
callback method.
45.5.3.2 Managing Transactions in Session Beans
Instead of using local transactions, you use JTA transactions. You can use either
container-managed transactions or bean-managed transactions. Normally, you use
container-managed transactions for bean methods that perform sends or receives,
allowing the EJB container to handle transaction demarcation. Because
container-managed transactions are the default, you do not have to specify them.
You can use bean-managed transactions and the
javax.transaction.UserTransaction interface's transaction demarcation methods,
but you should do so only if your application has special requirements and you are an
expert in using transactions. Usually, container-managed transactions produce the
most efficient and correct behavior. This tutorial does not provide any examples of
bean-managed transactions.
45.5.4 Using Message-Driven Beans to Receive Messages Asynchronously
The sections What Is a Message-Driven Bean? and How Does the JMS API Work with
the Java EE Platform? describe how the Java EE platform supports a special kind of
enterprise bean, the message-driven bean, which allows Java EE applications to
process JMS messages asynchronously. Other Java EE web and EJB components allow
you to send messages and to receive them synchronously but not asynchronously.
A message-driven bean is a message listener to which messages can be delivered from
either a queue or a topic. The messages can be sent by any Java EE component (from
an application client, another enterprise bean, or a web component) or from an
application or a system that does not use Java EE technology.
A message-driven bean class has the following requirements.
■
It must be annotated with the @MessageDriven annotation if it does not use a
deployment descriptor.
■
The class must be defined as public, but not as abstract or final.
■
It must contain a public constructor with no arguments.
Java Message Service Concepts
45-29
Using the JMS API in Java EE Applications
It is recommended, but not required, that a message-driven bean class implement the
message listener interface for the message type it supports. A bean that supports the
JMS API implements the javax.jms.MessageListener interface, which means that it
must provide an onMessage method with the following signature:
void onMessage(Message inMessage)
The onMessage method is called by the bean's container when a message has arrived
for the bean to service. This method contains the business logic that handles the
processing of the message. It is the message-driven bean's responsibility to parse the
message and perform the necessary business logic.
A message-driven bean differs from an application client's message listener in the
following ways.
■
■
■
■
In an application client, you must create a JMSContext, then create a JMSConsumer,
then call setMessageListener to activate the listener. For a message-driven bean,
you need only define the class and annotate it, and the EJB container creates it for
you.
The bean class uses the @MessageDriven annotation, which typically contains an
activationConfig element containing @ActivationConfigProperty annotations
that specify properties used by the bean or the connection factory. These properties
can include the connection factory, a destination type, a durable subscription, a
message selector, or an acknowledgment mode. Some of the examples in
Chapter 46, "Java Message Service Examples" set these properties. You can also set
the properties in the deployment descriptor.
The application client container has only one instance of a MessageListener,
which is called on a single thread at a time. A message-driven bean, however, may
have multiple instances, configured by the container, which may be called
concurrently by multiple threads (although each instance is called by only one
thread at a time). Message-driven beans may therefore allow much faster
processing of messages than message listeners.
You do not need to specify a message acknowledgment mode unless you use
bean-managed transactions. The message is consumed in the transaction in which
the onMessage method is invoked.
Table 45–3 lists the activation configuration properties defined by the JMS
specification.
Table 45–3
@ActivationConfigProperty Settings for Message-Driven Beans
Property Name
Description
acknowledgeMode
Acknowledgment mode, used only for bean-managed
transactions; the default is Auto-acknowledge
(Dups-ok-acknowledge is also permitted)
destinationLookup
The lookup name of the queue or topic from which the bean
will receive messages
destinationType
Either javax.jms.Queue or javax.jms.Topic
subscriptionDurability
For durable subscriptions, set the value to Durable; see
Creating Durable Subscriptions for more information
clientId
For durable subscriptions, the client ID for the connection
(optional)
subscriptionName
For durable subscriptions, the name of the subscription
45-30 The Java EE 7 Tutorial
Using the JMS API in Java EE Applications
Table 45–3 (Cont.) @ActivationConfigProperty Settings for Message-Driven Beans
Property Name
Description
messageSelector
A string that filters messages; see JMS Message Selectors for
information
connectionFactoryLookup
The lookup name of the connection factory to be used to
connect to the JMS provider from which the bean will receive
messages
For example, here is the message-driven bean used in Receiving Messages
Asynchronously Using a Message-Driven Bean:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup",
propertyValue = "jms/MyQueue"),
@ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Queue")
})
public class SimpleMessageBean implements MessageListener {
@Resource
private MessageDrivenContext mdc;
static final Logger logger = Logger.getLogger("SimpleMessageBean");
public SimpleMessageBean() {
}
@Override
public void onMessage(Message inMessage) {
try {
if (inMessage instanceof TextMessage) {
logger.log(Level.INFO,
"MESSAGE BEAN: Message received: {0}",
inMessage.getBody(String.class));
} else {
logger.log(Level.WARNING,
"Message of wrong type: {0}",
inMessage.getClass().getName());
}
} catch (JMSException e) {
logger.log(Level.SEVERE,
"SimpleMessageBean.onMessage: JMSException: {0}",
e.toString());
mdc.setRollbackOnly();
}
}
}
If JMS is integrated with the application server using a resource adapter, the JMS
resource adapter handles these tasks for the EJB container.
The bean class commonly injects a MessageDrivenContext resource, which provides
some additional methods you can use for transaction management (setRollbackOnly,
for example):
@Resource
private MessageDrivenContext mdc;
Java Message Service Concepts
45-31
Using the JMS API in Java EE Applications
A message-driven bean never has a local or remote interface. Instead, it has only a
bean class.
A message-driven bean is similar in some ways to a stateless session bean: Its instances
are relatively short-lived and retain no state for a specific client. The instance variables
of the message-driven bean instance can contain some state across the handling of
client messages: for example, an open database connection, or an object reference to an
enterprise bean object.
Like a stateless session bean, a message-driven bean can have many interchangeable
instances running at the same time. The container can pool these instances to allow
streams of messages to be processed concurrently. The container attempts to deliver
messages in chronological order when that would not impair the concurrency of
message processing, but no guarantees are made as to the exact order in which
messages are delivered to the instances of the message-driven bean class. If message
order is essential to your application, you may want to configure your application
server to use just one instance of the message-driven bean.
For details on the lifecycle of a message-driven bean, see The Lifecycle of a
Message-Driven Bean.
45.5.5 Managing JTA Transactions
Java EE application clients and Java SE clients use JMS local transactions (described in
Using JMS Local Transactions), which allow the grouping of sends and receives within
a specific JMS session. Java EE applications that run in the web or EJB container
commonly use JTA transactions to ensure the integrity of accesses to external
resources. The key difference between a JTA transaction and a JMS local transaction is
that a JTA transaction is controlled by the application server's transaction managers.
JTA transactions may be distributed, which means that they can encompass multiple
resources in the same transaction, such as a JMS provider and a database.
For example, distributed transactions allow multiple applications to perform atomic
updates on the same database, and they allow a single application to perform atomic
updates on multiple databases.
In a Java EE application that uses the JMS API, you can use transactions to combine
message sends or receives with database updates and other resource manager
operations. You can access resources from multiple application components within a
single transaction. For example, a servlet can start a transaction, access multiple
databases, invoke an enterprise bean that sends a JMS message, invoke another
enterprise bean that modifies an EIS system using the Connector Architecture, and
finally commit the transaction. Your application cannot, however, both send a JMS
message and receive a reply to it within the same transaction.
JTA transactions within the EJB and web containers can be either of two kinds.
■
Container-managed transactions: The container controls the integrity of your
transactions without your having to call commit or rollback. Container-managed
transactions are easier to use than bean-managed transactions. You can specify
appropriate transaction attributes for your enterprise bean methods.
Use the Required transaction attribute (the default) to ensure that a method is
always part of a transaction. If a transaction is in progress when the method is
called, the method will be part of that transaction; if not, a new transaction will be
started before the method is called and will be committed when the method
returns. See Transaction Attributes for more information.
■
Bean-managed transactions: You can use these in conjunction with the
javax.transaction.UserTransaction interface, which provides its own commit
45-32 The Java EE 7 Tutorial
Further Information about JMS
and rollback methods you can use to delimit transaction boundaries.
Bean-managed transactions are recommended only for those who are experienced
in programming transactions.
You can use either container-managed transactions or bean-managed transactions with
message-driven beans. To ensure that all messages are received and handled within
the context of a transaction, use container-managed transactions and use the Required
transaction attribute (the default) for the onMessage method.
When you use container-managed transactions, you can call the following
MessageDrivenContext methods.
■
■
setRollbackOnly: Use this method for error handling. If an exception occurs,
setRollbackOnly marks the current transaction so that the only possible outcome
of the transaction is a rollback.
getRollbackOnly: Use this method to test whether the current transaction has
been marked for rollback.
If you use bean-managed transactions, the delivery of a message to the onMessage
method takes place outside the JTA transaction context. The transaction begins when
you call the UserTransaction.begin method within the onMessage method, and it
ends when you call UserTransaction.commit or UserTransaction.rollback. Any call
to the Connection.createSession method must take place within the transaction.
Using bean-managed transactions allows you to process the message by using more
than one transaction or to have some parts of the message processing take place
outside a transaction context. However, if you use container-managed transactions, the
message is received by the MDB and processed by the onMessage method within the
same transaction. It is not possible to achieve this behavior with bean-managed
transactions.
When you create a JMSContext in a JTA transaction (in the web or EJB container), the
container ignores any arguments you specify, because it manages all transactional
properties. When you create a JMSContext in the web or EJB container and there is no
JTA transaction, the value (if any) passed to the createContext method should be
JMSContext.AUTO_ACKNOWLEDGE or JMSContext.DUPS_OK_ACKNOWLEDGE.
When you use container-managed transactions, you normally use the Required
transaction attribute (the default) for your enterprise bean's business methods.
You do not specify the activation configuration property acknowledgeMode when you
create a message-driven bean that uses container-managed transactions. The container
acknowledges the message automatically when it commits the transaction.
If a message-driven bean uses bean-managed transactions, the message receipt cannot
be part of the bean-managed transaction. You can set the activation configuration
property acknowledgeMode to Auto-acknowledge or Dups-ok-acknowledge to specify
how you want the message received by the message-driven bean to be acknowledged.
If the onMessage method throws a RuntimeException, the container does not
acknowledge processing the message. In that case, the JMS provider will redeliver the
unacknowledged message in the future.
45.6 Further Information about JMS
For more information about JMS, see
■
Java Message Service website:
http://www.oracle.com/technetwork/java/index-jsp-142945.html
Java Message Service Concepts
45-33
Further Information about JMS
■
Java Message Service specification, version 2.0, available from:
http://jcp.org/en/jsr/detail?id=343
45-34 The Java EE 7 Tutorial
46
Java Message Service Examples
46
This chapter provides examples that show how to use the JMS API in various kinds of
Java EE applications. It covers the following topics:
■
Overview of the JMS Examples
■
Writing Simple JMS Applications
■
Writing More Advanced JMS Applications
■
Writing High Performance and Scalable JMS Applications
■
Sending and Receiving Messages Using a Simple Web Application
■
Receiving Messages Asynchronously Using a Message-Driven Bean
■
Sending Messages from a Session Bean to an MDB
■
Using an Entity to Join Messages from Two MDBs
■
Using NetBeans IDE to Create JMS Resources
A final section covers Using NetBeans IDE to Create JMS Resources.
The examples are in the tut-install/examples/jms/ directory.
The steps to build and run each example are as follows.
1.
Use NetBeans IDE or Maven to compile, package, and in some cases deploy the
example.
2.
Use NetBeans IDE, Maven, or the appclient command to run the application
client, or use the browser to run the web application examples.
Before you deploy or run the examples, you need to create resources for them. Some
examples have a glassfish-resources.xml file that is used to create resources for that
example and others. You can use the asadmin command to create the resources.
To use the asadmin and appclient commands, you need to put the GlassFish Server
bin directories in your command path, as described in SDK Installation Tips.
46.1 Overview of the JMS Examples
The following tables list the examples used in this chapter, describe what they do, and
link to the section that describes them fully. The example directory for each example is
relative to the tut-install/examples/jms/ directory.
Java Message Service Examples 46-1
Writing Simple JMS Applications
Table 46–1
JMS Examples That Show the Use of Java EE Application Clients
Example Directory
Description
simple/producer
Using an application client to send messages; see Sending
Messages
simple/synchconsumer
Using an application client to receive messages
synchronously; see Receiving Messages Synchronously
simple/asynchconsumer
Using an application client to receive messages
asynchronously; see Using a Message Listener for
Asynchronous Message Delivery
simple/messagebrowser
Using an application client to use a QueueBrowser to
browse a queue; see Browsing Messages on a Queue
simple/clientackconsumer
Using an application client to acknowledge messages
received synchronously; see Acknowledging Messages
durablesubscriptionexample
Using an application client to create a durable subscription
on a topic; see Using Durable Subscriptions
transactedexample
Using an application client to send and receive messages in
local transactions (also uses request-reply messaging); see
Using Local Transactions
shared/sharedconsumer
Using an application client to create shared nondurable
topic subscriptions; see Using Shared Nondurable
Subscriptions
shared/shareddurableconsumer
Using an application client to create shared durable topic
subscriptions; see Using Shared Durable Subscriptions
Table 46–2
JMS Examples That Show the Use of Java EE Web and EJB Components
Example Directory
Description
websimplemessage
Using managed beans to send messages and to receive messages
synchronously; see Sending and Receiving Messages Using a Simple
Web Application
simplemessage
Using an application client to send messages, and using a
message-driven bean to receive messages asynchronously; see
Receiving Messages Asynchronously Using a Message-Driven Bean
clientsessionmdb
Using a session bean to send messages, and using a message-driven
bean to receive messages; see Sending Messages from a Session Bean
to an MDB
clientmdbentity
Using an application client, two message-driven beans, and JPA
persistence to create a simple HR application; see Using an Entity to
Join Messages from Two MDBs
46.2 Writing Simple JMS Applications
This section shows how to create, package, and run simple JMS clients that are
packaged as application clients. The clients demonstrate the basic tasks a JMS
application must perform:
■
Creating a JMSContext
■
Creating message producers and consumers
■
Sending and receiving messages
46-2 The Java EE 7 Tutorial
Writing Simple JMS Applications
Each example uses two clients: one that sends messages and one that receives them.
You can run the clients in two terminal windows.
When you write a JMS client to run in an enterprise bean application, you use many of
the same methods in much the same sequence as for an application client. However,
there are some significant differences. Using the JMS API in Java EE Applications
describes these differences, and this chapter provides examples that illustrate them.
The examples for this section are in the tut-install/examples/jms/simple/ directory,
under the following subdirectories:
producer/
synchconsumer/
asynchconsumer/
messagebrowser/
clientackconsumer/
Before running the examples, you need to start GlassFish Server and create
administered objects.
46.2.1 Starting the JMS Provider
When you use GlassFish Server, your JMS provider is GlassFish Server. Start the
server as described in Starting and Stopping GlassFish Server.
46.2.2 Creating JMS Administered Objects
This example uses the following JMS administered objects:
■
A connection factory
■
Two destination resources: a topic and a queue
Before you run the applications, you can use the asadmin add-resources command to
create needed JMS resources, specifying as the argument a file named
glassfish-resources.xml. This file can be created in any project using NetBeans IDE,
although you can also create it by hand. A file for the needed resources is present in
the jms/simple/producer/src/main/setup/ directory.
The JMS examples use a connection factory with the logical JNDI lookup name
java:comp/DefaultJMSConnectionFactory, which is preconfigured in GlassFish
Server.
You can also use the asadmin create-jms-resource command to create resources, the
asadmin list-jms-resources command to display their names, and the asadmin
delete-jms-resource command to remove them.
46.2.2.1 To Create Resources for the Simple Examples
A glassfish-resources.xml file in one of the Maven projects can create all the
resources needed for the simple examples.
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a command window, go to the Producer example.
cd tut-install/jms/simple/producer
3.
Create the resources using the asadmin add-resources command:
asadmin add-resources src/main/setup/glassfish-resources.xml
Java Message Service Examples 46-3
Writing Simple JMS Applications
4.
Verify the creation of the resources:
asadmin list-jms-resources
The command lists the two destinations and connection factory specified in the
glassfish-resources.xml file in addition to the platform default connection
factory:
jms/MyQueue
jms/MyTopic
jms/__defaultConnectionFactory
Command list-jms-resources executed successfully.
In GlassFish Server, the Java EE java:comp/DefaultJMSConnectionFactory
resource is mapped to a connection factory named jms/__
defaultConnectionFactory.
46.2.3 Building All the Simple Examples
To run the simple examples using GlassFish Server, package each example in an
application client JAR file. The application client JAR file requires a manifest file,
located in the src/main/java/META-INF/ directory for each example, along with the
.class file.
The pom.xml file for each example specifies a plugin that creates an application client
JAR file. You can build the examples using either NetBeans IDE or Maven.
46.2.3.1 To Build All the Simple Examples Using NetBeans IDE
1.
From the File menu, choose Open Project.
2.
In the Open Project dialog box, navigate to:
tut-install/examples/jms
3.
Expand the jms node and select the simple folder.
4.
Click Open Project to open all the simple examples.
5.
In the Projects tab, right-click the simple project and select Build to build all the
examples.
This command places the application client JAR files in the target directories for
the examples.
46.2.3.2 To Build All the Simple Examples Using Maven
1.
In a terminal window, go to the simple directory:
cd tut-install/jms/simple/
2.
Enter the following command to build all the projects:
mvn install
This command places the application client JAR files in the target directories for
the examples.
46-4 The Java EE 7 Tutorial
Writing Simple JMS Applications
46.2.4 Sending Messages
This section describes how to use a client to send messages. The Producer.java client
will send messages in all of these examples.
The general steps this example performs are as follows.
1.
Inject resources for the administered objects used by the example.
2.
Accept and verify command-line arguments. You can use this example to send any
number of messages to either a queue or a topic, so you specify the destination
type and the number of messages on the command line when you run the
program.
3.
Create a JMSContext, then send the specified number of text messages in the form
of strings, as described in Message Bodies.
4.
Send a final message of type Message to indicate that the consumer should expect
no more messages.
5.
Catch any exceptions.
46.2.4.1 The Producer.java Client
The sending client, Producer.java, performs the following steps.
1.
Injects resources for a connection factory, queue, and topic:
@Resource(lookup = "java:comp/DefaultJMSConnectionFactory")
private static ConnectionFactory connectionFactory;
@Resource(lookup = "jms/MyQueue")
private static Queue queue;
@Resource(lookup = "jms/MyTopic")
private static Topic topic;
2.
Retrieves and verifies command-line arguments that specify the destination type
and the number of arguments:
final int NUM_MSGS;
String destType = args[0];
System.out.println("Destination type is " + destType);
if ( ! ( destType.equals("queue") || destType.equals("topic") ) ) {
System.err.println("Argument must be \"queue\" or " + "\"topic\"");
System.exit(1);
}
if (args.length == 2){
NUM_MSGS = (new Integer(args[1])).intValue();
} else {
NUM_MSGS = 1;
}
3.
Assigns either the queue or the topic to a destination object, based on the specified
destination type:
Destination dest = null;
try {
if (destType.equals("queue")) {
dest = (Destination) queue;
} else {
dest = (Destination) topic;
}
} catch (Exception e) {
System.err.println("Error setting destination: " + e.toString());
System.exit(1);
Java Message Service Examples 46-5
Writing Simple JMS Applications
}
4.
Within a try-with-resources block, creates a JMSContext:
try (JMSContext context = connectionFactory.createContext();) {
5.
Sets the message count to zero, then creates a JMSProducer and sends one or more
messages to the destination and increments the count. Messages in the form of
strings are of the TextMessage message type:
int count = 0;
for (int i = 0; i < NUM_MSGS; i++) {
String message = "This is message " + (i + 1)
+ " from producer";
// Comment out the following line to send many messages
System.out.println("Sending message: " + message);
context.createProducer().send(dest, message);
count += 1;
}
System.out.println("Text messages sent: " + count);
6.
Sends an empty control message to indicate the end of the message stream:
context.createProducer().send(dest, context.createMessage());
Sending an empty message of no specified type is a convenient way for an
application to indicate to the consumer that the final message has arrived.
7.
Catches and handles any exceptions. The end of the try-with-resources block
automatically causes the JMSContext to be closed:
} catch (Exception e) {
System.err.println("Exception occurred: " + e.toString());
System.exit(1);
}
System.exit(0);
46.2.4.2 To Run the Producer Client
You can run the client using the appclient command. The Producer client takes one or
two command-line arguments: a destination type and, optionally, a number of
messages. If you do not specify a number of messages, the client sends one message.
You will use the client to send three messages to a queue.
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server) and that you have created resources and built the simple JMS
examples (see Creating JMS Administered Objects and Building All the Simple
Examples).
2.
In a terminal window, go to the producer directory:
cd producer
3.
Run the Producer program, sending three messages to the queue:
appclient -client target/producer.jar queue 3
The output of the program looks like this (along with some additional output):
Destination type
Sending message:
Sending message:
Sending message:
46-6 The Java EE 7 Tutorial
is queue
This is message 1 from producer
This is message 2 from producer
This is message 3 from producer
Writing Simple JMS Applications
Text messages sent: 3
The messages are now in the queue, waiting to be received.
When you run an application client, the command may take
a long time to complete.
Note:
46.2.5 Receiving Messages Synchronously
This section describes the receiving client, which uses the receive method to consume
messages synchronously. This section then explains how to run the clients using
GlassFish Server.
46.2.5.1 The SynchConsumer.java Client
The receiving client, SynchConsumer.java, performs the following steps.
1.
Injects resources for a connection factory, queue, and topic.
2.
Assigns either the queue or the topic to a destination object, based on the specified
destination type.
3.
Within a try-with-resources block, creates a JMSContext.
4.
Creates a JMSConsumer, starting message delivery:
consumer = context.createConsumer(dest);
5.
Receives the messages sent to the destination until the end-of-message-stream
control message is received:
int count = 0;
while (true) {
Message m = consumer.receive(1000);
if (m != null) {
if (m instanceof TextMessage) {
System.out.println(
"Reading message: " + m.getBody(String.class));
count += 1;
} else {
break;
}
}
}
System.out.println("Messages received: " + count);
Because the control message is not a TextMessage, the receiving client terminates
the while loop and stops receiving messages after the control message arrives.
6.
Catches and handles any exceptions. The end of the try-with-resources block
automatically causes the JMSContext to be closed.
The SynchConsumer client uses an indefinite while loop to receive messages, calling
receive with a timeout argument.
46.2.5.2 To Run the SynchConsumer and Producer Clients
You can run the client using the appclient command. The SynchConsumer client takes
one command-line argument, the destination type.
Java Message Service Examples 46-7
Writing Simple JMS Applications
These steps show how to receive and send messages synchronously using both a
queue and a topic. The steps assume you already ran the Producer client and have
three messages waiting in the queue.
1.
In the same terminal window where you ran Producer, go to the synchconsumer
directory:
cd ../synchconsumer
2.
Run the SynchConsumer client, specifying the queue:
appclient -client target/synchconsumer.jar queue
The output of the client looks like this (along with some additional output):
Destination type is queue
Reading message: This is message 1 from producer
Reading message: This is message 2 from producer
Reading message: This is message 3 from producer
Messages received: 3
3.
Now try running the clients in the opposite order. Run the SynchConsumer client:
appclient -client target/synchconsumer.jar queue
The client displays the destination type and then waits for messages.
4.
Open a new terminal window and run the Producer client:
cd tut-install/jms/simple/producer
appclient -client target/producer.jar queue 3
When the messages have been sent, the SynchConsumer client receives them and
exits.
5.
Now run the Producer client using a topic instead of a queue:
appclient -client target/producer.jar topic 3
The output of the client looks like this (along with some additional output):
Destination type is topic
Sending message: This is message 1 from producer
Sending message: This is message 2 from producer
Sending message: This is message 3 from producer
Text messages sent: 3
6.
Now, in the other terminal window, run the SynchConsumer client using the topic:
appclient -client target/synchconsumer.jar topic
The result, however, is different. Because you are using a subscription on a topic,
messages that were sent before you created the subscription on the topic will not
be added to the subscription and delivered to the consumer. (See
Publish/Subscribe Messaging Style and Consuming Messages from Topics for
details.) Instead of receiving the messages, the client waits for messages to arrive.
7.
Leave the SynchConsumer client running and run the Producer client again:
appclient -client target/producer.jar topic 3
Now the SynchConsumer client receives the messages:
Destination type is topic
Reading message: This is message 1 from producer
46-8 The Java EE 7 Tutorial
Writing Simple JMS Applications
Reading message: This is message 2 from producer
Reading message: This is message 3 from producer
Messages received: 3
Because these messages were sent after the consumer was started, the client
receives them.
46.2.6 Using a Message Listener for Asynchronous Message Delivery
This section describes the receiving clients in an example that uses a message listener
for asynchronous message delivery. This section then explains how to compile and run
the clients using GlassFish Server.
In the Java EE platform, message listeners can be used only in
application clients, as in this example. To allow asynchronous message
delivery in a web or enterprise bean application, you use a
message-driven bean, shown in later examples in this chapter.
Note:
46.2.6.1 Writing the AsynchConsumer.java and TextListener.java Clients
The sending client is Producer.java, the same client used in Sending Messages and
Receiving Messages Synchronously.
An asynchronous consumer normally runs indefinitely. This one runs until the user
types the character q or Q to stop the client.
The client, AsynchConsumer.java, performs the following steps.
1.
Injects resources for a connection factory, queue, and topic.
2.
Assigns either the queue or the topic to a destination object, based on the specified
destination type.
3.
In a try-with-resources block, creates a JMSContext.
4.
Creates a JMSConsumer.
5.
Creates an instance of the TextListener class and registers it as the message
listener for the JMSConsumer:
listener = new TextListener();
consumer.setMessageListener(listener);
6.
Listens for the messages sent to the destination, stopping when the user types the
character q or Q (it uses a java.io.InputStreamReader to do this).
7.
Catches and handles any exceptions. The end of the try-with-resources block
automatically causes the JMSContext to be closed, thus stopping delivery of
messages to the message listener.
The message listener, TextListener.java, follows these steps:
1.
When a message arrives, the onMessage method is called automatically.
2.
If the message is a TextMessage, the onMessage method displays its content as a
string value. If the message is not a text message, it reports this fact:
public void onMessage(Message m) {
try {
if (m instanceof TextMessage) {
System.out.println(
"Reading message: " + m.getBody(String.class));
Java Message Service Examples 46-9
Writing Simple JMS Applications
} else {
System.out.println("Message is not a TextMessage");
}
} catch (JMSException | JMSRuntimeException e) {
System.err.println("JMSException in onMessage(): " + e.toString());
}
}
For this example, you will use the same connection factory and destinations you
created in To Create Resources for the Simple Examples.
The steps assume that you have already built and packaged all the examples using
NetBeans IDE or Maven.
46.2.6.2 To Run the AsynchConsumer and Producer Clients
You will need two terminal windows, as you did in Receiving Messages
Synchronously.
1.
In the terminal window where you ran the SynchConsumer client, go to the
asynchconsumer example directory:
cd tut-install/jms/simple/asynchconsumer
2.
Run the AsynchConsumer client, specifying the topic destination type:
appclient -client target/asynchconsumer.jar topic
The client displays the following lines (along with some additional output) and
then waits for messages:
Destination type is topic
To end program, enter Q or q, then <return>
3.
In the terminal window where you ran the Producer client previously, run the
client again, sending three messages:
appclient -client target/producer.jar topic 3
The output of the client looks like this (along with some additional output):
Destination type is topic
Sending message: This is message 1 from producer
Sending message: This is message 2 from producer
Sending message: This is message 3 from producer
Text messages sent: 3
In the other window, the AsynchConsumer client displays the following (along with
some additional output):
Destination type is topic
To end program, enter Q or q, then
Reading message: This is message 1
Reading message: This is message 2
Reading message: This is message 3
Message is not a TextMessage
<return>
from producer
from producer
from producer
The last line appears because the client has received the non-text control message
sent by the Producer client.
4.
Enter Q or q and press Return to stop the AsynchConsumer client.
5.
Now run the clients using a queue.
46-10 The Java EE 7 Tutorial
Writing Simple JMS Applications
In this case, as with the synchronous example, you can run the Producer client
first, because there is no timing dependency between the sender and receiver:
appclient -client target/producer.jar queue 3
The output of the client looks like this:
Destination type is queue
Sending message: This is message 1 from producer
Sending message: This is message 2 from producer
Sending message: This is message 3 from producer
Text messages sent: 3
6.
In the other window, run the AsynchConsumer client:
appclient -client target/asynchconsumer.jar queue
The output of the client looks like this (along with some additional output):
Destination type is queue
To end program, enter Q or q, then
Reading message: This is message 1
Reading message: This is message 2
Reading message: This is message 3
Message is not a TextMessage
7.
<return>
from producer
from producer
from producer
Enter Q or q and press Return to stop the client.
46.2.7 Browsing Messages on a Queue
This section describes an example that creates a QueueBrowser object to examine
messages on a queue, as described in JMS Queue Browsers. This section then explains
how to compile, package, and run the example using GlassFish Server.
46.2.7.1 The MessageBrowser.java Client
To create a QueueBrowser for a queue, you call the JMSContext.createBrowser method
with the queue as the argument. You obtain the messages in the queue as an
Enumeration object. You can then iterate through the Enumeration object and display
the contents of each message.
The MessageBrowser.java client performs the following steps.
1.
Injects resources for a connection factory and a queue.
2.
In a try-with-resources block, creates a JMSContext.
3.
Creates a QueueBrowser:
QueueBrowser browser = context.createBrowser(queue);
4.
Retrieves the Enumeration that contains the messages:
Enumeration msgs = browser.getEnumeration();
5.
Verifies that the Enumeration contains messages, then displays the contents of the
messages:
if ( !msgs.hasMoreElements() ) {
System.out.println("No messages in queue");
} else {
while (msgs.hasMoreElements()) {
Message tempMsg = (Message)msgs.nextElement();
Java Message Service Examples 46-11
Writing Simple JMS Applications
System.out.println("Message: " + tempMsg);
}
}
6.
Catches and handles any exceptions. The end of the try-with-resources block
automatically causes the JMSContext to be closed.
Dumping the message contents to standard output retrieves the message body and
properties in a format that depends on the implementation of the toString method. In
GlassFish Server, the message format looks something like this:
Text:
This is message
Class:
getJMSMessageID():
getJMSTimestamp():
getJMSCorrelationID():
JMSReplyTo:
JMSDestination:
getJMSDeliveryMode():
getJMSRedelivered():
getJMSType():
getJMSExpiration():
getJMSPriority():
Properties:
3 from producer
com.sun.messaging.jmq.jmsclient.TextMessageImpl
ID:8-10.152.23.26(bf:27:4:e:e7:ec)-55645-1363100335526
1129061034355
null
null
PhysicalQueue
PERSISTENT
false
null
0
4
{JMSXDeliveryCount=0}
Instead of displaying the message contents this way, you can call some of the Message
interface's getter methods to retrieve the parts of the message you want to see.
For this example, you will use the connection factory and queue you created for
Receiving Messages Synchronously. It is assumed that you have already built and
packaged all the examples.
46.2.7.2 To Run the QueueBrowser Client
To run the MessageBrowser example using the appclient command, follow these
steps.
You also need the Producer example to send the message to the queue, and one of the
consumer clients to consume the messages after you inspect them.
To run the clients, you need two terminal windows.
1.
In a terminal window, go to the producer directory:
cd tut-install/examples/jms/simple/producer/
2.
Run the Producer client, sending one message to the queue, along with the
non-text control message:
appclient -client target/producer.jar queue
The output of the client looks like this (along with some additional output):
Destination type is queue
Sending message: This is message 1 from producer
Text messages sent: 1
3.
In another terminal window, go to the messagebrowser directory:
cd tut-install/jms/simple/messagebrowser
4.
Run the MessageBrowser client using the following command:
appclient -client target/messagebrowser.jar
46-12 The Java EE 7 Tutorial
Writing Simple JMS Applications
The output of the client looks something like this (along with some additional
output):
Message:
Text:
This is message
Class:
getJMSMessageID():
getJMSTimestamp():
getJMSCorrelationID():
JMSReplyTo:
JMSDestination:
getJMSDeliveryMode():
getJMSRedelivered():
getJMSType():
getJMSExpiration():
getJMSPriority():
Properties:
1 from producer
com.sun.messaging.jmq.jmsclient.TextMessageImpl
ID:9-10.152.23.26(bf:27:4:e:e7:ec)-55645-1363100335526
1363100335526
null
null
PhysicalQueue
PERSISTENT
false
null
0
4
{JMSXDeliveryCount=0}
Message:
Class:
getJMSMessageID():
getJMSTimestamp():
getJMSCorrelationID():
JMSReplyTo:
JMSDestination:
getJMSDeliveryMode():
getJMSRedelivered():
getJMSType():
getJMSExpiration():
getJMSPriority():
Properties:
com.sun.messaging.jmq.jmsclient.MessageImpl
ID:10-10.152.23.26(bf:27:4:e:e7:ec)-55645-1363100335526
1363100335526
null
null
PhysicalQueue
PERSISTENT
false
null
0
4
{JMSXDeliveryCount=0}
The first message is the TextMessage, and the second is the non-text control
message.
5.
Go to the synchconsumer directory.
6.
Run the SynchConsumer client to consume the messages:
appclient -client target/synchconsumer.jar queue
The output of the client looks like this (along with some additional output):
Destination type is queue
Reading message: This is message 1 from producer
Messages received: 1
46.2.8 Running Multiple Consumers on the Same Destination
To illustrate further the way point-to-point and publish/subscribe messaging works,
you can use the Producer and SynchConsumer examples to send messages that are then
consumed by two clients running simultaneously.
1.
Open three command windows. In one, go to the producer directory. In the other
two, go to the synchconsumer directory.
2.
In each of the synchconsumer windows, start running the client, receiving
messages from a queue:
appclient -client target/synchconsumer.jar queue
Java Message Service Examples 46-13
Writing Simple JMS Applications
Wait until you see the "Destination type is queue" message in both windows.
3.
In the producer window, run the client, sending 20 or so messages to the queue:
appclient -client target/producer.jar queue 20
4.
Look at the output in the synchconsumer windows. In point-to-point messaging,
each message can have only one consumer. Therefore, each of the clients receives
some of the messages. One of the clients receives the non-text control message,
reports the number of messages received, and exits.
5.
In the window of the client that did not receive the non-text control message, enter
Control-C to exit the program.
6.
Next, run the synchconsumer clients using a topic. In each window, run the
following command:
appclient -client target/synchconsumer.jar topic
Wait until you see the "Destination type is topic" message in both windows.
7.
In the producer window, run the client, sending 20 or so messages to the topic:
appclient -client target/producer.jar topic 20
8.
Again, look at the output in the synchconsumer windows. In publish/subscribe
messaging, a copy of every message is sent to each subscription on the topic.
Therefore, each of the clients receives all 20 text messages as well as the non-text
control message.
46.2.9 Acknowledging Messages
JMS provides two alternative ways for a consuming client to ensure that a message is
not acknowledged until the application has finished processing the message:
■
■
Using a synchronous consumer in a JMSContext that has been configured to use
the CLIENT_ACKNOWLEDGE setting
Using a message listener for asynchronous message delivery in a JMSContext that
has been configured to use the default AUTO_ACKNOWLEDGE setting
Note: In the Java EE platform, CLIENT_ACKNOWLEDGE sessions can be
used only in application clients, as in this example.
The clientackconsumer example demonstrates the first alternative, in which a
synchronous consumer uses client acknowledgment. The asynchconsumer example
described in Using a Message Listener for Asynchronous Message Delivery
demonstrates the second alternative.
For information about message acknowledgment, see Controlling Message
Acknowledgment.
The following table describes four possible interactions between types of consumers
and types of acknowledgment.
46-14 The Java EE 7 Tutorial
Writing Simple JMS Applications
Table 46–3 Message Acknowledgment with Synchronous and Asynchronous
Consumers
Consumer Type
Acknowledgment Type
Behavior
Synchronous
Client
Client acknowledges message after processing
is complete
Asynchronous
Client
Client acknowledges message after processing
is complete
Synchronous
Auto
Acknowledgment happens immediately after
receive call; message cannot be redelivered if
any subsequent processing steps fail
Asynchronous
Auto
Message is automatically acknowledged when
onMessage method returns
The example is under the tut-install/examples/jms/simple/clientackconsumer/
directory.
The example client, ClientAckConsumer.java, creates a JMSContext that specifies
client acknowledgment:
try (JMSContext context =
connectionFactory.createContext(JMSContext.CLIENT_ACKNOWLEDGE);) {
...
The client uses a while loop almost identical to that used by SynchConsumer.java,
with the exception that after processing each message, it calls the acknowledge method
on the JMSContext:
context.acknowledge();
The example uses the following objects:
■
■
The jms/MyQueue resource that you created for Receiving Messages
Synchronously.
java:comp/DefaultJMSConnectionFactory, the platform default connection
factory preconfigured with GlassFish Server
46.2.9.1 To Run the ClientAckConsumer Client
1.
In a terminal window, go to the following directory:
tut-install/examples/jms/simple/producer/
2.
Run the Producer client, sending some messages to the queue:
appclient -client target/producer.jar queue 3
3.
In another terminal window, go to the following directory:
tut-install/examples/jms/simple/clientackconsumer/
4.
To run the client, use the following command:
appclient -client target/clientackconsumer.jar
The client output looks like this (along with some additional output):
Created client-acknowledge JMSContext
Reading message: This is message 1 from producer
Acknowledging TextMessage
Java Message Service Examples 46-15
Writing More Advanced JMS Applications
Reading message: This is message 2 from producer
Acknowledging TextMessage
Reading message: This is message 3 from producer
Acknowledging TextMessage
Acknowledging non-text control message
The client acknowledges each message explicitly after processing it, just as a
JMSContext configured to use AUTO_ACKNOWLEDGE does automatically after a
MessageListener returns successfully from processing a message received
asynchronously.
46.3 Writing More Advanced JMS Applications
The following examples show how to use some of the more advanced features of the
JMS API: durable subscriptions and transactions.
46.3.1 Using Durable Subscriptions
The durablesubscriptionexample example shows how unshared durable
subscriptions work. It demonstrates that a durable subscription continues to exist and
accumulate messages even when there is no active consumer on it.
The example consists of two modules, a durableconsumer application that creates a
durable subscription and consumes messages, and an unsubscriber application that
enables you to unsubscribe from the durable subscription after you have finished
running the durableconsumer application.
For information on durable subscriptions, see Creating Durable Subscriptions.
The main client, DurableConsumer.java, is under the
tut-install/examples/jms/durablesubscriptionexample/durableconsumer/ directory.
The example uses a connection factory, jms/DurableConnectionFactory, that has a
client ID.
The DurableConsumer client creates a JMSContext using the connection factory. It then
stops the JMSContext, calls createDurableConsumer to create a durable subscription
and a consumer on the topic by specifying a subscription name, registers a message
listener, and starts the JMSContext again. The subscription is created only if it does not
already exist, so the example can be run repeatedly:
try (JMSContext context = durableConnectionFactory.createContext();) {
context.stop();
consumer = context.createDurableConsumer(topic, "MakeItLast");
listener = new TextListener();
consumer.setMessageListener(listener);
context.start();
...
To send messages to the topic, you run the producer client.
The unsubscriber example contains a very simple Unsubscriber client, which creates
a JMSContext on the same connection factory and then calls the unsubscribe method,
specifying the subscription name:
try (JMSContext context = durableConnectionFactory.createContext();) {
System.out.println("Unsubscribing from durable subscription");
context.unsubscribe("MakeItLast");
} ...
46-16 The Java EE 7 Tutorial
Writing More Advanced JMS Applications
46.3.1.1 To Create Resources for the Durable Subscription Example
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a command window, go to the durableconsumer example.
cd tut-install/jms/durablesubscriptionexample/durableconsumer
3.
Create the resources using the asadmin add-resources command:
asadmin add-resources src/main/setup/glassfish-resources.xml
The command output reports the creation of a connector connection pool and a
connector resource.
4.
Verify the creation of the resources:
asadmin list-jms-resources
In addition to the resources you created for the simple examples, the command
lists the new connection factory:
jms/MyQueue
jms/MyTopic
jms/__defaultConnectionFactory
jms/DurableConnectionFactory
Command list-jms-resources executed successfully.
46.3.1.2 To Run the Durable Subscription Example
1.
In a terminal window, go to the following directory:
tut-install/examples/jms/durablesubscriptionexample/
2.
Build the durableconsumer and unsubscriber examples:
mvn install
3.
Go to the durableconsumer directory:
cd durableconsumer
4.
To run the client, enter the following command:
appclient -client target/durableconsumer.jar
The client creates the durable consumer and then waits for messages:
Creating consumer for topic
Starting consumer
To end program, enter Q or q, then <return>
5.
In another terminal window, run the Producer client, sending some messages to
the topic:
cd tut-install/examples/jms/simple/producer
appclient -client target/producer.jar topic 3
6.
After the DurableConsumer client receives the messages, enter q or Q to exit the
program. At this point, the client has behaved like any other asynchronous
consumer.
7.
Now, while the DurableConsumer client is not running, use the Producer client to
send more messages:
Java Message Service Examples 46-17
Writing More Advanced JMS Applications
appclient -client target/producer.jar topic 2
If a durable subscription did not exist, these messages would be lost, because no
consumer on the topic is currently running. However, the durable subscription is
still active, and it retains the messages.
8.
Run the DurableConsumer client again. It immediately receives the messages that
were sent while it was inactive:
Creating consumer for topic
Starting consumer
To end program, enter Q or q, then <return>
Reading message: This is message 1 from producer
Reading message: This is message 2 from producer
Message is not a TextMessage
9.
Enter q or Q to exit the program.
46.3.1.3 To Run the unsubscriber Example
After you have finished running the DurableConsumer client, run the unsubscriber
example to unsubscribe from the durable subscription.
1.
In a terminal window, go to the following directory:
tut-install/examples/jms/durablesubscriptionexample/unsubscriber
2.
To run the Unsubscriber client, enter the following command:
appclient -client target/unsubscriber.jar
The client reports that it is unsubscribing from the durable subscription.
46.3.2 Using Local Transactions
The transactedexample example demonstrates the use of local transactions in a JMS
client application. It also demonstrates the use of the request/reply messaging pattern
described in Creating Temporary Destinations, although it uses permanent rather than
temporary destinations. The example consists of three modules, genericsupplier,
retailer, and vendor, which can be found under the
tut-install/examples/jms/transactedexample/ directory. The source code can be found
in the src/main/java/javaeetutorial trees for each module. The genericsupplier
and retailer modules each contain a single class,
genericsupplier/GenericSupplier.java and retailer/Retailer.java, respectively.
The vendor module is more complex, containing four classes: vendor/Vendor.java,
vendor/VendorMessageListener.java, vendor/Order.java, and
vendor/SampleUtilities.java.
The example shows how to use a queue and a topic in a single transaction as well as
how to pass a JMSContext to a message listener's constructor function. The example
represents a highly simplified e-commerce application in which the following actions
occur.
1.
A retailer (retailer/src/main/java/javaeetutorial/retailer/Retailer.java)
sends a MapMessage to a vendor order queue, ordering a quantity of computers,
and waits for the vendor's reply:
outMessage = context.createMapMessage();
outMessage.setString("Item", "Computer(s)");
outMessage.setInt("Quantity", quantity);
outMessage.setJMSReplyTo(retailerConfirmQueue);
46-18 The Java EE 7 Tutorial
Writing More Advanced JMS Applications
context.createProducer().send(vendorOrderQueue, outMessage);
System.out.println("Retailer: ordered " + quantity + " computer(s)");
orderConfirmReceiver = context.createConsumer(retailerConfirmQueue);
2.
The vendor (vendor/src/main/java/javaeetutorial/retailer/Vendor.java)
receives the retailer's order message and sends an order message to the supplier
order topic in one transaction. This JMS transaction uses a single session, so you
can combine a receive from a queue with a send to a topic. Here is the code that
uses the same session to create a consumer for a queue:
vendorOrderReceiver = session.createConsumer(vendorOrderQueue);
The following code receives the incoming message, sends an outgoing message,
and commits the JMSContext. The message processing has been removed to keep
the sequence simple:
inMessage = vendorOrderReceiver.receive();
// Process the incoming message and format the outgoing
// message
...
context.createProducer().send(supplierOrderTopic, orderMessage);
...
context.commit();
For simplicity, there are only two suppliers, one for CPUs and one for hard drives.
3.
Each supplier
(genericsupplier/src/main/java/javaeetutorial/retailer/GenericSupplier.
java) receives the order from the order topic, checks its inventory, and then sends
the items ordered to the queue named in the order message's JMSReplyTo field. If it
does not have enough of the item in stock, the supplier sends what it has. The
synchronous receive from the topic and the send to the queue take place in one
JMS transaction:
receiver = context.createConsumer(SupplierOrderTopic);
...
inMessage = receiver.receive();
if (inMessage instanceof MapMessage) {
orderMessage = (MapMessage) inMessage;
} ...
// Process message
outMessage = context.createMapMessage();
// Add content to message
context.createProducer().send(
(Queue) orderMessage.getJMSReplyTo(),
outMessage);
// Display message contents
context.commit();
4.
The vendor receives the suppliers' replies from its confirmation queue and
updates the state of the order. Messages are processed by an asynchronous
message listener, VendorMessageListener; this step shows the use of JMS
transactions with a message listener:
MapMessage component = (MapMessage) message;
...
int orderNumber = component.getInt("VendorOrderNumber");
Order order = Order.getOrder(orderNumber).processSubOrder(component);
context.commit();
Java Message Service Examples 46-19
Writing More Advanced JMS Applications
5.
When all outstanding replies are processed for a given order, the vendor message
listener sends a message notifying the retailer whether it can fulfill the order:
Queue replyQueue = (Queue) order.order.getJMSReplyTo();
MapMessage retailerConfirmMessage = context.createMapMessage();
// Format the message
context.createProducer().send(replyQueue, retailerConfirmMessage);
context.commit();
6.
The retailer receives the message from the vendor:
inMessage = (MapMessage) orderConfirmReceiver.receive();
The retailer then places a second order for twice as many computers as in the first
order, so these steps are executed twice.
Figure 46–1 illustrates these steps.
Figure 46–1 Transactions: JMS Client Example
Supplier
Order Topic
Vendor
OrderQ
1
2a
3
2b
Supplier 1
3
Retailer
Vendor
3
6
5
Retailer
ConfirmQ
4
3
Supplier N
Vendor
ConfirmQ
Message Send
Message Receive
Message Listen
All the messages use the MapMessage message type. Synchronous receives are used for
all message reception except when the vendor processes the replies of the suppliers.
These replies are processed asynchronously and demonstrate how to use transactions
within a message listener.
At random intervals, the Vendor client throws an exception to simulate a database
problem and cause a rollback.
All clients except Retailer use transacted contexts.
The example uses three queues named jms/AQueue, jms/BQueue, and jms/CQueue, and
one topic named jms/OTopic.
46.3.2.1 To Create Resources for the transactedexample Example
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a command window, go to the genericsupplier example:
cd tut-install/jms/transactedexample/genericsupplier
46-20 The Java EE 7 Tutorial
Writing More Advanced JMS Applications
3.
Create the resources using the asadmin add-resources command:
asadmin add-resources src/main/setup/glassfish-resources.xml
4.
Verify the creation of the resources:
asadmin list-jms-resources
In addition to the resources you created for the simple examples and the durable
subscription example, the command lists the four new destinations:
jms/MyQueue
jms/MyTopic
jms/AQueue
jms/BQueue
jms/CQueue
jms/OTopic
jms/__defaultConnectionFactory
jms/DurableConnectionFactory
Command list-jms-resources executed successfully.
46.3.2.2 To Run the transactedexample Clients
You will need four terminal windows to run the clients. Make sure that you start the
clients in the correct order.
1.
In a terminal window, go to the following directory:
tut-install/examples/jms/transactedexample/
2.
To build and package all the modules, enter the following command:
mvn install
3.
Go to the genericsupplier directory:
cd genericsupplier
4.
Use the following command to start the CPU supplier client:
appclient -client target\genericsupplier.jar CPU
After some initial output, the client reports the following:
Starting CPU supplier
5.
In a second terminal window, go to the genericsupplier directory:
cd tut-install/examples/jms/transactedexample/genericsupplier
6.
Use the following command to start the hard drive supplier client:
appclient -client target\genericsupplier.jar HD
After some initial output, the client reports the following:
Starting Hard Drive supplier
7.
In a third terminal window, go to the vendor directory:
cd tut-install/examples/jms/transactedexample/vendor
8.
Use the following command to start the Vendor client:
appclient -client target\vendor.jar
Java Message Service Examples 46-21
Writing More Advanced JMS Applications
After some initial output, the client reports the following:
Starting vendor
9.
In another terminal window, go to the retailer directory:
cd tut-install/examples/jms/transactedexample/retailer
10. Use a command like the following to run the Retailer client. The argument
specifies the number of computers to order:
appclient -client target/retailer.jar 4
After some initial output, the Retailer client reports something like the following.
In this case, the first order is filled, but the second is not:
Retailer:
Retailer:
Retailer:
Retailer:
Retailer:
Retailer:
Quantity to be ordered is 4
Ordered 4 computer(s)
Order filled
Placing another order
Ordered 8 computer(s)
Order not filled
The Vendor client reports something like the following, stating in this case that it is
able to send all the computers in the first order, but not in the second:
Vendor: Retailer ordered 4 Computer(s)
Vendor: Ordered 4 CPU(s) and hard drive(s)
Vendor: Committed transaction 1
Vendor: Completed processing for order 1
Vendor: Sent 4 computer(s)
Vendor: committed transaction 2
Vendor: Retailer ordered 8 Computer(s)
Vendor: Ordered 8 CPU(s) and hard drive(s)
Vendor: Committed transaction 1
Vendor: Completed processing for order 2
Vendor: Unable to send 8 computer(s)
Vendor: Committed transaction 2
The CPU supplier reports something like the following. In this case, it is able to
send all the CPUs for both orders:
CPU Supplier: Vendor ordered 4 CPU(s)
CPU Supplier: Sent 4 CPU(s)
CPU Supplier: Committed transaction
CPU Supplier: Vendor ordered 8 CPU(s)
CPU Supplier: Sent 8 CPU(s)
CPU Supplier: Committed transaction
The hard drive supplier reports something like the following. In this case, it has a
shortage of hard drives for the second order:
Hard Drive Supplier: Vendor ordered 4 Hard Drive(s)
Hard Drive Supplier: Sent 4 Hard Drive(s)
Hard Drive Supplier: Committed transaction
Hard Drive Supplier: Vendor ordered 8 Hard Drive(s)
Hard Drive Supplier: Sent 1 Hard Drive(s)
Hard Drive Supplier: Committed transaction
11. Repeat steps 4 through 10 as many times as you wish. Occasionally, the vendor
will report an exception that causes a rollback:
46-22 The Java EE 7 Tutorial
Writing High Performance and Scalable JMS Applications
Vendor: JMSException occurred: javax.jms.JMSException: Simulated
database concurrent access exception
Vendor: Rolled back transaction 1
12. After you finish running the clients, you can delete the destination resources by
using the following commands:
asadmin
asadmin
asadmin
asadmin
delete-jms-resource
delete-jms-resource
delete-jms-resource
delete-jms-resource
jms/AQueue
jms/BQueue
jms/CQueue
jms/OTopic
46.4 Writing High Performance and Scalable JMS Applications
This section describes how to use the JMS API to write applications that can handle
high volumes of messages robustly. These examples use both nondurable and durable
shared consumers.
46.4.1 Using Shared Nondurable Subscriptions
This section describes the receiving clients in an example that shows how to use a
shared consumer to distribute messages sent to a topic among different consumers.
This section then explains how to compile and run the clients using GlassFish Server.
You may wish to compare this example to the results of Running Multiple Consumers
on the Same Destination using an unshared consumer. In that example, messages are
distributed among the consumers on a queue, but each consumer on the topic receives
all the messages because each consumer on the topic is using a separate topic
subscription.
In this example, however, messages are distributed among multiple consumers on a
topic, because all the consumers are sharing the same subscription. Each message
added to the topic subscription is received by only one consumer, similarly to the way
in which each message added to a queue is received by only one consumer.
A topic may have multiple subscriptions. Each message sent to the topic will be added
to each topic subscription. However, if there are multiple consumers on a particular
subscription, each message added to that subscription will be delivered to only one of
those consumers.
46.4.1.1 Writing the Clients for the Shared Consumer Example
The sending client is Producer.java, the same client used in previous examples.
The receiving client is SharedConsumer.java. It is very similar to
AsynchConsumer.java, except that it always uses a topic. It performs the following
steps.
1.
Injects resources for a connection factory and topic.
2.
In a try-with-resources block, creates a JMSContext.
3.
Creates a consumer on a shared nondurable subscription, specifying a
subscription name:
consumer = context.createSharedConsumer(topic, "SubName");
4.
Creates an instance of the TextListener class and registers it as the message
listener for the shared consumer.
Java Message Service Examples 46-23
Writing High Performance and Scalable JMS Applications
5.
Listens for the messages published to the destination, stopping when the user
types the character q or Q.
6.
Catches and handles any exceptions. The end of the try-with-resources block
automatically causes the JMSContext to be closed.
The TextListener.java class is identical to the one for the asynchconsumer example.
For this example, you will use the default connection factory and the topic you created
in To Create Resources for the Simple Examples.
46.4.1.2 To Run the SharedConsumer and Producer Clients
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
Open three command windows. In the first, go to the simple/producer/ directory:
cd tut-install/examples/jms/simple/producer/
3.
In the second and third command windows, go to the shared/sharedconsumer/
directory:
cd tut-install/examples/jms/shared/sharedconsumer/
4.
In one of the sharedconsumer windows, build the example:
mvn install
5.
In each of the two sharedconsumer windows, start running the client. You do not
need to specify a topic argument:
appclient -client target/sharedconsumer.jar
Wait until you see the following output in both windows:
Waiting for messages on topic
To end program, enter Q or q, then <return>
6.
In the producer window, run the client, specifying the topic and a number of
messages:
appclient -client target/producer.jar topic 20
Each consumer client receives some of the messages. Only one of the clients
receives the non-text message that signals the end of the message stream.
7.
Enter Q or q and press Return to stop each client and see a report of the number of
text messages received.
46.4.2 Using Shared Durable Subscriptions
The shareddurableconsumer client shows how to use shared durable subscriptions. It
shows how shared durable subscriptions combine the advantages of durable
subscriptions (the subscription remains active when the client is not) with those of
shared consumers (the message load can be divided among multiple clients).
The example is much more similar to the sharedconsumer example than to the
DurableConsumer.java client. It uses two classes, SharedDurableConsumer.java and
TextListener.java, which can be found under the
tut-install/examples/jms/shared/shareddurableconsumer/ directory.
46-24 The Java EE 7 Tutorial
Writing High Performance and Scalable JMS Applications
The client uses java:comp/DefaultJMSConnectionFactory, the connection factory that
does not have a client identifier, as is recommended for shared durable subscriptions.
It uses the createSharedDurableConsumer method with a subscription name to
establish the subscription:
consumer = context.createSharedDurableConsumer(topic, "MakeItLast");
You run the example in combination with the Producer.java client.
46.4.2.1 To Run the SharedDurableConsumer and Producer Clients
1.
In a terminal window, go to the following directory:
tut-install/examples/jms/shared/shareddurableconsumer
2.
To compile and package the client, enter the following command:
mvn install
3.
Run the client first to establish the durable subscription:
appclient -client target/shareddurableconsumer.jar
4.
The client displays the following and pauses:
Waiting for messages on topic
To end program, enter Q or q, then <return>
5.
In the shareddurableconsumer window, enter q or Q to exit the program. The
subscription remains active, although the client is not running.
6.
Open another terminal window and go to the producer example directory:
cd tut-install/examples/jms/simple/producer
7.
Run the producer example, sending a number of messages to the topic:
appclient -client target/producer.jar topic 6
8.
After the producer has sent the messages, open a third terminal window and go to
the shareddurableconsumer directory.
9.
Run the client in both the first and third terminal windows. Whichever client starts
first will receive all the messages that were sent when there was no active
subscriber:
appclient -client target/shareddurableconsumer.jar
10. With both shareddurableconsumer clients still running, go to the producer
window and send a larger number of messages to the topic:
appclient -client target/producer.jar topic 25
Now the messages will be shared by the two consumer clients. If you continue
sending groups of messages to the topic, each client receives some of the messages.
If you exit one of the clients and send more messages, the other client will receive
all the messages.
Java Message Service Examples 46-25
Sending and Receiving Messages Using a Simple Web Application
46.5 Sending and Receiving Messages Using a Simple Web Application
Web applications can use the JMS API to send and receive messages, as noted in Using
Java EE Components to Produce and to Synchronously Receive Messages. This section
describes the components of a very simple web application that uses the JMS API.
This section assumes that you are familiar with the basics of JavaServer Faces
technology, described in Part III, "The Web Tier."
The example, websimplemessage, is under the tut-install/jms/examples/ directory. It
uses sending and receiving Facelets pages as well as corresponding backing beans.
When a user enters a message in the text field of the sending page and clicks a button,
the backing bean for the page sends the message to a queue and displays it on the
page. When the user goes to the receiving page and clicks another button, the backing
bean for that page receives the message synchronously and displays it.
Figure 46–2 The websimplemessage Application
Java EE Server
Msg
Web Container
sender.xhtml
SenderBean
Sends
Queue
Browser
receiver.xhtml
ReceiverBean
Delivers
Msg
46.5.1 The websimplemessage Facelets Pages
The Facelets pages for the example are as follows.
■
■
sender.xhtml, which provides a labeled h:InputText tag where the user enters
the message, along with two command buttons. When the user clicks the Send
Message button, the senderBean.sendMessage method is called to send the
message to the queue and display its contents. When the user clicks the Go to
Receive Page button, the receiver.xhtml page appears.
receiver.xhtml, which also provides two command buttons. When the user clicks
the Receive Message button, the receiverBean.getMessage method is called to
fetch the message from the queue and display its contents. When the user clicks
the Send Another Message button, the sender.xhtml page appears again.
46.5.2 The websimplemessage Managed Beans
The two managed beans for the example are as follows.
■
SenderBean.java, a CDI managed bean with one property, messageText, and one
business method, sendMessage. The class is annotated with
@JMSDestinationDefinition to create a component-private queue:
@JMSDestinationDefinition(
name = "java:comp/jms/webappQueue",
interfaceName = "javax.jms.Queue",
46-26 The Java EE 7 Tutorial
Sending and Receiving Messages Using a Simple Web Application
destinationName = "PhysicalWebappQueue")
@Named
@RequestScoped
public class SenderBean {
The sendMessage method injects a JMSContext (using the default connection
factory) and the queue, creates a producer, sends the message the user typed on
the Facelets page, and creates a FacesMessage to display on the Facelets page:
@Inject
private JMSContext context;
@Resource(lookup = "java:comp/jms/webappQueue")
private Queue queue;
private String messageText;
...
public void sendMessage() {
try {
String text = "Message from producer: " + messageText;
context.createProducer().send(queue, text);
FacesMessage facesMessage =
new FacesMessage("Sent message: " + text);
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
} catch (Throwable t) {
logger.log(Level.SEVERE,
"SenderBean.sendMessage: Exception: {0}",
t.toString());
}
}
■
ReceiverBean.java, a CDI managed bean with one business method, getMessage.
The method injects a JMSContext (using the default connection factory) and the
queue that was defined in SenderBean, creates a consumer, receives the message,
and creates a FacesMessage to display on the Facelets page:
@Inject
private JMSContext context;
@Resource(lookup = "java:comp/jms/webappQueue")
private Queue queue;
...
public void getMessage() {
try {
JMSConsumer receiver = context.createConsumer(queue);
String text = receiver.receiveBody(String.class);
if (text != null) {
FacesMessage facesMessage =
new FacesMessage("Reading message: " + text);
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
} else {
FacesMessage facesMessage =
new FacesMessage("No message received after 1 second");
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
}
} catch (Throwable t) {
logger.log(Level.SEVERE,
"ReceiverBean.getMessage: Exception: {0}",
t.toString());
}
}
Java Message Service Examples 46-27
Sending and Receiving Messages Using a Simple Web Application
46.5.3 Running the websimplemessage Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
websimplemessage application.
46.5.3.1 Creating Resources for the websimplemessage Example
This example uses an annotation-defined queue and the preconfigured default
connection factory java:comp/DefaultJMSConnectionFactory.
46.5.3.2 To Package and Deploy websimplemessage Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/jms
4.
Select the websimplemessage folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the websimplemessage project and select Build.
This command builds and deploys the project.
46.5.3.3 To Package and Deploy websimplemessage Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/jms/websimplemessage/
3.
To compile the source files and package and deploy the application, use the
following command:
mvn install
46.5.3.4 To Run the websimplemessage Example
1.
In a web browser, enter the following URL:
http://localhost:8080/websimplemessage
2.
Enter a message in the text field and click Send Message.
If, for example, you enter "Hello, Duke", the following appears below the buttons:
Sent message: Message from producer: Hello, Duke
3.
Click Go to Receive Page.
4.
Click Receive Message.
The following appears below the buttons:
Reading message: Message from producer: Hello, Duke
5.
Click Send Another Message to return to the sending page.
46-28 The Java EE 7 Tutorial
Receiving Messages Asynchronously Using a Message-Driven Bean
6.
After you have finished running the application, undeploy it using either the
Services tab of NetBeans IDE or the mvn cargo:undeploy command.
46.6 Receiving Messages Asynchronously Using a Message-Driven Bean
If you are writing an application to run in the Java EE application client container or
on the Java SE platform, and you want to receive messages asynchronously, you need
to define a class that implements the MessageListener interface, create a JMSConsumer,
and call the method setMessageListener.
If you're writing an application to run in the Java EE web or EJB container and want it
to receive messages asynchronously, you also need to need to define a class that
implements the MessageListener interface. However, instead of creating a
JMSConsumer and calling the method setMessageListener, you must configure your
message listener class to be a message-driven bean. The application server will then
take care of the rest.
Message-driven beans can implement any messaging type. Most commonly, however,
they implement the Java Message Service (JMS) technology.
This section describes a simple message-driven bean example. Before proceeding, you
should read the basic conceptual information in the section What Is a Message-Driven
Bean? as well as Using Message-Driven Beans to Receive Messages Asynchronously.
46.6.1 Overview of the simplemessage Example
The simplemessage application has the following components:
■
■
SimpleMessageClient: An application client that sends several messages to a
queue
SimpleMessageBean: A message-driven bean that asynchronously processes the
messages that are sent to the queue
Figure 46–3 illustrates the structure of this application. The application client sends
messages to the queue, which was created administratively using the Administration
Console. The JMS provider (in this case, GlassFish Server) delivers the messages to the
instances of the message-driven bean, which then processes the messages.
Figure 46–3 The simplemessage Application
Msg
Msg
Application
Client
Java EE Server
EJB Container
Delivers
Sends
MDB Instances
Queue
The source code for this application is in the tut-install/examples/jms/simplemessage/
directory.
Java Message Service Examples 46-29
Receiving Messages Asynchronously Using a Message-Driven Bean
46.6.2 The simplemessage Application Client
The SimpleMessageClient sends messages to the queue that the SimpleMessageBean
listens to. The client starts by injecting the connection factory and queue resources:
@Resource(lookup = "java:comp/DefaultJMSConnectionFactory")
private static ConnectionFactory connectionFactory;
@Resource(lookup = "jms/MyQueue")
private static Queue queue;
Next, the client creates the JMSContext in a try-with-resources block:
String text;
final int NUM_MSGS = 3;
try (JMSContext context = connectionFactory.createContext();) {
Finally, the client sends several text messages to the queue:
for (int i = 0; i < NUM_MSGS; i++) {
text = "This is message " + (i + 1);
System.out.println("Sending message: " + text);
context.createProducer().send(queue, text);
}
46.6.3 The simplemessage Message-Driven Bean Class
The code for the SimpleMessageBean class illustrates the requirements of a
message-driven bean class described in Using Message-Driven Beans to Receive
Messages Asynchronously.
The first few lines of the SimpleMessageBean class use the @MessageDriven
annotation's activationConfig attribute to specify configuration properties:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup",
propertyValue = "jms/MyQueue"),
@ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Queue")
})
See Table 45–3 for a list of the available properties.
See Sending Messages from a Session Bean to an MDB for examples of the
subscriptionDurability, clientId, subscriptionName, and messageSelector
properties.
46.6.3.1 The onMessage Method
When the queue receives a message, the EJB container invokes the message listener
method or methods. For a bean that uses JMS, this is the onMessage method of the
MessageListener interface.
In the SimpleMessageBean class, the onMessage method casts the incoming message to
a TextMessage and displays the text:
public void onMessage(Message inMessage) {
try {
if (inMessage instanceof TextMessage) {
logger.log(Level.INFO,
"MESSAGE BEAN: Message received: {0}",
46-30 The Java EE 7 Tutorial
Receiving Messages Asynchronously Using a Message-Driven Bean
inMessage.getBody(String.class));
} else {
logger.log(Level.WARNING,
"Message of wrong type: {0}",
inMessage.getClass().getName());
}
} catch (JMSException e) {
logger.log(Level.SEVERE,
"SimpleMessageBean.onMessage: JMSException: {0}",
e.toString());
mdc.setRollbackOnly();
}
}
46.6.4 Running the simplemessage Example
You can use either NetBeans IDE or Maven to build, deploy, and run the
simplemessage example.
46.6.4.1 Creating Resources for the simplemessage Example
This example uses the queue named jms/MyQueue and the preconfigured default
connection factory java:comp/DefaultJMSConnectionFactory.
If you have run the simple JMS examples in Writing Simple JMS Applications and
have not deleted the resources, you already have the queue. Otherwise, follow the
instructions in To Create Resources for the Simple Examples to create it.
For more information on creating JMS resources, see Creating JMS Administered
Objects.
46.6.4.2 To Run the simplemessage Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/jms/simplemessage
4.
Select the simplemessage folder.
5.
Make sure that the Open Required Projects check box is selected, then click Open
Project.
6.
In the Projects tab, right-click the simplemessage project and select Build. (If
NetBeans IDE suggests that you run a priming build, click the box to do so.)
This command packages the application client and the message-driven bean, then
creates a file named simplemessage.ear in the simplemessage-ear/target/
directory. It then deploys the simplemessage-ear module, retrieves the client
stubs, and runs the application client.
The output in the output window looks like this (preceded by application client
container output):
Sending message: This is message 1
Sending message: This is message 2
Sending message: This is message 3
To see if the bean received the messages,
check <install_dir>/domains/domain1/logs/server.log.
Java Message Service Examples 46-31
Sending Messages from a Session Bean to an MDB
In the server log file, lines similar to the following appear:
MESSAGE BEAN: Message received: This is message 1
MESSAGE BEAN: Message received: This is message 2
MESSAGE BEAN: Message received: This is message 3
The received messages may appear in a different order from the order in which
they were sent.
7.
After you have finished running the application, undeploy it using the Services
tab.
46.6.4.3 To Run the simplemessage Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/jms/simplemessage/
3.
To compile the source files and package the application, use the following
command:
mvn install
This target packages the application client and the message-driven bean, then
creates a file named simplemessage.ear in the simplemessage-ear/target/
directory. It then deploys the simplemessage-ear module, retrieves the client
stubs, and runs the application client.
The output in the terminal window looks like this (preceded by application client
container output):
Sending message: This is message 1
Sending message: This is message 2
Sending message: This is message 3
To see if the bean received the messages,
check <install_dir>/domains/domain1/logs/server.log.
In the server log file, lines similar to the following appear:
MESSAGE BEAN: Message received: This is message 1
MESSAGE BEAN: Message received: This is message 2
MESSAGE BEAN: Message received: This is message 3
The received messages may appear in a different order from the order in which
they were sent.
4.
After you have finished running the application, undeploy it using the mvn
cargo:undeploy command.
46.7 Sending Messages from a Session Bean to an MDB
This section explains how to write, compile, package, deploy, and run an application
that uses the JMS API in conjunction with a session bean. The application contains the
following components:
■
An application client that invokes a session bean
■
A session bean that publishes several messages to a topic
46-32 The Java EE 7 Tutorial
Sending Messages from a Session Bean to an MDB
■
A message-driven bean that receives and processes the messages using a durable
topic subscription and a message selector
You will find the source files for this section in the
tut-install/examples/jms/clientsessionmdb/ directory. Path names in this section are
relative to this directory.
46.7.1 Writing the Application Components for the clientsessionmdb Example
This application demonstrates how to send messages from an enterprise bean (in this
case, a session bean) rather than from an application client, as in the example in
Receiving Messages Asynchronously Using a Message-Driven Bean. Figure 46–4
illustrates the structure of this application. Sending messages from an enterprise bean
is very similar to sending messages from a managed bean, which was shown in
Sending and Receiving Messages Using a Simple Web Application.
Figure 46–4 An Enterprise Bean Application: Client to Session Bean to Message-Driven
Bean
Java EE Server
EJB Container
EJB Container
Session Bean
MDB Instance
Calls
Msg
Application
Client
Publishes
Msg
Topic
Delivers
The Publisher enterprise bean in this example is the enterprise-application equivalent
of a wire-service news feed that categorizes news events into six news categories. The
message-driven bean could represent a newsroom, where the sports desk, for example,
would set up a subscription for all news events pertaining to sports.
The application client in the example injects the Publisher enterprise bean's remote
home interface and then calls the bean's business method. The enterprise bean creates
18 text messages. For each message, it sets a String property randomly to one of six
values representing the news categories and then publishes the message to a topic. The
message-driven bean uses a message selector for the property to limit which of the
published messages will be delivered to it.
46.7.1.1 Coding the Application Client: MyAppClient.java
The application client, MyAppClient.java, found under
clientsessionmdb-app-client, performs no JMS API operations and so is simpler
than the client in Receiving Messages Asynchronously Using a Message-Driven Bean.
The client uses dependency injection to obtain the Publisher enterprise bean's business
interface:
@EJB(name="PublisherRemote")
Java Message Service Examples 46-33
Sending Messages from a Session Bean to an MDB
private static PublisherRemote publisher;
The client then calls the bean's business method twice.
46.7.1.2 Coding the Publisher Session Bean
The Publisher bean is a stateless session bean that has one business method. The
Publisher bean uses a remote interface rather than a local interface because it is
accessed from the application client.
The remote interface, PublisherRemote.java, found under clientsessionmdb-ejb,
declares a single business method, publishNews.
The bean class, PublisherBean.java, also found under clientsessionmdb-ejb,
implements the publishNews method and its helper method chooseType. The bean
class injects SessionContext and Topic resources (the topic is defined in the
message-driven bean). It then injects a JMSContext, which uses the preconfigured
default connection factory unless you specify otherwise. The bean class begins as
follows:
@Stateless
@Remote({
PublisherRemote.class
})
public class PublisherBean implements PublisherRemote {
@Resource
private SessionContext sc;
@Resource(lookup = "java:module/jms/newsTopic")
private Topic topic;
@Inject
private JMSContext context;
...
The business method publishNews creates a JMSProducer and publishes the messages.
46.7.1.3 Coding the Message-Driven Bean: MessageBean.java
The message-driven bean class, MessageBean.java, found under
clientsessionmdb-ejb, is almost identical to the one in Receiving Messages
Asynchronously Using a Message-Driven Bean. However, the @MessageDriven
annotation is different, because instead of a queue, the bean is using a topic, a durable
subscription, and a message selector. The bean defines a topic for the use of the
application; the definition uses the java:module scope because both the session bean
and the message-driven bean are in the same module. Because the destination is
defined in the message-driven bean, the @MessageDriven annotation uses the
destinationLookup activation config property. (See Creating Resources for Java EE
Applications for more information.) The annotation also sets the activation config
properties messageSelector, subscriptionDurability, clientId, and
subscriptionName, as follows:
@JMSDestinationDefinition(
name = "java:module/jms/newsTopic",
interfaceName = "javax.jms.Topic",
destinationName = "PhysicalNewsTopic")
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup",
propertyValue = "java:module/jms/newsTopic"),
@ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Topic"),
46-34 The Java EE 7 Tutorial
Sending Messages from a Session Bean to an MDB
@ActivationConfigProperty(propertyName = "messageSelector",
propertyValue = "NewsType = 'Sports' OR NewsType = 'Opinion'"),
@ActivationConfigProperty(propertyName = "subscriptionDurability",
propertyValue = "Durable"),
@ActivationConfigProperty(propertyName = "clientId",
propertyValue = "MyID"),
@ActivationConfigProperty(propertyName = "subscriptionName",
propertyValue = "MySub")
})
The topic is the one defined in the PublisherBean. The message selector in this case
represents both the sports and opinion desks, just to demonstrate the syntax of
message selectors.
The JMS resource adapter uses these properties to create a connection factory for the
message-driven bean that allows the bean to use a durable subscription.
46.7.2 Running the clientsessionmdb Example
You can use either NetBeans IDE or Maven to build, deploy, and run the
simplemessage example.
This example uses an annotation-defined topic and the preconfigured default
connection factory java:comp/DefaultJMSConnectionFactory, so you do not have to
create resources for it.
46.7.2.1 To Run clientsessionmdb Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/jms/clientsessionmdb
4.
Select the clientsessionmdb folder.
5.
Make sure that the Open Required Projects check box is selected, then click Open
Project.
6.
In the Projects tab, right-click the clientsessionmdb project and select Build. (If
NetBeans IDE suggests that you run a priming build, click the box to do so.)
This command creates the following:
■
■
■
An application client JAR file that contains the client class file and the session
bean's remote interface, along with a manifest file that specifies the main class
and places the EJB JAR file in its classpath
An EJB JAR file that contains both the session bean and the message-driven
bean
An application EAR file that contains the two JAR files
The clientsessionmdb.ear file is created in the clientsessionmdb-ear/target/
directory.
The command then deploys the EAR file, retrieves the client stubs, and runs the
client.
The client displays these lines:
Java Message Service Examples 46-35
Using an Entity to Join Messages from Two MDBs
To view the bean output,
check <install_dir>/domains/domain1/logs/server.log.
The output from the enterprise beans appears in the server log file. The Publisher
session bean sends two sets of 18 messages numbered 0 through 17. Because of the
message selector, the message-driven bean receives only the messages whose
NewsType property is Sports or Opinion.
7.
Use the Services tab to undeploy the application after you have finished running
it.
46.7.2.2 To Run clientsessionmdb Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
Go to the following directory:
tut-install/examples/jms/clientsessionmdb/
3.
To compile the source files and package, deploy, and run the application, enter the
following command:
mvn install
This command creates the following:
■
■
■
An application client JAR file that contains the client class file and the session
bean's remote interface, along with a manifest file that specifies the main class
and places the EJB JAR file in its classpath
An EJB JAR file that contains both the session bean and the message-driven
bean
An application EAR file that contains the two JAR files
The clientsessionmdb.ear file is created in the clientsessionmdb-ear/target/
directory.
The command then deploys the EAR file, retrieves the client stubs, and runs the
client.
The client displays these lines:
To view the bean output,
check <install_dir>/domains/domain1/logs/server.log.
The output from the enterprise beans appears in the server log file. The Publisher
session bean sends two sets of 18 messages numbered 0 through 17. Because of the
message selector, the message-driven bean receives only the messages whose
NewsType property is Sports or Opinion.
4.
Undeploy the application after you have finished running it:
mvn cargo:undeploy
46.8 Using an Entity to Join Messages from Two MDBs
This section explains how to write, compile, package, deploy, and run an application
that uses the JMS API with an entity. The application uses the following components:
■
An application client that both sends and receives messages
■
Two message-driven beans
46-36 The Java EE 7 Tutorial
Using an Entity to Join Messages from Two MDBs
■
An entity class
You will find the source files for this section in the
tut-install/examples/jms/clientmdbentity/ directory. Path names in this section are
relative to this directory.
46.8.1 Overview of the clientmdbentity Example Application
This application simulates, in a simplified way, the work flow of a company's human
resources (HR) department when it processes a new hire. This application also
demonstrates how to use the Java EE platform to accomplish a task that many JMS
applications need to perform.
A messaging client must often wait for several messages from various sources. It then
uses the information in all these messages to assemble a message that it then sends to
another destination. The common term for this design pattern (which is not specific to
JMS) is joining messages. Such a task must be transactional, with all the receives and
the send as a single transaction. If not all the messages are received successfully, the
transaction can be rolled back. For an application client example that illustrates this
task, see Using Local Transactions.
A message-driven bean can process only one message at a time in a transaction. To
provide the ability to join messages, an application can have the message-driven bean
store the interim information in a Java Persistence API entity. The entity can then
determine whether all the information has been received; when it has, the entity can
report this back to one of the message-driven beans, which then creates and sends the
message to the other destination. After it has completed its task, the entity can be
removed.
The basic steps of the application are as follows.
1.
The HR department's application client generates an employee ID for each new
hire and then publishes a message (M1) containing the new hire's name, employee
ID, and position. It publishes the message to a topic because the message needs to
be consumed by two message-driven beans. The client then creates a temporary
queue, ReplyQueue, with a message listener that waits for a reply to the message.
(See Creating Temporary Destinations for more information.)
2.
Two message-driven beans process each message: One bean, OfficeMDB, assigns
the new hire's office number, and the other bean, EquipmentMDB, assigns the new
hire's equipment. The first bean to process the message creates and persists an
entity named SetupOffice, then calls a business method of the entity to store the
information it has generated. The second bean locates the existing entity and calls
another business method to add its information.
3.
When both the office and the equipment have been assigned, the entity business
method returns a value of true to the message-driven bean that called the method.
The message-driven bean then sends to the reply queue a message (M2) describing
the assignments. Then it removes the entity. The application client's message
listener retrieves the information.
Figure 46–5 illustrates the structure of this application. Of course, an actual HR
application would have more components; other beans could set up payroll and
benefits records, schedule orientation, and so on.
Figure 46–5 assumes that OfficeMDB is the first message-driven bean to consume the
message from the client. OfficeMDB then creates and persists the SetupOffice entity
and stores the office information. EquipmentMDB then finds the entity, stores the
equipment information, and learns that the entity has completed its work.
EquipmentMDB then sends the message to the reply queue and removes the entity.
Java Message Service Examples 46-37
Using an Entity to Join Messages from Two MDBs
Figure 46–5 An Enterprise Bean Application: Client to Message-Driven Beans to Entity
Java EE Server
HR Client
M1
M1
OfficeMDB
M1
EquipmentMDB
Creates and Persists
Finds
SetupOffice Entity
New Hire Topic
M2
M2
Reply Queue
Message Passing
Method Invocation
46.8.2 Writing the Application Components for the clientmdbentity Example
Writing the components of the application involves coding the application client, the
message-driven beans, and the entity class.
46.8.2.1 Coding the Application Client: HumanResourceClient.java
The application client, HumanResourceClient.java, found under
clientmdbentity-app-client, performs the following steps:
1.
Defines a topic for the application, using the java:app namespace because the
topic is used in both the application client and the EJB module
2.
Injects ConnectionFactory and Topic resources
3.
Creates a TemporaryQueue to receive notification of processing that occurs, based
on new-hire events it has published
4.
Creates a JMSConsumer for the TemporaryQueue, sets the JMSConsumer's message
listener, and starts the connection
5.
Creates a MapMessage
6.
Creates five new employees with randomly generated names, positions, and ID
numbers (in sequence) and publishes five messages containing this information
The message listener, HRListener, waits for messages that contain the assigned office
and equipment for each employee. When a message arrives, the message listener
displays the information received and determines whether all five messages have
arrived. When they have, the message listener notifies the main method, which then
exits.
46.8.2.2 Coding the Message-Driven Beans for the clientmdbentity Example
This example uses two message-driven beans, both under clientmdbentity-ejb:
■
EquipmentMDB.java
■
OfficeMDB.java
The beans take the following steps.
46-38 The Java EE 7 Tutorial
Using an Entity to Join Messages from Two MDBs
1.
They inject a MessageDrivenContext resource, an EntityManager, and a
JMSContext.
2.
The onMessage method retrieves the information in the message. The
EquipmentMDB's onMessage method chooses equipment, based on the new hire's
position; the OfficeMDB's onMessage method randomly generates an office number.
3.
After a slight delay to simulate real world processing hitches, the onMessage
method calls a helper method, compose.
4.
The compose method takes the following steps.
a.
It either creates and persists the SetupOffice entity or finds it by primary key.
b.
It uses the entity to store the equipment or the office information in the
database, calling either the doEquipmentList or the doOfficeNumber business
method.
c.
If the business method returns true, meaning that all of the information has
been stored, it retrieves the reply destination information from the message,
creates a JMSProducer, and sends a reply message that contains the
information stored in the entity.
d.
It removes the entity.
46.8.2.3 Coding the Entity Class for the clientmdbentity Example
The SetupOffice.java class, also under clientmdbentity-ejb, is an entity class. The
entity and the message-driven beans are packaged together in an EJB JAR file. The
entity class is declared as follows:
@Entity
public class SetupOffice implements Serializable {
The class contains a no-argument constructor and a constructor that takes two
arguments, the employee ID and name. It also contains getter and setter methods for
the employee ID, name, office number, and equipment list. The getter method for the
employee ID has the @Id annotation to indicate that this field is the primary key:
@Id
public String getEmployeeId() {
return id;
}
The class also implements the two business methods, doEquipmentList and
doOfficeNumber, and their helper method, checkIfSetupComplete.
The message-driven beans call the business methods and the getter methods.
The persistence.xml file for the entity specifies the most basic settings:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="clientmdbentity-ejbPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:comp/DefaultDataSource</jta-data-source>
<properties>
<property name="eclipselink.ddl-generation"
value="drop-and-create-tables"/>
Java Message Service Examples 46-39
Using an Entity to Join Messages from Two MDBs
</properties>
</persistence-unit>
</persistence>
46.8.3 Running the clientmdbentity Example
You can use either NetBeans IDE or Maven to build, deploy, and run the
clientmdbentity example.
Because the example defines its own application-private topic and uses the
preconfigured default connection factory java:comp/DefaultJMSConnectionFactory
and the preconfigured default JDBC resource java:comp/DefaultDataSource, you do
not need to create resources for it.
46.8.3.1 To Run clientmdbentity Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server), as well as the database server (see Starting and Stopping the
Java DB Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/jms/clientmdbentity
4.
Select the clientmdbentity folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the clientmdbentity project and select Build.
This command creates the following:
■
■
■
An application client JAR file that contains the client class and listener class
files, along with a manifest file that specifies the main class
An EJB JAR file that contains the message-driven beans and the entity class,
along with the persistence.xml file
An application EAR file that contains the two JAR files along with an
application.xml file
The clientmdbentity.ear file is created in the clientmdbentity-ear/target/
directory.
The command then deploys the EAR file, retrieves the client stubs, and runs the
application client.
46.8.3.2 To Run clientmdbentity Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server), as well as the database server (see Starting and Stopping the
Java DB Server).
2.
Go to the following directory:
tut-install/examples/jms/clientmdbentity/
3.
To compile the source files and package, deploy, and run the application, enter the
following command:
mvn install
46-40 The Java EE 7 Tutorial
Using an Entity to Join Messages from Two MDBs
This command creates the following:
■
■
■
An application client JAR file that contains the client class and listener class
files, along with a manifest file that specifies the main class
An EJB JAR file that contains the message-driven beans and the entity class,
along with the persistence.xml file
An application EAR file that contains the two JAR files along with an
application.xml file
The command then deploys the application, retrieves the client stubs, and runs the
application client.
46.8.3.3 Viewing the Application Output
The output in the NetBeans IDE output window or in the terminal window looks
something like this (preceded by application client container output and Maven
output):
SENDER: Setting hire ID to 50,
SENDER: Setting hire ID to 51,
SENDER: Setting hire ID to 52,
SENDER: Setting hire ID to 53,
SENDER: Setting hire ID to 54,
Waiting for 5 message(s)
New hire event processed:
Employee ID: 52
Name: Mark Wilson
Equipment: Tablet
Office number: 294
Waiting for 4 message(s)
New hire event processed:
Employee ID: 53
Name: Polly Wren
Equipment: Laptop
Office number: 186
Waiting for 3 message(s)
New hire event processed:
Employee ID: 54
Name: Joe Lawrence
Equipment: Mobile Phone
Office number: 135
Waiting for 2 message(s)
New hire event processed:
Employee ID: 50
Name: Bill Tudor
Equipment: Desktop System
Office number: 200
Waiting for 1 message(s)
New hire event processed:
Employee ID: 51
Name: Carol Jones
Equipment: Laptop
Office number: 262
name
name
name
name
name
Bill Tudor, position Programmer
Carol Jones, position Senior Programmer
Mark Wilson, position Manager
Polly Wren, position Senior Programmer
Joe Lawrence, position Director
The output from the message-driven beans and the entity class appears in the server
log.
For each employee, the application first creates the entity and then finds it. You may
see runtime errors in the server log, and transaction rollbacks may occur. The errors
occur if both of the message-driven beans discover at the same time that the entity
Java Message Service Examples 46-41
Using NetBeans IDE to Create JMS Resources
does not yet exist, so they both try to create it. The first attempt succeeds, but the
second fails because the bean already exists. After the rollback, the second
message-driven bean tries again and succeeds in finding the entity.
Container-managed transactions allow the application to run correctly, in spite of these
errors, with no special programming.
To undeploy the application after you have finished running it, use the Services tab or
issue the mvn cargo:undeploy command.
46.9 Using NetBeans IDE to Create JMS Resources
When you write your own JMS applications, you will need to create resources for
them. This section explains how to use NetBeans IDE to create
src/main/setup/glassfish-resources.xml files similar to those used in the examples
in this chapter. It also explains how to use NetBeans IDE to delete the resources.
You can also create, list, and delete JMS resources using the Administration Console or
the asadmin create-jms-resource, asadmin list-jms-resources, and asadmin
delete-jms-resources commands. For information, consult the GlassFish Server
documentation or enter asadmin help command-name.
46.9.1 To Create JMS Resources Using NetBeans IDE
Follow these steps to create a JMS resource in GlassFish Server using NetBeans IDE.
Repeat these steps for each resource you need.
1.
Right-click the project for which you want to create resources and select New, then
select Other.
2.
In the New File wizard, under Categories, select GlassFish.
3.
Under File Types, select JMS Resource.
4.
On the General Attributes - JMS Resource page, in the JNDI Name field, enter the
name of the resource.
By convention, JMS resource names begin with jms/.
5.
Select the option for the resource type.
Normally, this is either javax.jms.Queue, javax.jms.Topic, or
javax.jms.ConnectionFactory.
6.
Click Next.
7.
On the JMS Properties page, for a queue or topic, enter a name for a physical
queue in the Value field for the Name property.
You can enter any value for this required field.
Connection factories have no required properties. In a few situations, you may
need to specify a property.
8.
Click Finish.
A file named glassfish-resources.xml is created in your Maven project, in a
directory named src/main/setup/. In the Projects tab, you can find it under the
Other Sources node. You will need to run the asadmin add-resources command
to create the resources in GlassFish Server.
46-42 The Java EE 7 Tutorial
Using NetBeans IDE to Create JMS Resources
46.9.2 To Delete JMS Resources Using NetBeans IDE
1.
In the Services tab, expand the Servers node, then expand the GlassFish Server
node.
2.
Expand the Resources node, then expand the Connector Resources node.
3.
Expand the Admin Object Resources node.
4.
Right-click any destination you want to remove and select Unregister.
5.
Expand the Connector Connection Pools node.
6.
Right-click the connection pool that corresponds to the connection factory you
removed and select Unregister.
When you remove a connector connection pool, the associated connector resource
is also deleted. This action removes the connection factory.
Java Message Service Examples 46-43
Using NetBeans IDE to Create JMS Resources
46-44 The Java EE 7 Tutorial
Part X
Part X
Security
Part X explores security concepts and examples. This part contains the following
chapters:
■
Chapter 47, "Introduction to Security in the Java EE Platform"
■
Chapter 48, "Getting Started Securing Web Applications"
■
Chapter 49, "Getting Started Securing Enterprise Applications"
■
Chapter 50, "Java EE Security: Advanced Topics"
47
Introduction to Security in the Java EE
Platform
47
This chapter introduces basic security concepts and security mechanisms. More
information on these concepts and mechanisms can be found in the chapter on
security in the Java EE 7 specification.
Other chapters in this Part discuss security requirements in web tier and enterprise tier
applications.
■
■
Chapter 48, "Getting Started Securing Web Applications" explains how to add
security to web components, such as servlets.
Chapter 49, "Getting Started Securing Enterprise Applications" explains how to
add security to Java EE components, such as enterprise beans and application
clients.
The following topics are addressed here:
■
Overview of Java EE Security
■
Security Mechanisms
■
Securing Containers
■
Securing GlassFish Server
■
Working with Realms, Users, Groups, and Roles
■
Establishing a Secure Connection Using SSL
■
Further Information about Security
47.1 Overview of Java EE Security
Every enterprise that has either sensitive resources that can be accessed by many users
or resources that traverse unprotected, open networks, such as the Internet, needs to
be protected.
Enterprise tier and web tier applications are made up of components that are deployed
into various containers. These components are combined to build a multitier
enterprise application. Security for components is provided by their containers. A
container provides two kinds of security: declarative and programmatic.
■
Declarative security expresses an application component's security requirements
by using either deployment descriptors or annotations.
A deployment descriptor is an XML file that is external to the application and that
expresses an application's security structure, including security roles, access
Introduction to Security in the Java EE Platform 47-1
Overview of Java EE Security
control, and authentication requirements. For more information about deployment
descriptors, read Using Deployment Descriptors for Declarative Security.
Annotations, also called metadata, are used to specify information about security
within a class file. When the application is deployed, this information can be either
used by or overridden by the application deployment descriptor. Annotations save
you from having to write declarative information inside XML descriptors. Instead,
you simply put annotations on the code, and the required information gets
generated. For this tutorial, annotations are used for securing applications
wherever possible. For more information about annotations, see Using
Annotations to Specify Security Information.
■
Programmatic security is embedded in an application and is used to make
security decisions. Programmatic security is useful when declarative security
alone is not sufficient to express the security model of an application. For more
information about programmatic security, read Using Programmatic Security.
47.1.1 A Simple Application Security Walkthrough
The security behavior of a Java EE environment may be better understood by
examining what happens in a simple application with a web client, a user interface,
and enterprise bean business logic.
In the following example, which is taken from the Java EE 7 Specification, the web
client relies on the web server to act as its authentication proxy by collecting user
authentication data from the client and using it to establish an authenticated session.
47.1.1.1 Step 1: Initial Request
In the first step of this example, the web client requests the main application URL. This
action is shown in Figure 47–1.
Figure 47–1 Initial Request
Web Client
Request access to
protected resource
Web Server
Since the client has not yet authenticated itself to the application environment, the
server responsible for delivering the web portion of the application, hereafter referred
to as the web server, detects this and invokes the appropriate authentication mechanism
for this resource. For more information on these mechanisms, see Security
Mechanisms.
47.1.1.2 Step 2: Initial Authentication
The web server returns a form that the web client uses to collect authentication data,
such as user name and password, from the user. The web client forwards the
authentication data to the web server, where it is validated by the web server, as
shown in Figure 47–2. The validation mechanism may be local to a server or may
leverage the underlying security services. On the basis of the validation, the web
server sets a credential for the user.
Figure 47–2 Initial Authentication
Web Server
Web Client
47-2 The Java EE 7 Tutorial
Form
Authentication
data
Credential
Overview of Java EE Security
47.1.1.3 Step 3: URL Authorization
The credential is used for future determinations of whether the user is authorized to
access restricted resources it may request. The web server consults the security policy
associated with the web resource to determine the security roles that are permitted
access to the resource. The security policy is derived from annotations or from the
deployment descriptor. The web container then tests the user's credential against each
role to determine whether it can map the user to the role. Figure 47–3 shows this
process.
Figure 47–3 URL Authorization
Web Server
Requested
access to
protected
resource
Credential
Session
Context
Authorization
Web Client
Web
Component
The web server's evaluation stops with an "is authorized" outcome when the web
server is able to map the user to a role. A "not authorized" outcome is reached if the
web server is unable to map the user to any of the permitted roles.
47.1.1.4 Step 4: Fulfilling the Original Request
If the user is authorized, the web server returns the result of the original URL request,
as shown in Figure 47–4.
Figure 47–4 Fulfilling the Original Request
Web Server
Web Client
Result of request
Post to
business logic
Credential
Web Component
Session
Context
In our example, the response URL of a web page is returned, enabling the user to post
form data that needs to be handled by the business-logic component of the
application. See Chapter 48, "Getting Started Securing Web Applications" for more
information on protecting web applications.
47.1.1.5 Step 5: Invoking Enterprise Bean Business Methods
The web page performs the remote method call to the enterprise bean, using the user's
credential to establish a secure association between the web page and the enterprise
bean, as shown in Figure 47–5. The association is implemented as two related security
contexts: one in the web server and one in the EJB container.
Introduction to Security in the Java EE Platform 47-3
Overview of Java EE Security
Figure 47–5 Invoking an Enterprise Bean Business Method
Web Server
Credential
Web
Component
Session
Context
Security
Context
Remote
call
EJB Container
Authorization
Web Client
Credential
used to
establish
security
association
EJB
Security
Context
The EJB container is responsible for enforcing access control on the enterprise bean
method. The container consults the security policy associated with the enterprise bean
to determine the security roles that are permitted access to the method. The security
policy is derived from annotations or from the deployment descriptor. For each role,
the EJB container determines whether it can map the caller to the role by using the
security context associated with the call.
The container's evaluation stops with an "is authorized" outcome when the container is
able to map the caller's credential to a role. A "not authorized" outcome is reached if
the container is unable to map the caller to any of the permitted roles. A "not
authorized" result causes an exception to be thrown by the container and propagated
back to the calling web page.
If the call is authorized, the container dispatches control to the enterprise bean
method. The result of the bean's execution of the call is returned to the web page and
ultimately to the user by the web server and the web client.
47.1.2 Features of a Security Mechanism
A properly implemented security mechanism will provide the following functionality:
■
■
■
Prevent unauthorized access to application functions and business or personal
data (authentication)
Hold system users accountable for operations they perform (non-repudiation)
Protect a system from service interruptions and other breaches that affect quality
of service
Ideally, properly implemented security mechanisms will also be
■
Easy to administer
■
Transparent to system users
■
Interoperable across application and enterprise boundaries
47.1.3 Characteristics of Application Security
Java EE applications consist of components that can contain both protected and
unprotected resources. Often, you need to protect resources to ensure that only
authorized users have access. Authorization provides controlled access to protected
resources. Authorization is based on identification and authentication. Identification
is a process that enables recognition of an entity by a system, and authentication is a
process that verifies the identity of a user, device, or other entity in a computer system,
usually as a prerequisite to allowing access to resources in a system.
47-4 The Java EE 7 Tutorial
Security Mechanisms
Authorization and authentication are not required for an entity to access unprotected
resources. Accessing a resource without authentication is referred to as
unauthenticated, or anonymous, access.
The characteristics of application security that, when properly addressed, help to
minimize the security threats faced by an enterprise include the following.
■
■
■
■
■
■
■
Authentication: The means by which communicating entities, such as client and
server, prove to each other that they are acting on behalf of specific identities that
are authorized for access. This ensures that users are who they say they are.
Authorization, or access control: The means by which interactions with resources
are limited to collections of users or programs for the purpose of enforcing
integrity, confidentiality, or availability constraints. This ensures that users have
permission to perform operations or access data.
Data integrity: The means used to prove that information has not been modified
by a third party, an entity other than the source of the information. For example, a
recipient of data sent over an open network must be able to detect and discard
messages that were modified after they were sent. This ensures that only
authorized users can modify data.
Confidentiality, or data privacy: The means used to ensure that information is
made available only to users who are authorized to access it. This ensures that
only authorized users can view sensitive data.
Non-repudiation: The means used to prove that a user who performed some
action cannot reasonably deny having done so. This ensures that transactions can
be proved to have happened.
Quality of Service: The means used to provide better service to selected network
traffic over various technologies.
Auditing: The means used to capture a tamper-resistant record of security-related
events for the purpose of being able to evaluate the effectiveness of security
policies and mechanisms. To enable this, the system maintains a record of
transactions and security information.
47.2 Security Mechanisms
The characteristics of an application should be considered when deciding the layer
and type of security to be provided for applications. The following sections discuss the
characteristics of the common mechanisms that can be used to secure Java EE
applications. Each of these mechanisms can be used individually or with others to
provide protection layers based on the specific needs of your implementation.
47.2.1 Java SE Security Mechanisms
Java SE provides support for a variety of security features and mechanisms.
■
■
Java Authentication and Authorization Service (JAAS) is a set of APIs that
enable services to authenticate and enforce access controls upon users. JAAS
provides a pluggable and extensible framework for programmatic user
authentication and authorization. JAAS is a core Java SE API and is an underlying
technology for Java EE security mechanisms.
Java Generic Security Services (Java GSS-API) is a token-based API used to
securely exchange messages between communicating applications. The GSS-API
offers application programmers uniform access to security services atop a variety
of underlying security mechanisms, including Kerberos.
Introduction to Security in the Java EE Platform 47-5
Security Mechanisms
■
■
■
Java Cryptography Extension (JCE) provides a framework and implementations
for encryption, key generation and key agreement, and Message Authentication
Code (MAC) algorithms. Support for encryption includes symmetric, asymmetric,
block, and stream ciphers. Block ciphers operate on groups of bytes; stream
ciphers operate on one byte at a time. The software also supports secure streams
and sealed objects.
Java Secure Sockets Extension (JSSE) provides a framework and an
implementation for a Java version of the Secure Sockets Layer (SSL) and Transport
Layer Security (TLS) protocols and includes functionality for data encryption,
server authentication, message integrity, and optional client authentication to
enable secure Internet communications.
Simple Authentication and Security Layer (SASL) is an Internet standard (RFC
2222) that specifies a protocol for authentication and optional establishment of a
security layer between client and server applications. SASL defines how
authentication data is to be exchanged but does not itself specify the contents of
that data. SASL is a framework into which specific authentication mechanisms
that specify the contents and semantics of the authentication data can fit.
Java SE also provides a set of tools for managing keystores, certificates, and policy
files; generating and verifying JAR signatures; and obtaining, listing, and managing
Kerberos tickets.
For more information on Java SE security, visit
http://docs.oracle.com/javase/7/docs/technotes/guides/security/.
47.2.2 Java EE Security Mechanisms
Java EE security services are provided by the component container and can be
implemented by using declarative or programmatic techniques (see Securing
Containers). Java EE security services provide a robust and easily configured security
mechanism for authenticating users and authorizing access to application functions
and associated data at many different layers. Java EE security services are separate
from the security mechanisms of the operating system.
47.2.2.1 Application-Layer Security
In Java EE, component containers are responsible for providing application-layer
security, security services for a specific application type tailored to the needs of the
application. At the application layer, application firewalls can be used to enhance
application protection by protecting the communication stream and all associated
application resources from attacks.
Java EE security is easy to implement and configure and can offer fine-grained access
control to application functions and data. However, as is inherent to security applied
at the application layer, security properties are not transferable to applications running
in other environments and protect data only while it is residing in the application
environment. In the context of a traditional enterprise application, this is not
necessarily a problem, but when applied to a web services application, in which data
often travels across several intermediaries, you would need to use the Java EE security
mechanisms along with transport-layer security and message-layer security for a
complete security solution.
The advantages of using application-layer security include the following.
■
Security is uniquely suited to the needs of the application.
■
Security is fine grained, with application-specific settings.
47-6 The Java EE 7 Tutorial
Security Mechanisms
The disadvantages of using application-layer security include the following.
■
The application is dependent on security attributes that are not transferable
between application types.
■
Support for multiple protocols makes this type of security vulnerable.
■
Data is close to or contained within the point of vulnerability.
For more information on providing security at the application layer, see Securing
Containers.
47.2.2.2 Transport-Layer Security
Transport-layer security is provided by the transport mechanisms used to transmit
information over the wire between clients and providers; thus, transport-layer security
relies on secure HTTP transport (HTTPS) using Secure Sockets Layer (SSL). Transport
security is a point-to-point security mechanism that can be used for authentication,
message integrity, and confidentiality. When running over an SSL-protected session,
the server and client can authenticate each other and negotiate an encryption
algorithm and cryptographic keys before the application protocol transmits or receives
its first byte of data. Security is active from the time the data leaves the client until it
arrives at its destination, or vice versa, even across intermediaries. The problem is that
the data is not protected once it gets to the destination. One solution is to encrypt the
message before sending.
Transport-layer security is performed in a series of phases, as follows.
■
■
■
The client and server agree on an appropriate algorithm.
A key is exchanged using public-key encryption and certificate-based
authentication.
A symmetric cipher is used during the information exchange.
Digital certificates are necessary when running HTTPS using SSL. The HTTPS service
of most web servers will not run unless a digital certificate has been installed. Digital
certificates have already been created for GlassFish Server.
The advantages of using transport-layer security include the following.
■
It is relatively simple, well-understood, standard technology.
■
It applies to both a message body and its attachments.
The disadvantages of using transport-layer security include the following.
■
■
■
■
It is tightly coupled with the transport-layer protocol.
It represents an all-or-nothing approach to security. This implies that the security
mechanism is unaware of message contents, so that you cannot selectively apply
security to portions of the message as you can with message-layer security.
Protection is transient. The message is protected only while in transit. Protection is
removed automatically by the endpoint when it receives the message.
It is not an end-to-end solution, simply point-to-point.
For more information on transport-layer security, see Establishing a Secure Connection
Using SSL.
47.2.2.3 Message-Layer Security
In message-layer security, security information is contained within the SOAP message
and/or SOAP message attachment, which allows security information to travel along
Introduction to Security in the Java EE Platform 47-7
Securing Containers
with the message or attachment. For example, a portion of the message may be signed
by a sender and encrypted for a particular receiver. When sent from the initial sender,
the message may pass through intermediate nodes before reaching its intended
receiver. In this scenario, the encrypted portions continue to be opaque to any
intermediate nodes and can be decrypted only by the intended receiver. For this
reason, message-layer security is also sometimes referred to as end-to-end security.
The advantages of message-layer security include the following.
■
■
■
■
Security stays with the message over all hops and after the message arrives at its
destination.
Security can be selectively applied to different portions of a message and, if using
XML Web Services Security, to attachments.
Message security can be used with intermediaries over multiple hops.
Message security is independent of the application environment or transport
protocol.
The disadvantage of using message-layer security is that it is relatively complex and
adds some overhead to processing.
GlassFish Server supports message security using Metro, a web services stack that
uses Web Services Security (WSS) to secure messages. Because this message security is
specific to Metro and is not a part of the Java EE platform, this tutorial does not
discuss using WSS to secure messages. See the Metro User's Guide at
https://metro.java.net/guide/.
47.3 Securing Containers
In Java EE, the component containers are responsible for providing application
security. A container provides two types of security: declarative and programmatic.
47.3.1 Using Annotations to Specify Security Information
Annotations enable a declarative style of programming and so encompass both the
declarative and programmatic security concepts. Users can specify information about
security within a class file by using annotations. GlassFish Server uses this information
when the application is deployed. Not all security information can be specified by
using annotations, however. Some information must be specified in the application
deployment descriptors.
Specific annotations that can be used to specify security information within an
enterprise bean class file are described in Securing an Enterprise Bean Using
Declarative Security. Chapter 48, "Getting Started Securing Web Applications",
describes how to use annotations to secure web applications where possible.
Deployment descriptors are described only where necessary.
For more information on annotations, see Further Information about Security.
47.3.2 Using Deployment Descriptors for Declarative Security
Declarative security can express an application component's security requirements by
using deployment descriptors. Because deployment descriptor information is
declarative, it can be changed without the need to modify the source code. At runtime,
the Java EE server reads the deployment descriptor and acts upon the corresponding
application, module, or component accordingly. Deployment descriptors must provide
47-8 The Java EE 7 Tutorial
Securing GlassFish Server
certain structural information for each component if this information has not been
provided in annotations or is not to be defaulted.
This part of the tutorial does not document how to create deployment descriptors; it
describes only the elements of the deployment descriptor relevant to security.
NetBeans IDE provides tools for creating and modifying deployment descriptors.
Different types of components use different formats, or schemas, for their deployment
descriptors. The security elements of deployment descriptors discussed in this tutorial
include the following.
■
Web components may use a web application deployment descriptor named
web.xml.
The schema for web component deployment descriptors is provided in Chapter 14
of the Java Servlet 3.1 specification (JSR 340), which can be downloaded from
http://jcp.org/en/jsr/detail?id=340.
■
Enterprise JavaBeans components may use an EJB deployment descriptor named
META-INF/ejb-jar.xml, contained in the EJB JAR file.
The schema for enterprise bean deployment descriptors is provided in Chapter 14
of the EJB 3.2 Core Contracts and Requirements Specification (JSR 345), which can
be downloaded from http://jcp.org/en/jsr/detail?id=345.
47.3.3 Using Programmatic Security
Programmatic security is embedded in an application and is used to make security
decisions. Programmatic security is useful when declarative security alone is not
sufficient to express the security model of an application. The API for programmatic
security consists of methods of the EJBContext interface and the HttpServletRequest
interface. These methods allow components to make business-logic decisions based on
the security role of the caller or remote user.
Programmatic security is discussed in more detail in the following sections:
■
Using Programmatic Security with Web Applications
■
Securing an Enterprise Bean Programmatically
47.4 Securing GlassFish Server
This tutorial describes deployment to GlassFish Server, which provides highly secure,
interoperable, and distributed component computing based on the Java EE security
model. GlassFish Server supports the Java EE 7 security model. You can configure
GlassFish Server for the following purposes.
■
Adding, deleting, or modifying authorized users. For more information on this
topic, see Working with Realms, Users, Groups, and Roles.
■
Configuring secure HTTP and Internet Inter-Orb Protocol (IIOP) listeners.
■
Configuring secure Java Management Extensions (JMX) connectors.
■
Adding, deleting, or modifying existing or custom realms.
■
Defining an interface for pluggable authorization providers using Java
Authorization Contract for Containers (JACC). JACC defines security contracts
between GlassFish Server and authorization policy modules. These contracts
specify how the authorization providers are installed, configured, and used in
access decisions.
Introduction to Security in the Java EE Platform 47-9
Working with Realms, Users, Groups, and Roles
■
■
■
Using pluggable audit modules.
Customizing authentication mechanisms. All implementations of Java EE 7
compatible web containers are required to support the Servlet Profile of JSR 196,
which offers an avenue for customizing the authentication mechanism applied by
the web container on behalf of one or more applications.
Setting and changing policy permissions for an application.
47.5 Working with Realms, Users, Groups, and Roles
You often need to protect resources to ensure that only authorized users have access.
See Characteristics of Application Security for an introduction to the concepts of
authentication, identification, and authorization.
This section discusses setting up users so that they can be correctly identified and
either given access to protected resources or denied access if they are not authorized to
access the protected resources. To authenticate a user, you need to follow these basic
steps.
1.
The application developer writes code to prompt for a user name and password.
The various methods of authentication are discussed in Specifying Authentication
Mechanisms.
2.
The application developer communicates how to set up security for the deployed
application by use of a metadata annotation or deployment descriptor. This step is
discussed in Setting Up Security Roles.
3.
The server administrator sets up authorized users and groups in GlassFish Server.
This is discussed in Managing Users and Groups in GlassFish Server.
4.
The application deployer maps the application's security roles to users, groups,
and principals defined in GlassFish Server. This topic is discussed in Mapping
Roles to Users and Groups.
47.5.1 What Are Realms, Users, Groups, and Roles?
A realm is a security policy domain defined for a web or application server. A realm
contains a collection of users, who may or may not be assigned to a group. Managing
users in GlassFish Server is discussed in Managing Users and Groups in GlassFish
Server.
An application will often prompt for a user name and password before allowing access
to a protected resource. After the user name and password have been entered, that
information is passed to the server, which either authenticates the user and sends the
protected resource or does not authenticate the user, in which case access to the
protected resource is denied. This type of user authentication is discussed in
Specifying an Authentication Mechanism in the Deployment Descriptor.
In some applications, authorized users are assigned to roles. In this situation, the role
assigned to the user in the application must be mapped to a principal or group defined
on the application server. Figure 47–6 shows this. More information on mapping roles
to users and groups can be found in Setting Up Security Roles.
47-10 The Java EE 7 Tutorial
Working with Realms, Users, Groups, and Roles
Figure 47–6 Mapping Roles to Users and Groups
Create users
and/or groups
Define roles
in application
Map roles to users
and/or groups
Application
Application
User 1
User 1
Role 1
User 2
Role 1
User 3
Group 1
User 2
User 3
Role 2
Role 2
Group 1
User 1
User 1
User 2
User 2
User 3
User 3
The following sections provide more information on realms, users, groups, and roles.
47.5.1.1 What Is a Realm?
The protected resources on a server can be partitioned into a set of protection spaces,
each with its own authentication scheme and/or authorization database containing a
collection of users and groups. A realm is a complete database of users and groups
identified as valid users of one or more applications and controlled by the same
authentication policy.
The Java EE server authentication service can govern users in multiple realms. The
file, admin-realm, and certificate realms come preconfigured for GlassFish Server.
In the file realm, the server stores user credentials locally in a file named keyfile.
You can use the Administration Console to manage users in the file realm. When
using the file realm, the server authentication service verifies user identity by
checking the file realm. This realm is used for the authentication of all clients except
for web browser clients that use HTTPS and certificates.
In the certificate realm, the server stores user credentials in a certificate database.
When using the certificate realm, the server uses certificates with HTTPS to
authenticate web clients. To verify the identity of a user in the certificate realm, the
authentication service verifies an X.509 certificate. For step-by-step instructions for
creating this type of certificate, see Working with Digital Certificates. The common
name field of the X.509 certificate is used as the principal name.
The admin-realm is also a file realm and stores administrator user credentials locally
in a file named admin-keyfile. You can use the Administration Console to manage
users in this realm in the same way you manage users in the file realm. For more
information, see Managing Users and Groups in GlassFish Server.
47.5.1.2 What Is a User?
A user is an individual or application program identity that has been defined in
GlassFish Server. In a web application, a user can have associated with that identity a
Introduction to Security in the Java EE Platform 47-11
Working with Realms, Users, Groups, and Roles
set of roles that entitle the user to access all resources protected by those roles. Users
can be associated with a group.
A Java EE user is similar to an operating system user. Typically, both types of users
represent people. However, these two types of users are not the same. The Java EE
server authentication service has no knowledge of the user name and password you
provide when you log in to the operating system. The Java EE server authentication
service is not connected to the security mechanism of the operating system. The two
security services manage users that belong to different realms.
47.5.1.3 What Is a Group?
A group is a set of authenticated users, classified by common traits, defined in
GlassFish Server. A Java EE user of the file realm can belong to a group in
GlassFish Server. (A user in the certificate realm cannot.) A group in GlassFish
Server is a category of users classified by common traits, such as job title or customer
profile. For example, most customers of an e-commerce application might belong to
the CUSTOMER group, but the big spenders would belong to the PREFERRED group.
Categorizing users into groups makes it easier to control the access of large numbers of
users.
A group in GlassFish Server has a different scope from a role. A group is designated
for the entire GlassFish Server, whereas a role is associated only with a specific
application in GlassFish Server.
47.5.1.4 What Is a Role?
A role is an abstract name for the permission to access a particular set of resources in
an application. A role can be compared to a key that can open a lock. Many people
might have a copy of the key. The lock doesn't care who you are, only that you have
the right key.
47.5.1.5 Some Other Terminology
The following terminology is also used to describe the security requirements of the
Java EE platform.
■
■
■
■
A principal is an entity that can be authenticated by an authentication protocol in
a security service that is deployed in an enterprise. A principal is identified by
using a principal name and authenticated by using authentication data.
A security policy domain, also known as a security domain or realm, is a scope
over which a common security policy is defined and enforced by the security
administrator of the security service.
Security attributes are a set of attributes associated with every principal. The
security attributes have many uses: for example, access to protected resources and
auditing of users. Security attributes can be associated with a principal by an
authentication protocol.
A credential is an object that contains or references security attributes used to
authenticate a principal for Java EE services. A principal acquires a credential
upon authentication or from another principal that allows its credential to be used.
47.5.2 Managing Users and Groups in GlassFish Server
Follow these steps for managing users before you run the tutorial examples.
47-12 The Java EE 7 Tutorial
Working with Realms, Users, Groups, and Roles
47.5.2.1 To Add Users to GlassFish Server
1.
Start GlassFish Server, if you haven't already done so.
Information on starting GlassFish Server is available in Starting and Stopping
GlassFish Server.
2.
Start the Administration Console, if you haven't already done so.
To start the Administration Console, open a web browser and specify the URL
http://localhost:4848/. If you changed the default Admin port during
installation, enter the correct port number in place of 4848.
3.
In the navigation tree, expand the Configurations node, then expand the
server-config node.
4.
Expand the Security node.
5.
Expand the Realms node.
6.
Select the realm to which you are adding users.
■
Select the file realm to add users you want to access applications running in
this realm.
For the example security applications, select the file realm.
■
Select the admin-realm to add users you want to enable as system
administrators of GlassFish Server.
You cannot add users to the certificate realm by using the Administration
Console. In the certificate realm, you can add only certificates. For information
on adding (importing) certificates to the certificate realm, see Adding Users to
the Certificate Realm.
7.
On the Edit Realm page, click Manage Users.
8.
On the File Users or Admin Users page, click New to add a new user to the realm.
9.
On the New File Realm User page, enter values in the User ID, Group List, New
Password, and Confirm New Password fields.
For the Admin Realm, the Group List field is read-only, and the group name is
asadmin. Restart GlassFish Server and the Administration Console after you add a
user to the Admin Realm.
For more information on these properties, see Working with Realms, Users,
Groups, and Roles.
For the example security applications, specify a user with any name and password
you like, but make sure that the user is assigned to the group TutorialUser. The
user name and password are case-sensitive. Keep a record of the user name and
password for working with the examples later in this tutorial.
10. Click OK to add this user to the realm, or click Cancel to quit without saving.
47.5.3 Setting Up Security Roles
When you design an enterprise bean or web component, you should always think
about the kinds of users who will access the component. For example, a web
application for a human resources department might have a different request URL for
someone who has been assigned the role of DEPT_ADMIN than for someone who has
been assigned the role of DIRECTOR. The DEPT_ADMIN role may let you view employee
data, but the DIRECTOR role enables you to modify employee data, including salary
data. Each of these security roles is an abstract logical grouping of users that is defined
Introduction to Security in the Java EE Platform 47-13
Working with Realms, Users, Groups, and Roles
by the person who assembles the application. When an application is deployed, the
deployer will map the roles to security identities in the operational environment, as
shown in Figure 47–6.
For Java EE components, you define security roles using the @DeclareRoles and
@RolesAllowed metadata annotations.
The following is an example of an application in which the role of DEPT-ADMIN is
authorized for methods that review employee payroll data, and the role of DIRECTOR is
authorized for methods that change employee payroll data.
The enterprise bean would be annotated as shown in the following code:
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
...
@DeclareRoles({"DEPT-ADMIN", "DIRECTOR"})
@Stateless public class PayrollBean implements Payroll {
@Resource SessionContext ctx;
@RolesAllowed("DEPT-ADMIN")
public void reviewEmployeeInfo(EmplInfo info) {
oldInfo = ... read from database;
// ...
}
@RolesAllowed("DIRECTOR")
public void updateEmployeeInfo(EmplInfo info) {
newInfo = ... update database;
// ...
}
...
}
For a servlet, you can use the @HttpConstraint annotation within the
@ServletSecurity annotation to specify the roles that are allowed to access the servlet.
For example, a servlet might be annotated as follows:
@WebServlet(name = "PayrollServlet", urlPatterns = {"/payroll"})
@ServletSecurity(
@HttpConstraint(transportGuarantee = TransportGuarantee.CONFIDENTIAL,
rolesAllowed = {"DEPT-ADMIN", "DIRECTOR"}))
public class GreetingServlet extends HttpServlet {
These annotations are discussed in more detail in Specifying Security for Basic
Authentication Using Annotations and Securing an Enterprise Bean Using Declarative
Security.
After users have provided their login information and the application has declared
what roles are authorized to access protected parts of an application, the next step is to
map the security role to the name of a user, or principal.
47.5.4 Mapping Roles to Users and Groups
When you are developing a Java EE application, you don't need to know what
categories of users have been defined for the realm in which the application will be
47-14 The Java EE 7 Tutorial
Establishing a Secure Connection Using SSL
run. In the Java EE platform, the security architecture provides a mechanism for
mapping the roles defined in the application to the users or groups defined in the
runtime realm.
The role names used in the application are often the same as the group names defined
in GlassFish Server. Under these circumstances, you can enable a default
principal-to-role mapping in GlassFish Server by using the Administration
Console. The task To Set Up Your System for Running the Security Examples explains
how to do this. All the tutorial security examples use default principal-to-role
mapping. With that setting enabled, if the group name defined on GlassFish Server
matches the role name defined in the application, there is no need to use the runtime
deployment descriptor to provide a mapping. The application server will implicitly
make this mapping, as long as the names of the groups and roles match.
If the role names used in an application are not the same as the group names defined
on the server, use the runtime deployment descriptor to specify the mapping. The
following example demonstrates how to do this mapping in the glassfish-web.xml
file, which is the file used for web applications:
<glassfish-web-app>
...
<security-role-mapping>
<role-name>Mascot</role-name>
<principal-name>Duke</principal-name>
</security-role-mapping>
<security-role-mapping>
<role-name>Admin</role-name>
<group-name>Director</group-name>
</security-role-mapping>
...
</glassfish-web-app>
A role can be mapped to specific principals, specific groups, or both. The principal or
group names must be valid principals or groups in the current default realm or in the
realm specified in the login-config element. In this example, the role of Mascot used
in the application is mapped to a principal, named Duke, that exists on the application
server. Mapping a role to a specific principal is useful when the person occupying that
role may change. For this application, you would need to modify only the runtime
deployment descriptor rather than search and replace throughout the application for
references to this principal.
Also in this example, the role of Admin is mapped to a group of users assigned the
group name of Director. This is useful because the group of people authorized to
access director-level administrative data has to be maintained only in GlassFish Server.
The application developer does not need to know who these people are, but only
needs to define the group of people who will be given access to the information.
The role-name must match the role-name in the security-role element of the
corresponding deployment descriptor or the role name defined in a @DeclareRoles
annotation.
47.6 Establishing a Secure Connection Using SSL
Secure Sockets Layer (SSL) technology is security that is implemented at the
transport layer (see Transport-Layer Security for more information about
transport-layer security). SSL allows web browsers and web servers to communicate
over a secure connection. In this secure connection, the data is encrypted before being
Introduction to Security in the Java EE Platform 47-15
Establishing a Secure Connection Using SSL
sent and then is decrypted upon receipt and before processing. Both the browser and
the server encrypt all traffic before sending any data.
SSL addresses the following important security considerations.
■
■
■
Authentication: During your initial attempt to communicate with a web server
over a secure connection, that server will present your web browser with a set of
credentials in the form of a server certificate (also called a public key certificate).
The purpose of the certificate is to verify that the site is who and what it claims to
be. In some cases, the server may request a certificate proving that the client is
who and what it claims to be; this mechanism is known as client authentication.
Confidentiality: When data is being passed between the client and the server on a
network, third parties can view and intercept this data. SSL responses are
encrypted so that the data cannot be deciphered by the third party and the data
remains confidential.
Integrity: When data is being passed between the client and the server on a
network, third parties can view and intercept this data. SSL helps guarantee that
the data will not be modified in transit by that third party.
The SSL protocol is designed to be as efficient as securely possible. However,
encryption and decryption are computationally expensive processes from a
performance standpoint. It is not strictly necessary to run an entire web application
over SSL, and it is customary for a developer to decide which pages require a secure
connection and which do not. Pages that might require a secure connection include
those for login, personal information, shopping cart checkouts, or credit card
information transmittal. Any page within an application can be requested over a
secure socket by simply prefixing the address with https: instead of http:. Any pages
that absolutely require a secure connection should check the protocol type associated
with the page request and take the appropriate action if https: is not specified.
Using name-based virtual hosts on a secured connection can be problematic. This is a
design limitation of the SSL protocol itself. The SSL handshake, whereby the client
browser accepts the server certificate, must occur before the HTTP request is accessed.
As a result, the request information containing the virtual host name cannot be
determined before authentication, and it is therefore not possible to assign multiple
certificates to a single IP address. If all virtual hosts on a single IP address need to
authenticate against the same certificate, the addition of multiple virtual hosts should
not interfere with normal SSL operations on the server. Be aware, however, that most
client browsers will compare the server's domain name against the domain name
listed in the certificate, if any; this is applicable primarily to official certificates signed
by a certificate authority (CA). If the domain names do not match, these browsers will
display a warning to the client. In general, only address-based virtual hosts are
commonly used with SSL in a production environment.
47.6.1 Verifying and Configuring SSL Support
As a general rule, you must address the following issues to enable SSL for a server.
■
■
■
There must be a Connector element for an SSL connector in the server deployment
descriptor.
There must be valid keystore and certificate files.
The location of the keystore file and its password must be specified in the server
deployment descriptor.
An SSL HTTPS connector is already enabled in GlassFish Server.
47-16 The Java EE 7 Tutorial
Further Information about Security
For testing purposes and to verify that SSL support has been correctly installed, load
the default introduction page with a URL that connects to the port defined in the
server deployment descriptor:
https://localhost:8181/
The https in this URL indicates that the browser should be using the SSL protocol.
The localhost in this example assumes that you are running the example on your
local machine as part of the development process. The 8181 in this example is the
secure port that was specified where the SSL connector was created. If you are using a
different server or port, modify this value accordingly.
The first time that you load this application, the New Site Certificate or Security Alert
dialog box appears. Click Next to move through the series of dialog boxes, and click
Finish when you reach the last dialog box. The certificates will appear only the first
time. When you accept the certificates, subsequent hits to this site assume that you still
trust the content.
47.7 Further Information about Security
For more information about security in Java EE applications, see
■
Java EE 7 specification:
http://jcp.org/en/jsr/detail?id=342
■
Enterprise JavaBeans 3.2 specification:
http://jcp.org/en/jsr/detail?id=345
■
Implementing Enterprise Web Services 1.3 specification:
http://jcp.org/en/jsr/detail?id=109
■
Java SE security information:
http://docs.oracle.com/javase/7/docs/technotes/guides/securit
y/
■
Java Servlet 3.1 specification:
http://jcp.org/en/jsr/detail?id=340
■
Java Authorization Contract for Containers 1.5 specification:
http://jcp.org/en/jsr/detail?id=115
Introduction to Security in the Java EE Platform 47-17
Further Information about Security
47-18 The Java EE 7 Tutorial
48
Getting Started Securing Web Applications
48
The ways to implement security for Java EE web applications are discussed in a
general way in Securing Containers. This chapter provides more detail and a few
examples that explore these security services as they relate to web components.
A web application is accessed using a web browser over a network, such as the
Internet or a company's intranet. As discussed in Distributed Multitiered Applications,
the Java EE platform uses a distributed multitiered application model, and web
applications run in the web tier.
Web applications contain resources that can be accessed by many users. These
resources often traverse unprotected, open networks, such as the Internet. In such an
environment, a substantial number of web applications will require some type of
security.
Securing applications and their clients in the business tier and the EIS tier is discussed
in Chapter 49, "Getting Started Securing Enterprise Applications".
The following topics are addressed here:
■
Overview of Web Application Security
■
Securing Web Applications
■
Using Programmatic Security with Web Applications
■
Examples: Securing Web Applications
48.1 Overview of Web Application Security
In the Java EE platform, web components provide the dynamic extension capabilities
for a web server. Web components can be Java servlets or JavaServer Faces pages.
Certain aspects of web application security can be configured when the application is
installed, or deployed, to the web container. Annotations and/or deployment
descriptors are used to relay information to the deployer about security and other
aspects of the application. Specifying this information in annotations or in the
deployment descriptor helps the deployer set up the appropriate security policy for
the web application. Any values explicitly specified in the deployment descriptor
override any values specified in annotations.
Security for Java EE web applications can be implemented in the following ways.
■
Declarative security can be implemented using either metadata annotations or an
application's deployment descriptor. See Overview of Java EE Security for more
information.
Getting Started Securing Web Applications 48-1
Securing Web Applications
Declarative security for web applications is described in Securing Web
Applications.
■
Programmatic security is embedded in an application and can be used to make
security decisions when declarative security alone is not sufficient to express the
security model of an application. Declarative security alone may not be sufficient
when conditional login in a particular work flow, instead of for all cases, is
required in the middle of an application. See Overview of Java EE Security for
more information.
Servlet 3.1 provides the authenticate, login, and logout methods of the
HttpServletRequest interface. With the addition of the authenticate, login, and
logout methods to the Servlet specification, an application deployment descriptor
is no longer required for web applications but may still be used to further specify
security requirements beyond the basic default values.
Programmatic security is discussed in Using Programmatic Security with Web
Applications.
■
Message security works with web services and incorporates security features,
such as digital signatures and encryption, into the header of a SOAP message,
working in the application layer, ensuring end-to-end security. Message security is
not a component of Java EE 7 and is mentioned here for informational purposes
only.
Some of the material in this chapter builds on material presented earlier in this
tutorial. In particular, this chapter assumes that you are familiar with the information
in the following chapters:
■
Chapter 6, "Getting Started with Web Applications"
■
Chapter 7, "JavaServer Faces Technology"
■
Chapter 17, "Java Servlet Technology"
■
Chapter 47, "Introduction to Security in the Java EE Platform"
48.2 Securing Web Applications
Web applications are created by application developers who give, sell, or otherwise
transfer the application to an application deployer for installation into a runtime
environment. Application developers communicate how to set up security for the
deployed application by using annotations or deployment descriptors. This
information is passed on to the deployer, who uses it to define method permissions for
security roles, set up user authentication, and set up the appropriate transport
mechanism. If the application developer doesn't define security requirements, the
deployer will have to determine the security requirements independently.
Some elements necessary for security in a web application cannot be specified as
annotations for all types of web applications. This chapter explains how to secure web
applications using annotations wherever possible. It explains how to use deployment
descriptors where annotations cannot be used.
48.2.1 Specifying Security Constraints
A security constraint is used to define the access privileges to a collection of resources
using their URL mapping.
If your web application uses a servlet, you can express the security constraint
information by using annotations. Specifically, you use the @HttpConstraint and,
48-2 The Java EE 7 Tutorial
Securing Web Applications
optionally, the @HttpMethodConstraint annotations within the @ServletSecurity
annotation to specify a security constraint.
If your web application does not use a servlet, however, you must specify a
security-constraint element in the deployment descriptor file. The authentication
mechanism cannot be expressed using annotations, so if you use any authentication
method other than BASIC (the default), a deployment descriptor is required.
The following subelements can be part of a security-constraint.
■
■
■
Web resource collection (web-resource-collection): A list of URL patterns (the
part of a URL after the host name and port you want to constrain) and HTTP
operations (the methods within the files that match the URL pattern you want to
constrain) that describe a set of resources to be protected. Web resource collections
are discussed in Specifying a Web Resource Collection.
Authorization constraint (auth-constraint): Specifies whether authentication is
to be used and names the roles authorized to perform the constrained requests.
For more information about authorization constraints, see Specifying an
Authorization Constraint.
User data constraint (user-data-constraint): Specifies how data is protected
when transported between a client and a server. User data constraints are
discussed in Specifying a Secure Connection.
48.2.1.1 Specifying a Web Resource Collection
A web resource collection consists of the following subelements.
■
■
web-resource-name is the name you use for this resource. Its use is optional.
url-pattern is used to list the request URI to be protected. Many applications
have both unprotected and protected resources. To provide unrestricted access to a
resource, do not configure a security constraint for that particular request URI.
The request URI is the part of a URL after the host name and port. For example,
let's say that you have an e-commerce site with a catalog that you would want
anyone to be able to access and browse, and a shopping cart area for customers
only. You could set up the paths for your web application so that the pattern
/cart/* is protected but nothing else is protected. Assuming that the application
is installed at context path /myapp, the following are true.
–
http://localhost:8080/myapp/index.xhtml is not protected.
–
http://localhost:8080/myapp/cart/index.xhtml is protected.
A user will be prompted to log in the first time he or she accesses a resource in the
cart/ subdirectory.
■
http-method or http-method-omission is used to specify which methods should
be protected or which methods should be omitted from protection. An HTTP
method is protected by a web-resource-collection under any of the following
circumstances:
–
If no HTTP methods are named in the collection (which means that all are
protected)
–
If the collection specifically names the HTTP method in an http-method
subelement
–
If the collection contains one or more http-method-omission elements, none
of which names the HTTP method
Getting Started Securing Web Applications 48-3
Securing Web Applications
48.2.1.2 Specifying an Authorization Constraint
An authorization constraint (auth-constraint) contains the role-name element. You
can use as many role-name elements as needed here.
An authorization constraint establishes a requirement for authentication and names
the roles authorized to access the URL patterns and HTTP methods declared by this
security constraint. If there is no authorization constraint, the container must accept
the request without requiring user authentication. If there is an authorization
constraint but no roles are specified within it, the container will not allow access to
constrained requests under any circumstances. Each role name specified here must
either correspond to the role name of one of the security-role elements defined for
this web application or be the specially reserved role name *, which indicates all roles
in the web application. Role names are case sensitive. The roles defined for the
application must be mapped to users and groups defined on the server, except when
default principal-to-role mapping is used.
For more information about security roles, see Declaring Security Roles. For
information on mapping security roles, see Mapping Roles to Users and Groups.
For a servlet, the @HttpConstraint and @HttpMethodConstraint annotations accept a
rolesAllowed element that specifies the authorized roles.
48.2.1.3 Specifying a Secure Connection
A user data constraint (user-data-constraint in the deployment descriptor) contains
the transport-guarantee subelement. A user data constraint can be used to require
that a protected transport-layer connection, such as HTTPS, be used for all constrained
URL patterns and HTTP methods specified in the security constraint. The choices for
transport guarantee are CONFIDENTIAL, INTEGRAL, or NONE. If you specify CONFIDENTIAL
or INTEGRAL as a security constraint, it generally means that the use of SSL is required
and applies to all requests that match the URL patterns in the web resource collection,
not just to the login dialog box.
The strength of the required protection is defined by the value of the transport
guarantee, as follows.
■
■
■
Specify CONFIDENTIAL when the application requires that data be transmitted so as
to prevent other entities from observing the contents of the transmission.
Specify INTEGRAL when the application requires that the data be sent between
client and server in such a way that it cannot be changed in transit.
Specify NONE to indicate that the container must accept the constrained requests on
any connection, including an unprotected one.
In practice, Java EE servers treat the CONFIDENTIAL and
INTEGRAL transport guarantee values identically.
Note:
The user data constraint is handy to use in conjunction with basic and form-based user
authentication. When the login authentication method is set to BASIC or FORM,
passwords are not protected, meaning that passwords sent between a client and a
server on an unprotected session can be viewed and intercepted by third parties.
Using a user data constraint with the user authentication mechanism can alleviate this
concern. Configuring a user authentication mechanism is described in Specifying an
Authentication Mechanism in the Deployment Descriptor.
48-4 The Java EE 7 Tutorial
Securing Web Applications
To guarantee that data is transported over a secure connection, ensure that SSL
support is configured for your server. SSL support is already configured for GlassFish
Server.
After you switch to SSL for a session, you should never
accept any non-SSL requests for the rest of that session. For
example, a shopping site might not use SSL until the checkout
page, and then it might switch to using SSL to accept your card
number. After switching to SSL, you should stop listening to
non-SSL requests for this session. The reason for this practice is that
the session ID itself was not encrypted on the earlier
communications. This is not so bad when you're only doing your
shopping, but after the credit card information is stored in the
session, you don't want anyone to use that information to fake the
purchase transaction against your credit card. This practice could
be easily implemented by using a filter.
Note:
48.2.1.4 Specifying Security Constraints for Resources
You can create security constraints for resources within your application. For example,
you could allow users with the role of PARTNER full access to all resources at the URL
pattern /acme/wholesale/* and allow users with the role of CLIENT full access to all
resources at the URL pattern /acme/retail/*. This is the recommended way to protect
resources if you do not want to protect some HTTP methods while leaving other HTTP
methods unprotected. An example of a deployment descriptor that would
demonstrate this functionality is the following:
<!-- SECURITY CONSTRAINT #1 -->
<security-constraint>
<web-resource-collection>
<web-resource-name>wholesale</web-resource-name>
<url-pattern>/acme/wholesale/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>PARTNER</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- SECURITY CONSTRAINT #2 -->
<security-constraint>
<web-resource-collection>
<web-resource-name>retail</web-resource-name>
<url-pattern>/acme/retail/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>CLIENT</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
Getting Started Securing Web Applications 48-5
Securing Web Applications
48.2.2 Specifying Authentication Mechanisms
A user authentication mechanism specifies
■
The way a user gains access to web content
■
With basic authentication, the realm in which the user will be authenticated
■
With form-based authentication, additional attributes
When an authentication mechanism is specified, the user must be authenticated before
access is granted to any resource that is constrained by a security constraint. There can
be multiple security constraints applying to multiple resources, but the same
authentication method will apply to all constrained resources in an application.
Before you can authenticate a user, you must have a database of user names,
passwords, and roles configured on your web or application server. For information
on setting up the user database, see Managing Users and Groups in GlassFish Server.
The Java EE platform supports the following authentication mechanisms:
■
Basic authentication
■
Form-based authentication
■
Digest authentication
■
Client authentication
■
Mutual authentication
Basic, form-based, and digest authentication are discussed in this section. Client and
mutual authentication are discussed in Chapter 50, "Java EE Security: Advanced
Topics".
HTTP basic authentication and form-based authentication are not very secure
authentication mechanisms. Basic authentication sends user names and passwords
over the Internet as Base64-encoded text. Form-based authentication sends this data as
plain text. In both cases, the target server is not authenticated. Therefore, these forms
of authentication leave user data exposed and vulnerable. If someone can intercept the
transmission, the user name and password information can easily be decoded.
However, when a secure transport mechanism, such as SSL, or security at the network
level, such as the Internet Protocol Security (IPsec) protocol or virtual private network
(VPN) strategies, is used in conjunction with basic or form-based authentication, some
of these concerns can be alleviated. To specify a secure transport mechanism, use the
elements described in Specifying a Secure Connection.
48.2.2.1 HTTP Basic Authentication
Specifying HTTP basic authentication requires that the server request a user name
and password from the web client and verify that the user name and password are
valid by comparing them against a database of authorized users in the specified or
default realm.
Basic authentication is the default when you do not specify an authentication
mechanism.
When basic authentication is used, the following actions occur.
1.
A client requests access to a protected resource.
2.
The web server returns a dialog box that requests the user name and password.
3.
The client submits the user name and password to the server.
48-6 The Java EE 7 Tutorial
Securing Web Applications
4.
The server authenticates the user in the specified realm and, if successful, returns
the requested resource.
Figure 48–1 shows what happens when you specify HTTP basic authentication.
Figure 48–1 HTTP Basic Authentication
Client
1 Requests protected resource
Requests username:password
Server
2
3 Sends username:password
Returns requested resource
4
48.2.2.2 Form-Based Authentication
Form-based authentication allows the developer to control the look and feel of the
login authentication screens by customizing the login screen and error pages that an
HTTP browser presents to the end user. When form-based authentication is declared,
the following actions occur.
1.
A client requests access to a protected resource.
2.
If the client is unauthenticated, the server redirects the client to a login page.
3.
The client submits the login form to the server.
4.
The server attempts to authenticate the user.
■
■
If authentication succeeds, the authenticated user's principal is checked to
ensure that it is in a role that is authorized to access the resource. If the user is
authorized, the server redirects the client to the resource by using the stored
URL path.
If authentication fails, the client is forwarded or redirected to an error page.
Figure 48–2 shows what happens when you specify form-based authentication.
Getting Started Securing Web Applications 48-7
Securing Web Applications
Figure 48–2 Form-Based Authentication
1
Requests protected resource
Login
Page
Client
3
Redirected to login page
2
Form submitted
Redirected to source
Error
Page
Server
j_security_check
4
Success
?
Failure
Error page returned
The section The hello1-formauth Example: Form-Based Authentication with a
JavaServer Faces Application is an example application that uses form-based
authentication.
When you create a form-based login, be sure to maintain sessions using cookies or SSL
session information.
For authentication to proceed appropriately, the action of the login form must always
be j_security_check. This restriction is made so that the login form will work no
matter which resource it is for and to avoid requiring the server to specify the action
field of the outbound form. The following code snippet shows how the form should be
coded into the HTML page:
<form method="POST" action="j_security_check">
<input type="text" name="j_username">
<input type="password" name="j_password">
</form>
48.2.2.3 Digest Authentication
Like basic authentication, digest authentication authenticates a user based on a user
name and a password. However, unlike basic authentication, digest authentication
does not send user passwords over the network. Instead, the client sends a one-way
cryptographic hash of the password and additional data. Although passwords are not
sent on the wire, digest authentication requires that clear-text password equivalents be
available to the authenticating container so that it can validate received authenticators
by calculating the expected digest.
48.2.3 Specifying an Authentication Mechanism in the Deployment Descriptor
To specify an authentication mechanism, use the login-config element. It can contain
the following subelements.
■
The auth-method subelement configures the authentication mechanism for the
web application. The element content must be either NONE, BASIC, DIGEST, FORM, or
CLIENT-CERT.
48-8 The Java EE 7 Tutorial
Securing Web Applications
■
■
The realm-name subelement indicates the realm name to use when the basic
authentication scheme is chosen for the web application.
The form-login-config subelement specifies the login and error pages that
should be used when form-based login is specified.
Another way to specify form-based authentication is to use
the authenticate, login, and logout methods of
HttpServletRequest, as discussed in Authenticating Users
Programmatically.
Note:
When you try to access a web resource that is constrained by a security-constraint
element, the web container activates the authentication mechanism that has been
configured for that resource. The authentication mechanism specifies how the user will
be prompted to log in. If the login-config element is present and the auth-method
element contains a value other than NONE, the user must be authenticated to access the
resource. If you do not specify an authentication mechanism, authentication of the user
is not required.
The following example shows how to declare form-based authentication in your
deployment descriptor:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>file</realm-name>
<form-login-config>
<form-login-page>/login.xhtml</form-login-page>
<form-error-page>/error.xhtml</form-error-page>
</form-login-config>
</login-config>
The login and error page locations are specified relative to the location of the
deployment descriptor. Examples of login and error pages are shown in Creating the
Login Form and the Error Page.
The following example shows how to declare digest authentication in your
deployment descriptor:
<login-config>
<auth-method>DIGEST</auth-method>
</login-config>
48.2.4 Declaring Security Roles
You can declare security role names used in web applications by using the
security-role element of the deployment descriptor. Use this element to list all the
security roles that you have referenced in your application.
The following snippet of a deployment descriptor declares the roles that will be used
in an application using the security-role element and specifies which of these roles
is authorized to access protected resources using the auth-constraint element:
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/security/protected/*</url-pattern>
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
<http-method>GET</http-method>
Getting Started Securing Web Applications 48-9
Using Programmatic Security with Web Applications
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<!-- Security roles used by this web application -->
<security-role>
<role-name>manager</role-name>
</security-role>
<security-role>
<role-name>employee</role-name>
</security-role>
In this example, the security-role element lists all the security roles used in the
application: manager and employee. This enables the deployer to map all the roles
defined in the application to users and groups defined in GlassFish Server.
The auth-constraint element specifies the role, manager, that can access the HTTP
methods PUT, DELETE, GET, and POST located in the directory specified by the
url-pattern element (/security/protected/*).
The @ServletSecurity annotation cannot be used in this situation because its
constraints apply to all URL patterns specified by the @WebServlet annotation.
48.3 Using Programmatic Security with Web Applications
Programmatic security is used by security-aware applications when declarative
security alone is not sufficient to express the security model of the application.
48.3.1 Authenticating Users Programmatically
The following methods of the HttpServletRequest interface enable you to
authenticate users for a web application programmatically.
■
■
■
authenticate allows an application to instigate authentication of the request caller
by the container from within an unconstrained request context. A login dialog box
displays and collects the user name and password for authentication purposes.
login allows an application to collect user name and password information as an
alternative to specifying form-based authentication in an application deployment
descriptor.
logout allows an application to reset the caller identity of a request.
The following example code shows how to use the login and logout methods:
package test;
import
import
import
import
import
import
import
import
import
java.io.IOException;
java.io.PrintWriter;
java.math.BigDecimal;
javax.ejb.EJB;
javax.servlet.ServletException;
javax.servlet.annotation.WebServlet;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
@WebServlet(name="TutorialServlet", urlPatterns={"/TutorialServlet"})
48-10 The Java EE 7 Tutorial
Using Programmatic Security with Web Applications
public class TutorialServlet extends HttpServlet {
@EJB
private ConverterBean converterBean;
/**
* Processes requests for both HTTP <code>GET</code>
*
and <code>POST</code> methods.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet TutorialServlet</title>");
out.println("</head>");
out.println("<body>");
request.login("TutorialUser", "TutorialUser");
BigDecimal result =
converterBean.dollarToYen(new BigDecimal("1.0"));
out.println("<h1>Servlet TutorialServlet result of dollarToYen= "
+ result + "</h1>");
out.println("</body>");
out.println("</html>");
} catch (Exception e) {
throw new ServletException(e);
} finally {
request.logout();
out.close();
}
}
}
The following example code shows how to use the authenticate method:
package com.example.test;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class TestServlet extends HttpServlet {
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
request.authenticate(response);
out.println("Authenticate Successful");
} finally {
out.close();
}
Getting Started Securing Web Applications 48-11
Using Programmatic Security with Web Applications
}
48.3.2 Checking Caller Identity Programmatically
In general, security management should be enforced by the container in a manner that
is transparent to the web component. The security API described in this section should
be used only in the less frequent situations in which the web component methods need
to access the security context information.
Servlet 3.1 specifies the following methods that enable you to access security
information about the component's caller.
■
■
getRemoteUser determines the user name with which the client authenticated. The
getRemoteUser method returns the name of the remote user (the caller) associated
by the container with the request. If no user has been authenticated, this method
returns null.
isUserInRole determines whether a remote user is in a specific security role. If no
user has been authenticated, this method returns false. This method expects a
String user role-name parameter.
The security-role-ref element should be declared in the deployment descriptor
with a role-name subelement containing the role name to be passed to the
method. Using security role references is discussed in Declaring and Linking Role
References.
■
getUserPrincipal determines the principal name of the current user and returns a
java.security.Principal object. If no user has been authenticated, this method
returns null. Calling the getName method on the Principal returned by
getUserPrincipal returns the name of the remote user.
Your application can make business-logic decisions based on the information obtained
using these APIs.
48.3.3 Example Code for Programmatic Security
The following code demonstrates the use of programmatic security for the purposes of
programmatic login. This servlet does the following.
1.
It displays information about the current user.
2.
It prompts the user to log in.
3.
It prints out the information again to demonstrate the effect of the login method.
4.
It logs the user out.
5.
It prints out the information again to demonstrate the effect of the logout method.
package enterprise.programmatic_login;
import
import
import
import
import
java.io.*;
java.net.*;
javax.annotation.security.DeclareRoles;
javax.servlet.*;
javax.servlet.http.*;
@DeclareRoles("javaee7user")
public class LoginServlet extends HttpServlet {
/**
* Processes requests for both HTTP GET and POST methods.
* @param request servlet request
48-12 The Java EE 7 Tutorial
Using Programmatic Security with Web Applications
* @param response servlet response
*/
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
String userName = request.getParameter("txtUserName");
String password = request.getParameter("txtPassword");
out.println("Before Login" + "<br><br>");
out.println("IsUserInRole?.."
+ request.isUserInRole("javaee7user")+"<br>");
out.println("getRemoteUser?.." + request.getRemoteUser()+"<br>");
out.println("getUserPrincipal?.."
+ request.getUserPrincipal()+"<br>");
out.println("getAuthType?.." + request.getAuthType()+"<br><br>");
try {
request.login(userName, password);
} catch(ServletException ex) {
out.println("Login Failed with a ServletException.."
+ ex.getMessage());
return;
}
out.println("After Login..."+"<br><br>");
out.println("IsUserInRole?.."
+ request.isUserInRole("javaee7user")+"<br>");
out.println("getRemoteUser?.." + request.getRemoteUser()+"<br>");
out.println("getUserPrincipal?.."
+ request.getUserPrincipal()+"<br>");
out.println("getAuthType?.." + request.getAuthType()+"<br><br>");
request.logout();
out.println("After Logout..."+"<br><br>");
out.println("IsUserInRole?.."
+ request.isUserInRole("javaee7user")+"<br>");
out.println("getRemoteUser?.." + request.getRemoteUser()+"<br>");
out.println("getUserPrincipal?.."
+ request.getUserPrincipal()+"<br>");
out.println("getAuthType?.." + request.getAuthType()+"<br>");
} finally {
out.close();
}
}
...
}
48.3.4 Declaring and Linking Role References
A security role reference is a mapping between the name of a role that is called from a
web component using isUserInRole(String role) and the name of a security role
that has been defined for the application. If no security-role-ref element is declared
in a deployment descriptor and the isUserInRole method is called, the container
defaults to checking the provided role name against the list of all security roles defined
for the web application. Using the default method instead of using the
security-role-ref element limits your flexibility to change role names in an
application without also recompiling the servlet making the call.
Getting Started Securing Web Applications 48-13
Examples: Securing Web Applications
The security-role-ref element is used when an application uses the
HttpServletRequest.isUserInRole(String role). The value passed to the
isUserInRole method is a String representing the role name of the user. The value of
the role-name element must be the String used as the parameter to the
HttpServletRequest.isUserInRole(String role). The role-link must contain the
name of one of the security roles defined in the security-role elements. The
container uses the mapping of security-role-ref to security-role when
determining the return value of the call.
For example, to map the security role reference cust to the security role with role
name bankCustomer, the elements would look like this:
<servlet>
...
<security-role-ref>
<role-name>cust</role-name>
<role-link>bankCustomer</role-link>
</security-role-ref>
...
</servlet>
If the servlet method is called by a user in the bankCustomer security role,
isUserInRole("cust") returns true.
The role-link element in the security-role-ref element must match a role-name
defined in the security-role element of the same web.xml deployment descriptor, as
shown here:
<security-role>
<role-name>bankCustomer</role-name>
</security-role>
A security role reference, including the name defined by the reference, is scoped to the
component whose deployment descriptor contains the security-role-ref
deployment descriptor element.
48.4 Examples: Securing Web Applications
Some basic setup is required before any of the example applications will run correctly.
The examples use annotations, programmatic security, and/or declarative security to
demonstrate adding security to existing web applications.
Here are some other locations where you will find examples of securing various types
of applications:
■
■
■
The cart-secure Example: Securing an Enterprise Bean with Declarative Security
The converter-secure Example: Securing an Enterprise Bean with Programmatic
Security
GlassFish samples: https://glassfish-samples.java.net/
48.4.1 To Set Up Your System for Running the Security Examples
To set up your system for running the security examples, you need to configure a user
database that the application can use for authenticating users. Before continuing,
follow these steps.
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
48-14 The Java EE 7 Tutorial
Examples: Securing Web Applications
2.
Add an authorized user to GlassFish Server. For the examples in this chapter
and in Chapter 49, "Getting Started Securing Enterprise Applications", add a user
to the file realm of GlassFish Server, and assign the user to the group
TutorialUser.
a.
From the Administration Console, expand the Configurations node, then
expand the server-config node.
b.
Expand the Security node.
c.
Expand the Realms node.
d.
Select the File node.
e.
On the Edit Realm page, click Manage Users.
f.
On the File Users page, click New.
g.
In the User ID field, enter a user ID.
h.
In the Group List field, enter TutorialUser.
i.
In the New Password and Confirm New Password fields, enter a password.
j.
Click OK.
Be sure to write down the user name and password for the user you create so that
you can use it for testing the example applications. Authentication is case sensitive
for both the user name and password, so write down the user name and password
exactly. This topic is discussed more in Managing Users and Groups in GlassFish
Server.
3.
Set up Default Principal to Role Mapping in GlassFish Server.
a.
From the Administration Console, expand the Configurations node, then
expand the server-config node.
b.
Select the Security node.
c.
Select the Default Principal to Role Mapping Enabled check box.
d.
Click Save.
48.4.2 The hello2-basicauth Example: Basic Authentication with a Servlet
This example explains how to use basic authentication with a servlet. With basic
authentication of a servlet, the web browser presents a standard login dialog box that
is not customizable. When a user submits his or her name and password, the server
determines whether the user name and password are those of an authorized user and
sends the requested web resource if the user is authorized to view it.
In general, the following steps are necessary for adding basic authentication to an
unsecured servlet, such as the ones described in Chapter 6, "Getting Started with Web
Applications". In the example application included with this tutorial, many of these
steps have been completed for you and are listed here simply to show what needs to
be done should you wish to create a similar application. This application can be found
in the tut-install/examples/security/hello2-basicauth/ directory.
1.
Follow the steps in To Set Up Your System for Running the Security Examples.
2.
Create a web module for the servlet example, hello2, as described in Chapter 6,
"Getting Started with Web Applications".
3.
Add the appropriate security annotations to the servlet. The security annotations
are described in Specifying Security for Basic Authentication Using Annotations.
Getting Started Securing Web Applications 48-15
Examples: Securing Web Applications
4.
Build, package, and deploy the web application by following the steps in To Build,
Package, and Deploy the hello2-basicauth Example Using NetBeans IDE or To
Build, Package, and Deploy the hello2-basicauth Example Using Maven.
5.
Run the web application by following the steps described in To Run the
hello2-basicauth Example.
48.4.2.1 Specifying Security for Basic Authentication Using Annotations
The default authentication mechanism used by GlassFish Server is basic
authentication. With basic authentication, GlassFish Server spawns a standard login
dialog box to collect user name and password data for a protected resource. Once the
user is authenticated, access to the protected resource is permitted.
To specify security for a servlet, use the @ServletSecurity annotation. This annotation
allows you to specify both specific constraints on HTTP methods and more general
constraints that apply to all HTTP methods for which no specific constraint is
specified. Within the @ServletSecurity annotation, you can specify the following
annotations:
■
■
The @HttpMethodConstraint annotation, which applies to a specific HTTP method
The more general @HttpConstraint annotation, which applies to all HTTP
methods for which there is no corresponding @HttpMethodConstraint annotation
Both the @HttpMethodConstraint and @HttpConstraint annotations within the
@ServletSecurity annotation can specify the following:
■
■
A transportGuarantee element that specifies the data protection requirements
(that is, whether or not SSL/TLS is required) that must be satisfied by the
connections on which requests arrive. Valid values for this element are NONE and
CONFIDENTIAL.
A rolesAllowed element that specifies the names of the authorized roles.
For the hello2-basicauth application, the GreetingServlet has the following
annotations:
@WebServlet(name = "GreetingServlet", urlPatterns = {"/greeting"})
@ServletSecurity(
@HttpConstraint(transportGuarantee = TransportGuarantee.CONFIDENTIAL,
rolesAllowed = {"TutorialUser"}))
These annotations specify that the request URI /greeting can be accessed only by
users who have been authorized to access this URL because they have been verified to
be in the role TutorialUser. The data will be sent over a protected transport in order
to keep the user name and password data from being read in transit.
If you use the @ServletSecurity annotation, you do not need to specify security
settings in the deployment descriptor. Use the deployment descriptor to specify
settings for nondefault authentication mechanisms, for which you cannot use the
@ServletSecurity annotation.
48.4.2.2 To Build, Package, and Deploy the hello2-basicauth Example Using
NetBeans IDE
1.
Follow the steps in To Set Up Your System for Running the Security Examples.
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/security
48-16 The Java EE 7 Tutorial
Examples: Securing Web Applications
4.
Select the hello2-basicauth folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the hello2-basicauth project and select Build.
This command builds and deploys the example application to your GlassFish
Server instance.
48.4.2.3 To Build, Package, and Deploy the hello2-basicauth Example Using Maven
1.
Follow the steps in To Set Up Your System for Running the Security Examples.
2.
In a terminal window, go to:
tut-install/examples/security/hello2-basicauth/
3.
Enter the following command:
mvn install
This command builds and packages the application into a WAR file,
hello2-basicauth.war, that is located in the target directory, then deploys the
WAR file.
48.4.2.4 To Run the hello2-basicauth Example
1.
In a web browser, enter the following URL:
https://localhost:8181/hello2-basicauth/greeting
You may be prompted to accept the security certificate for the server. If so, accept
the security certificate. If the browser warns that the certificate is invalid because it
is self-signed, add a security exception for the application.
An Authentication Required dialog box appears. Its appearance varies, depending
on the browser you use.
2.
Enter a user name and password combination that corresponds to a user who has
already been created in the file realm of GlassFish Server and has been assigned
to the group TutorialUser; then click OK.
Basic authentication is case sensitive for both the user name and password, so
enter the user name and password exactly as defined for GlassFish Server.
The server returns the requested resource if all the following conditions are met.
■
A user with the user name you entered is defined for GlassFish Server.
■
The user with the user name you entered has the password you entered.
■
■
3.
The user name and password combination you entered is assigned to the
group TutorialUser in GlassFish Server.
The role of TutorialUser, as defined for the application, is mapped to the
group TutorialUser, as defined for GlassFish Server.
Enter a name in the field and click Submit.
Because you have already been authorized, the name you enter in this step does
not have any limitations. You have unlimited access to the application now.
The application responds by saying "Hello" to the name you entered.
Getting Started Securing Web Applications 48-17
Examples: Securing Web Applications
48.4.3 The hello1-formauth Example: Form-Based Authentication with a JavaServer
Faces Application
This example explains how to use form-based authentication with a JavaServer Faces
application. With form-based authentication, you can customize the login screen and
error pages that are presented to the web client for authentication of the user name
and password. When a user submits his or her name and password, the server
determines whether the user name and password are those of an authorized user and,
if authorized, sends the requested web resource.
This example, hello1-formauth, adds security to the basic JavaServer Faces
application shown in A Web Module That Uses JavaServer Faces Technology: The
hello1 Example.
In general, the steps necessary for adding form-based authentication to an unsecured
JavaServer Faces application are similar to those described in The hello2-basicauth
Example: Basic Authentication with a Servlet. The major difference is that you must
use a deployment descriptor to specify the use of form-based authentication, as
described in Specifying Security for the Form-Based Authentication Example. In
addition, you must create a login form page and a login error page, as described in
Creating the Login Form and the Error Page.
This application can be found in the tut-install/examples/security/hello1-formauth/
directory.
48.4.3.1 Creating the Login Form and the Error Page
When using form-based login mechanisms, you must specify a page that contains the
form you want to use to obtain the user name and password, as well as a page to
display if login authentication fails. This section discusses the login form and the error
page used in this example. Specifying Security for the Form-Based Authentication
Example shows how you specify these pages in the deployment descriptor.
The login page can be an HTML page or a servlet, and it must return an HTML page
containing a form that conforms to specific naming conventions (see the Java Servlet
3.1 specification for more information on these requirements). To do this, include the
elements that accept user name and password information between <form></form>
tags in your login page. The content of an HTML page or servlet for a login page
should be coded as follows:
<form method="post" action="j_security_check">
<input type="text" name="j_username">
<input type="password" name= "j_password">
</form>
The full code for the login page used in this example can be found at
tut-install/examples/security/hello1-formauth/src/main/webapp/login.html. Here
is the code for this page:
<html lang="en">
<head>
<title>Login Form</title>
</head>
<body>
<h2>Hello, please log in:</h2>
<form method="post" action="j_security_check">
<table role="presentation">
<tr>
<td>Please type your user name: </td>
<td><input type="text" name="j_username"
48-18 The Java EE 7 Tutorial
Examples: Securing Web Applications
size="20"/></td>
</tr>
<tr>
<td>Please type your password: </td>
<td><input type="password" name="j_password"
size="20"/></td>
</tr>
</table>
<p></p>
<input type="submit" value="Submit"/>
<input type="reset" value="Reset"/>
</form>
</body>
</html>
The login error page is displayed if the user enters a user name and password
combination that is not authorized to access the protected URI. For this example, the
login error page can be found at
tut-install/examples/security/hello1-formauth/src/main/webapp/error.html. For
this example, the login error page explains the reason for receiving the error page and
provides a link that will allow the user to try again. Here is the code for this page:
<html lang="en">
<head>
<title>Login Error</title>
</head>
<body>
<h2>Invalid user name or password.</h2>
<p>Please enter a user name or password that is authorized to access
this application. For this application, this means a user that
has been created in the <code>file</code> realm and has been
assigned to the <em>group</em> of <code>TutorialUser</code>.</p>
<p><a href="login.html">Return to login page</a></p>
</body>
</html>
48.4.3.2 Specifying Security for the Form-Based Authentication Example
This example takes a very simple servlet-based web application and adds form-based
security. To specify form-based instead of basic authentication for a JavaServer Faces
example, you must use the deployment descriptor.
The following sample code shows the security elements added to the deployment
descriptor for this example, which can be found in
tut-install/examples/security/hello1-formauth/src/main/webapp/WEB-INF/web.xml:
<security-constraint>
<display-name>Constraint1</display-name>
<web-resource-collection>
<web-resource-name>wrcoll</web-resource-name>
<description/>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>TutorialUser</role-name>
</auth-constraint>
</security-constraint>
Getting Started Securing Web Applications 48-19
Examples: Securing Web Applications
<login-config>
<auth-method>FORM</auth-method>
<realm-name>file</realm-name>
<form-login-config>
<form-login-page>/login.xhtml</form-login-page>
<form-error-page>/error.xhtml</form-error-page>
</form-login-config>
</login-config>
<security-role>
<description/>
<role-name>TutorialUser</role-name>
</security-role>
48.4.3.3 To Build, Package, and Deploy the hello1-formauth Example Using
NetBeans IDE
1.
Follow the steps in To Set Up Your System for Running the Security Examples.
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/security
4.
Select the hello1-formauth folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the hello1-formauth project and select Run.
This command builds and deploys the example application to your GlassFish
Server instance, then opens it in a browser.
48.4.3.4 To Build, Package, and Deploy the hello1-formauth Example Using Maven
and the asadmin Command
1.
Follow the steps in To Set Up Your System for Running the Security Examples.
2.
In a terminal window, go to:
tut-install/examples/security/hello1-formauth/
3.
Enter the following command at the terminal window or command prompt:
mvn install
This command builds and packages the application into a WAR file,
hello1-formauth.war, that is located in the target directory, then deploys the
WAR file to GlassFish Server.
48.4.3.5 To Run the hello1-formauth Example
To run the web client for hello1-formauth, follow these steps.
1.
Open a web browser to the following URL:
http://localhost:8080/hello1-formauth/
2.
In the login form, enter a user name and password combination that corresponds
to a user who has already been created in the file realm of GlassFish Server and
has been assigned to the group TutorialUser.
48-20 The Java EE 7 Tutorial
Examples: Securing Web Applications
Form-based authentication is case sensitive for both the user name and password,
so enter the user name and password exactly as defined for GlassFish Server.
3.
Click Submit.
If you entered My_Name as the name and My_Pwd for the password, the server
returns the requested resource if all the following conditions are met.
■
■
■
■
A user with the user name My_Name is defined for GlassFish Server.
The user with the user name My_Name has a password My_Pwd defined for
GlassFish Server.
The user My_Name with the password My_Pwd is assigned to the group
TutorialUser on GlassFish Server.
The role TutorialUser, as defined for the application, is mapped to the group
TutorialUser, as defined for GlassFish Server.
When these conditions are met and the server has authenticated the user, the
application appears.
4.
Enter your name and click Submit.
Because you have already been authorized, the name you enter in this step does
not have any limitations. You have unlimited access to the application now.
The application responds by saying "Hello" to you.
Next Steps
For additional testing and to see the login error page generated, close and reopen your
browser, enter the application URL, and enter a user name and password that are not
authorized.
Getting Started Securing Web Applications 48-21
Examples: Securing Web Applications
48-22 The Java EE 7 Tutorial
49
Getting Started Securing Enterprise
Applications
49
This chapter describes how to administer security for enterprise applications.
The following topics are addressed here:
■
Basic Security Tasks for Enterprise Applications
■
Securing Enterprise Beans
■
Examples: Securing Enterprise Beans
49.1 Basic Security Tasks for Enterprise Applications
System administrators, application developers, bean providers, and deployers are
responsible for administering security for enterprise applications. The basic security
tasks are as follows:
■
Setting up a database of users and assigning them to the proper group
■
Setting up identity propagation
■
■
Setting GlassFish Server properties that enable the applications to run properly,
such as setting default principal-to-role mapping
Annotating the classes and methods of an enterprise application to provide
information about which methods need to have restricted access
The sections on the security examples in this chapter and the previous chapter explain
how to perform these tasks.
49.2 Securing Enterprise Beans
Enterprise beans are Java EE components that implement EJB technology. Enterprise
beans run in the EJB container, a runtime environment within GlassFish Server.
Although transparent to the application developer, the EJB container provides
system-level services, such as transactions and security to its enterprise beans, which
form the core of transactional Java EE applications.
Enterprise bean methods can be secured in either of the following ways.
■
Declarative security (preferred): Expresses an application component's security
requirements using either deployment descriptors or annotations. The presence of
an annotation in the business method of an enterprise bean class that specifies
method permissions is all that is needed for method protection and authentication
in some situations. This section discusses this simple and efficient method of
securing enterprise beans.
Getting Started Securing Enterprise Applications 49-1
Securing Enterprise Beans
Because of some limitations to the simplified method of securing enterprise beans,
you would want to continue to use the deployment descriptor to specify security
information in some instances. An authentication mechanism must be configured
on the server for the simple solution to work. Basic authentication is GlassFish
Server's default authentication method.
This tutorial explains how to invoke user name/password authentication of
authorized users by decorating the enterprise application's business methods with
annotations that specify method permissions.
To make the deployer's task easier, the application developer can define security
roles. A security role is a grouping of permissions that a given type of application
users must have in order to successfully use the application. For example, in a
payroll application, some users will want to view their own payroll information
(employee), some will need to view others' payroll information (manager), and
some will need to be able to change others' payroll information (payrollDept). The
application developer would determine the potential users of the application and
which methods would be accessible to which users. The application developer
would then decorate classes or methods of the enterprise bean with annotations
that specify the types of users authorized to access those methods. Using
annotations to specify authorized users is described in Specifying Authorized
Users by Declaring Security Roles.
When one of the annotations is used to define method permissions, the
deployment system will automatically require user name/password
authentication. In this type of authentication, a user is prompted to enter a user
name and password, which will be compared against a database of known users.
If the user is found and the password matches, the roles that the user is assigned
will be compared against the roles that are authorized to access the method. If the
user is authenticated and found to have a role that is authorized to access that
method, the data will be returned to the user.
Using declarative security is discussed in Securing an Enterprise Bean Using
Declarative Security.
■
Programmatic security: For an enterprise bean, code embedded in a business
method that is used to access a caller's identity programmatically and that uses
this information to make security decisions. Programmatic security is useful when
declarative security alone is not sufficient to express the security model of an
application.
In general, security management should be enforced by the container in a manner
that is transparent to the enterprise beans' business methods. The programmatic
security APIs described in this chapter should be used only in the less frequent
situations in which the enterprise bean business methods need to access the
security-context information, such as when you want to grant access based on the
time of day or other nontrivial condition checks for a particular role.
Programmatic security is discussed in Securing an Enterprise Bean
Programmatically.
Some of the material in this chapter assumes that you have already read Chapter 32,
"Enterprise Beans", Chapter 33, "Getting Started with Enterprise Beans", and
Chapter 47, "Introduction to Security in the Java EE Platform".
This section discusses securing a Java EE application where one or more modules,
such as EJB JAR files, are packaged into an EAR file, the archive file that holds the
application. Security annotations will be used in the Java programming class files to
specify authorized users and basic, or user name/password, authentication.
49-2 The Java EE 7 Tutorial
Securing Enterprise Beans
Enterprise beans often provide the business logic of a web application. In these cases,
packaging the enterprise bean within the web application's WAR module simplifies
deployment and application organization. Enterprise beans may be packaged within a
WAR module as Java class files or within a JAR file that is bundled within the WAR
module. When a servlet or JavaServer Faces page handles the web front end and the
application is packaged into a WAR module as a Java class file, security for the
application can be handled in the application's web.xml file. The EJB in the WAR file
can have its own deployment descriptor, ejb-jar.xml, if required. Securing web
applications using web.xml is discussed in Chapter 48, "Getting Started Securing Web
Applications".
The following sections describe declarative and programmatic security mechanisms
that can be used to protect enterprise bean resources. The protected resources include
enterprise bean methods that are called from application clients, web components, or
other enterprise beans.
For more information on this topic, read the Enterprise JavaBeans 3.2 specification.
This document can be downloaded from
http://jcp.org/en/jsr/detail?id=345. Chapter 12 of this specification,
"Security Management," discusses security management for enterprise beans.
49.2.1 Securing an Enterprise Bean Using Declarative Security
Declarative security enables the application developer to specify which users are
authorized to access which methods of the enterprise beans and to authenticate these
users with basic, or user name/password, authentication. Frequently, the person who
is developing an enterprise application is not the same person who is responsible for
deploying the application. An application developer who uses declarative security to
define method permissions and authentication mechanisms is passing along to the
deployer a security view of the enterprise beans contained in the EJB JAR. When a
security view is passed on to the deployer, he or she uses this information to define
method permissions for security roles. If you don't define a security view, the deployer
will have to determine what each business method does to determine which users are
authorized to call each method.
A security view consists of a set of security roles, a semantic grouping of permissions
that a given type of users of an application must have to successfully access the
application. Security roles are meant to be logical roles, representing a type of user.
You can define method permissions for each security role. A method permission is a
permission to invoke a specified group of methods of an enterprise bean's business
interface, home interface, component interface, and/or web service endpoints. After
method permissions are defined, user name/password authentication will be used to
verify the identity of the user.
It is important to keep in mind that security roles are used to define the logical security
view of an application. They should not be confused with the user groups, users,
principals, and other concepts that exist in GlassFish Server. An additional step is
required to map the roles defined in the application to users, groups, and principals
that are the components of the user database in the file realm of GlassFish Server.
These steps are outlined in Mapping Roles to Users and Groups.
The following sections show how an application developer uses declarative security to
either secure an application or to create a security view to pass along to the deployer.
49.2.1.1 Specifying Authorized Users by Declaring Security Roles
This section discusses how to use annotations to specify the method permissions for
the methods of a bean class. For more information on these annotations, refer to the
Getting Started Securing Enterprise Applications 49-3
Securing Enterprise Beans
Common Annotations for the Java Platform specification at
http://jcp.org/en/jsr/detail?id=250.
Method permissions can be specified on the class, the business methods of the class, or
both. Method permissions can be specified on a method of the bean class to override
the method permissions value specified on the entire bean class. The following
annotations are used to specify method permissions.
■
@DeclareRoles: Specifies all the roles that the application will use, including roles
not specifically named in a @RolesAllowed annotation. The set of security roles the
application uses is the total of the security roles defined in the @DeclareRoles and
@RolesAllowed annotations.
The @DeclareRoles annotation is specified on a bean class, where it serves to
declare roles that can be tested (for example, by calling isCallerInRole) from
within the methods of the annotated class. When declaring the name of a role used
as a parameter to the isCallerInRole(String roleName) method, the declared
name must be the same as the parameter value.
The following example code demonstrates the use of the @DeclareRoles
annotation:
@DeclareRoles("BusinessAdmin")
public class Calculator {
...
}
The syntax for declaring more than one role is as shown in the following example:
@DeclareRoles({"Administrator", "Manager", "Employee"})
■
@RolesAllowed("list-of-roles"): Specifies the security roles permitted to access
methods in an application. This annotation can be specified on a class or on one or
more methods. When specified at the class level, the annotation applies to all
methods in the class. When specified on a method, the annotation applies to that
method only and overrides any values specified at the class level.
To specify that no roles are authorized to access methods in an application, use the
@DenyAll annotation. To specify that a user in any role is authorized to access the
application, use the @PermitAll annotation.
When used in conjunction with the @DeclareRoles annotation, the combined set of
security roles is used by the application.
The following example code demonstrates the use of the @RolesAllowed
annotation:
@DeclareRoles({"Administrator", "Manager", "Employee"})
public class Calculator {
@RolesAllowed("Administrator")
public void setNewRate(int rate) {
...
}
}
■
@PermitAll: Specifies that all security roles are permitted to execute the specified
method or methods. The user is not checked against a database to ensure that he
or she is authorized to access this application.
49-4 The Java EE 7 Tutorial
Securing Enterprise Beans
This annotation can be specified on a class or on one or more methods. Specifying
this annotation on the class means that it applies to all methods of the class.
Specifying it at the method level means that it applies to only that method.
The following example code demonstrates the use of the @PermitAll annotation:
import javax.annotation.security.*;
@RolesAllowed("RestrictedUsers")
public class Calculator {
@RolesAllowed("Administrator")
public void setNewRate(int rate) {
//...
}
@PermitAll
public long convertCurrency(long amount) {
//...
}
}
■
@DenyAll: Specifies that no security roles are permitted to execute the specified
method or methods. This means that these methods are excluded from execution
in the Java EE container.
The following example code demonstrates the use of the @DenyAll annotation:
import javax.annotation.security.*;
@RolesAllowed("Users")
public class Calculator {
@RolesAllowed("Administrator")
public void setNewRate(int rate) {
//...
}
@DenyAll
public long convertCurrency(long amount) {
//...
}
}
The following code snippet demonstrates the use of the @DeclareRoles annotation
with the isCallerInRole method. In this example, the @DeclareRoles annotation
declares a role that the enterprise bean PayrollBean uses to make the security check by
using isCallerInRole("payroll") to verify that the caller is authorized to change
salary data:
@DeclareRoles("payroll")
@Stateless public class PayrollBean implements Payroll {
@Resource SessionContext ctx;
public void updateEmployeeInfo(EmplInfo info) {
oldInfo = ... read from database;
// The salary field can be changed only by callers
// who have the security role "payroll"
Principal callerPrincipal = ctx.getCallerPrincipal();
if (info.salary != oldInfo.salary && !ctx.isCallerInRole("payroll")) {
throw new SecurityException(...);
}
...
}
Getting Started Securing Enterprise Applications 49-5
Securing Enterprise Beans
...
}
The following example code illustrates the use of the @RolesAllowed annotation:
@RolesAllowed("admin")
public class SomeClass {
public void aMethod () {...}
public void bMethod () {...}
...
}
@Stateless public class MyBean extends SomeClass implements A
{
@RolesAllowed("HR")
public void aMethod () {...}
public void cMethod () {...}
...
}
In this example, assuming that aMethod, bMethod, and cMethod are methods of
business interface A, the method permissions values of methods aMethod and bMethod
are @RolesAllowed("HR") and @RolesAllowed("admin"), respectively. The method
permissions for method cMethod have not been specified.
To clarify, the annotations are not inherited by the subclass itself. Instead, the
annotations apply to methods of the superclass that are inherited by the subclass.
49.2.1.2 Specifying an Authentication Mechanism and Secure Connection
When method permissions are specified, basic user name/password authentication
will be invoked by GlassFish Server.
To use a different type of authentication or to require a secure connection using SSL,
specify this information in an application deployment descriptor.
49.2.2 Securing an Enterprise Bean Programmatically
Programmatic security, code that is embedded in a business method, is used to access
a caller's identity programmatically and uses this information to make security
decisions within the method itself.
49.2.2.1 Accessing an Enterprise Bean Caller's Security Context
In general, security management should be enforced by the container in a manner that
is transparent to the enterprise bean's business methods. The security API described in
this section should be used only in the less frequent situations in which the enterprise
bean business methods need to access the security context information, such as when
you want to restrict access to a particular time of day.
The javax.ejb.EJBContext interface provides two methods that allow the bean
provider to access security information about the enterprise bean's caller.
■
getCallerPrincipal allows the enterprise bean methods to obtain the current
caller principal's name. The methods might, for example, use the name as a key to
information in a database.
The following code sample illustrates the use of the getCallerPrincipal method:
@Stateless public class EmployeeServiceBean implements EmployeeService {
49-6 The Java EE 7 Tutorial
Securing Enterprise Beans
@Resource SessionContext ctx;
@PersistenceContext EntityManager em;
public void changePhoneNumber(...) {
...
// obtain the caller principal
callerPrincipal = ctx.getCallerPrincipal();
// obtain the caller principal's name
callerKey = callerPrincipal.getName();
// use callerKey as primary key to find EmployeeRecord
EmployeeRecord myEmployeeRecord =
em.find(EmployeeRecord.class, callerKey);
// update phone number
myEmployeeRecord.setPhoneNumber(...);
...
}
}
In this example, the enterprise bean obtains the principal name of the current
caller and uses it as the primary key to locate an EmployeeRecord entity. This
example assumes that application has been deployed such that the current caller
principal contains the primary key used for the identification of employees (for
example, employee number).
■
isCallerInRole allows the developer to code the security checks that cannot be
easily defined using method permissions. Such a check might impose a role-based
limit on a request, or it might depend on information stored in the database.
The enterprise bean code can use the isCallerInRole method to test whether the
current caller has been assigned to a given security role. Security roles are defined
by the bean provider or the application assembler and are assigned by the
deployer to principals or principal groups that exist in the operational
environment.
The following code sample illustrates the use of the isCallerInRole method:
@Stateless public class PayrollBean implements Payroll {
@Resource SessionContext ctx;
public void updateEmployeeInfo(EmplInfo info) {
oldInfo = ... read from database;
// The salary field can be changed only by callers
// who have the security role "payroll"
if (info.salary != oldInfo.salary &&
!ctx.isCallerInRole("payroll")) {
throw new SecurityException(...);
}
...
}
...
}
You would use programmatic security in this way to dynamically control access to a
method, for example, when you want to deny access except during a particular time of
day. An example application that uses the getCallerPrincipal and isCallerInRole
Getting Started Securing Enterprise Applications 49-7
Securing Enterprise Beans
methods is described in The converter-secure Example: Securing an Enterprise Bean
with Programmatic Security.
49.2.3 Propagating a Security Identity (Run-As)
You can specify whether a caller's security identity should be used for the execution of
specified methods of an enterprise bean or whether a specific run-as identity should be
used. Figure 49–1 illustrates this concept.
Figure 49–1 Security Identity Propagation
Application Client
or Web Client
Initiating Client
Java EE
Security
Identity
EJB or Web
Container
Intermediate
Propagated
Security Identity
(Java EE)
EJB
Container
Target
In this illustration, an application client is making a call to an enterprise bean method
in one EJB container. This enterprise bean method, in turn, makes a call to an
enterprise bean method in another container. The security identity during the first call
is the identity of the caller. The security identity during the second call can be any of
the following options.
■
■
By default, the identity of the caller of the intermediate component is propagated
to the target enterprise bean. This technique is used when the target container
trusts the intermediate container.
A specific identity is propagated to the target enterprise bean. This technique is
used when the target container expects access using a specific identity.
To propagate an identity to the target enterprise bean, configure a run-as identity for
the bean, as described in Configuring a Component's Propagated Security Identity.
Establishing a run-as identity for an enterprise bean does not affect the identities of its
callers, which are the identities tested for permission to access the methods of the
enterprise bean. The run-as identity establishes the identity that the enterprise bean
will use when it makes calls.
The run-as identity applies to the enterprise bean as a whole, including all the
methods of the enterprise bean's business interface, local and remote interfaces,
component interface, and web service endpoint interfaces, the message listener
methods of a message-driven bean, the timeout method of an enterprise bean, and all
internal methods of the bean that might be called in turn.
49.2.3.1 Configuring a Component's Propagated Security Identity
You can configure an enterprise bean's run-as, or propagated, security identity by
using the @RunAs annotation, which defines the role of the application during
execution in a Java EE container. The annotation can be specified on a class, allowing
developers to execute an application under a particular role. The role must map to the
user/group information in the container's security realm. The @RunAs annotation
specifies the name of a security role as its parameter.
The following code demonstrates the use of the @RunAs annotation:
@RunAs("Admin")
public class Calculator {
//....
}
49-8 The Java EE 7 Tutorial
Examples: Securing Enterprise Beans
You will have to map the run-as role name to a given principal defined in GlassFish
Server if the given roles are associated with more than one user principal.
49.2.3.2 Trust between Containers
When an enterprise bean is designed so that either the original caller identity or a
designated identity is used to call a target bean, the target bean will receive the
propagated identity only. The target bean will not receive any authentication data.
There is no way for the target container to authenticate the propagated security
identity. However, because the security identity is used in authorization checks (for
example, method permissions or with the isCallerInRole method), it is vitally
important that the security identity be authentic. Because no authentication data is
available to authenticate the propagated identity, the target must trust that the calling
container has propagated an authenticated security identity.
By default, GlassFish Server is configured to trust identities that are propagated from
different containers. Therefore, you do not need to take any special steps to set up a
trust relationship.
49.2.4 Deploying Secure Enterprise Beans
The deployer is responsible for ensuring that an assembled application is secure after
it has been deployed in the target operational environment. If a security view has been
provided to the deployer through the use of security annotations and/or a
deployment descriptor, the security view is mapped to the mechanisms and policies
used by the security domain in the target operational environment, which in this case
is GlassFish Server. If no security view is provided, the deployer must set up the
appropriate security policy for the enterprise bean application.
Deployment information is specific to a web or application server.
49.3 Examples: Securing Enterprise Beans
The following examples show how to secure enterprise beans using declarative and
programmatic security.
49.3.1 The cart-secure Example: Securing an Enterprise Bean with Declarative Security
This section discusses how to configure an enterprise bean for basic user
name/password authentication. When a bean that is constrained in this way is
requested, the server requests a user name and password from the client and verifies
that the user name and password are valid by comparing them against a database of
authorized users in GlassFish Server.
If the topic of authentication is new to you, see Specifying Authentication
Mechanisms.
This example demonstrates security by starting with the unsecured enterprise bean
application, cart, which is found in the tut-install/examples/ejb/cart/ directory and
is discussed in The cart Example.
In general, the following steps are necessary to add user name/password
authentication to an existing application that contains an enterprise bean. In the
example application included with this tutorial, these steps have been completed for
you and are listed here simply to show what needs to be done should you wish to
create a similar application.
Getting Started Securing Enterprise Applications 49-9
Examples: Securing Enterprise Beans
1.
Create an application like the one in The cart Example. The example in this tutorial
starts with this example and demonstrates adding basic authentication of the
client to this application. The example application discussed in this section can be
found at tut-install/examples/security/cart-secure/.
2.
If you have not already done so, complete the steps in To Set Up Your System for
Running the Security Examples to configure your system for running the tutorial
applications.
3.
Modify the source code for the enterprise bean, CartBean.java, to specify which
roles are authorized to access which protected methods. This step is discussed in
Annotating the Bean.
4.
Build, package, and deploy the enterprise bean; then build and run the client
application by following the steps in To Run the cart-secure Example Using
NetBeans IDE or To Run the cart-secure Example Using Maven.
49.3.1.1 Annotating the Bean
The source code for the original cart application was modified as shown in the
following code snippet (modifications in bold). The resulting file can be found in the
file
tut-install/examples/security/cart-secure/cart-secure-ejb/src/main/java/javae
etutorial/cart/ejb/CartBean.java.
The code snippet is as follows:
package javaeetutorial.cartsecure.ejb;
import
import
import
import
import
import
import
import
import
java.io.Serializable;
java.util.ArrayList;
java.util.List;
javaeetutorial.cart.util.BookException;
javaeetutorial.cart.util.IdVerifier;
javax.ejb.Remove;
javax.ejb.Stateful;
javax.annotation.security.DeclareRoles;
javax.annotation.security.RolesAllowed;
@Stateful
@DeclareRoles("TutorialUser")
public class CartBean implements Cart, Serializable {
List<String> contents;
String customerId;
String customerName;
@Override
public void initialize(String person) throws BookException {
if (person == null) {
throw new BookException("Null person not allowed.");
} else {
customerName = person;
}
customerId = "0";
contents = new ArrayList<>();
}
@Override
public void initialize(String person, String id) throws BookException {
if (person == null) {
49-10 The Java EE 7 Tutorial
Examples: Securing Enterprise Beans
throw new BookException("Null person not allowed.");
} else {
customerName = person;
}
IdVerifier idChecker = new IdVerifier();
if (idChecker.validate(id)) {
customerId = id;
} else {
throw new BookException("Invalid id: " + id);
}
contents = new ArrayList<>();
}
@Override
@RolesAllowed("TutorialUser")
public void addBook(String title) {
contents.add(title);
}
@Override
@RolesAllowed("TutorialUser")
public void removeBook(String title) throws BookException {
boolean result = contents.remove(title);
if (result == false) {
throw new BookException("\"" + title + "\" not in cart.");
}
}
@Override
@RolesAllowed("TutorialUser")
public List<String> getContents() {
return contents;
}
@Override
@Remove()
@RolesAllowed("TutorialUser")
public void remove() {
contents = null;
}
}
The @RolesAllowed annotation is specified on methods for which you want to restrict
access. In this example, only users in the role of TutorialUser will be allowed to add
and remove books from the cart and to list the contents of the cart. A @RolesAllowed
annotation implicitly declares a role that will be referenced in the application;
therefore, no @DeclareRoles annotation is required. The presence of the
@RolesAllowed annotation also implicitly declares that authentication will be required
for a user to access these methods. If no authentication method is specified in the
deployment descriptor, the type of authentication will be user name/password
authentication.
49.3.1.2 To Run the cart-secure Example Using NetBeans IDE
1.
Follow the steps in To Set Up Your System for Running the Security Examples.
Getting Started Securing Enterprise Applications 49-11
Examples: Securing Enterprise Beans
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/security
4.
Select the cart-secure folder.
5.
Select the Open Required Projects check box.
6.
Click Open Project.
7.
In the Projects tab, right-click the cart-secure project and select Build.
This step builds and packages the application into cart-secure.ear, located in the
cart-secure-ear/target/ directory, and deploys this EAR file to your GlassFish
Server instance, retrieves the client stubs, and runs the client.
8.
In the Login for user: dialog box, enter the user name and password of a file
realm user created in GlassFish Server and assigned to the group TutorialUser;
then click OK.
If the user name and password you enter are authenticated, the output of the
application client appears in the Output tab:
...
Retrieving book title from cart: Infinite Jest
Retrieving book title from cart: Bel Canto
Retrieving book title from cart: Kafka on the Shore
Removing "Gravity's Rainbow" from cart.
Caught a BookException: "Gravity's Rainbow" not in cart.
Java Result: 1
...
If the user name and password are not authenticated, the dialog box reappears
until you enter correct values.
49.3.1.3 To Run the cart-secure Example Using Maven
1.
Follow the steps in To Set Up Your System for Running the Security Examples.
2.
In a terminal window, go to:
tut-install/examples/security/cart-secure/
3.
To build the application, package it into an EAR file in the
cart-secure-ear/target subdirectory, deploy it, and run it, enter the following
command at the terminal window or command prompt:
mvn install
4.
In the Login for user: dialog box, enter the user name and password of a file
realm user created in GlassFish Server and assigned to the group TutorialUser;
then click OK.
If the user name and password you enter are authenticated, the output of the
application client appears in the Output tab:
...
Retrieving book title from cart: Infinite Jest
Retrieving book title from cart: Bel Canto
Retrieving book title from cart: Kafka on the Shore
Removing "Gravity's Rainbow" from cart.
Caught a BookException: "Gravity's Rainbow" not in cart.
49-12 The Java EE 7 Tutorial
Examples: Securing Enterprise Beans
Java Result: 1
...
If the user name and password are not authenticated, the dialog box reappears
until you enter correct values.
49.3.2 The converter-secure Example: Securing an Enterprise Bean with Programmatic
Security
This example demonstrates how to use the getCallerPrincipal and isCallerInRole
methods with an enterprise bean. This example starts with a very simple EJB
application, converter, and modifies the methods of the ConverterBean so that
currency conversion will occur only when the requester is in the role of TutorialUser.
This example can be found in the tut-install/examples/security/converter-secure
directory. This example is based on the unsecured enterprise bean application,
converter, which is discussed in Chapter 33, "Getting Started with Enterprise Beans"
and is found in the tut-install/examples/ejb/converter/ directory. This section builds
on the example by adding the necessary elements to secure the application by using
the getCallerPrincipal and isCallerInRole methods, which are discussed in more
detail in Accessing an Enterprise Bean Caller's Security Context.
In general, the following steps are necessary when using the getCallerPrincipal and
isCallerInRole methods with an enterprise bean. In the example application
included with this tutorial, many of these steps have been completed for you and are
listed here simply to show what needs to be done should you wish to create a similar
application.
1.
Create a simple enterprise bean application.
2.
Set up a user on GlassFish Server in the file realm, in the group TutorialUser,
and set up default principal to role mapping. To do this, follow the steps in To Set
Up Your System for Running the Security Examples.
3.
Modify the bean to add the getCallerPrincipal and isCallerInRole methods.
4.
If the application contains a web client that is a servlet, specify security for the
servlet, as described in Specifying Security for Basic Authentication Using
Annotations.
5.
Build, package, deploy, and run the application.
49.3.2.1 Modifying ConverterBean
The source code for the original ConverterBean class was modified to add the
if..else clause that tests whether the caller is in the role of TutorialUser. If the user
is in the correct role, the currency conversion is computed and displayed. If the user is
not in the correct role, the computation is not performed, and the application displays
the result as 0. The code example can be found in
tut-install/examples/security/converter-secure/converter-secure-ejb/src/main/
java/javaeetutorial/converter/ejb/ConverterBean.java.
The code snippet (with modifications shown in bold) is as follows:
package javaeetutorial.convertersecure.ejb;
import
import
import
import
import
java.math.BigDecimal;
java.security.Principal;
javax.ejb.Stateless;
javax.annotation.Resource;
javax.ejb.SessionContext;
Getting Started Securing Enterprise Applications 49-13
Examples: Securing Enterprise Beans
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
@Stateless()
@DeclareRoles("TutorialUser")
public class ConverterBean{
@Resource SessionContext ctx;
private final BigDecimal yenRate = new BigDecimal("104.34");
private final BigDecimal euroRate = new BigDecimal("0.007");
@RolesAllowed("TutorialUser")
public BigDecimal dollarToYen(BigDecimal dollars) {
BigDecimal result = new BigDecimal("0.0");
Principal callerPrincipal = ctx.getCallerPrincipal();
if (ctx.isCallerInRole("TutorialUser")) {
result = dollars.multiply(yenRate);
return result.setScale(2, BigDecimal.ROUND_UP);
} else {
return result.setScale(2, BigDecimal.ROUND_UP);
}
}
@RolesAllowed("TutorialUser")
public BigDecimal yenToEuro(BigDecimal yen) {
BigDecimal result = new BigDecimal("0.0");
Principal callerPrincipal = ctx.getCallerPrincipal();
if (ctx.isCallerInRole("TutorialUser")) {
result = yen.multiply(euroRate);
return result.setScale(2, BigDecimal.ROUND_UP);
} else {
return result.setScale(2, BigDecimal.ROUND_UP);
}
}
}
49.3.2.2 Modifying ConverterServlet
The following annotations specify security for the converter web client,
ConverterServlet:
@WebServlet(urlPatterns = {"/"})
@ServletSecurity(
@HttpConstraint(transportGuarantee = TransportGuarantee.CONFIDENTIAL,
rolesAllowed = {"TutorialUser"}))
49.3.2.3 To Run the converter-secure Example Using NetBeans IDE
1.
Follow the steps in To Set Up Your System for Running the Security Examples.
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/security
4.
Select the converter-secure folder.
5.
Click Open Project.
6.
Right-click the converter-secure project and select Build.
49-14 The Java EE 7 Tutorial
Examples: Securing Enterprise Beans
This command builds and deploys the example application to your GlassFish
Server instance.
49.3.2.4 To Run the converter-secure Example Using Maven
1.
Follow the steps in To Set Up Your System for Running the Security Examples.
2.
In a terminal window, go to:
tut-install/examples/security/converter-secure/
3.
Enter the following command:
mvn install
This command builds and packages the application into a WAR file,
converter-secure.war, that is located in the target directory, and deploys the
WAR file.
49.3.2.5 To Run the converter-secure Example
1.
Open a web browser to the following URL:
http://localhost:8080/converter-secure
An Authentication Required dialog box appears.
2.
Enter a user name and password combination that corresponds to a user who has
already been created in the file realm of GlassFish Server and has been assigned
to the group TutorialUser; then click OK.
3.
Enter 100 in the input field and click Submit.
A second page appears, showing the converted values.
Getting Started Securing Enterprise Applications 49-15
Examples: Securing Enterprise Beans
49-16 The Java EE 7 Tutorial
50
Java EE Security: Advanced Topics
50
This chapter provides advanced information on securing Java EE applications.
The following topics are addressed here:
■
Working with Digital Certificates
■
Authentication Mechanisms
■
Using the JDBC Realm for User Authentication
■
Securing HTTP Resources
■
Securing Application Clients
■
Securing Enterprise Information Systems Applications
■
Configuring Security Using Deployment Descriptors
■
Further Information about Advanced Security Topics
50.1 Working with Digital Certificates
Digital certificates for GlassFish Server have already been generated and can be found
in the directory domain-dir/config/. These digital certificates are self-signed and are
intended for use in a development environment; they are not intended for production
purposes. For production purposes, generate your own certificates and have them
signed by a Certificate Authority (CA).
To use the Secure Sockets Layer (SSL), an application or web server must have an
associated certificate for each external interface, or IP address, that accepts secure
connections. The theory behind this design is that a server should provide some kind
of reasonable assurance that its owner is who you think it is, particularly before
receiving any sensitive information. It may be useful to think of a certificate as a
"digital driver's license" for an Internet address. The certificate states with which
company the site is associated, along with some basic contact information about the
site owner or administrator.
The digital certificate is cryptographically signed by its owner and is difficult for
anyone else to forge. For sites involved in e-commerce or in any other business
transaction in which authentication of identity is important, a certificate can be
purchased from a well-known CA such as VeriSign or Thawte. If your server certificate
is self-signed, you must install it in the GlassFish Server keystore file (keystore.jks).
If your client certificate is self-signed, you should install it in the GlassFish Server
truststore file (cacerts.jks).
Sometimes, authentication is not really a concern. For example, an administrator might
simply want to ensure that data being transmitted and received by the server is private
Java EE Security: Advanced Topics 50-1
Working with Digital Certificates
and cannot be snooped by anyone eavesdropping on the connection. In such cases,
you can save the time and expense involved in obtaining a CA certificate and simply
use a self-signed certificate.
SSL uses public-key cryptography, which is based on key pairs. Key pairs contain one
public key and one private key. Data encrypted with one key can be decrypted only
with the other key of the pair. This property is fundamental to establishing trust and
privacy in transactions. For example, using SSL, the server computes a value and
encrypts it by using its private key. The encrypted value is called a digital signature.
The client decrypts the encrypted value by using the server's public key and compares
the value to its own computed value. If the two values match, the client can trust that
the signature is authentic, because only the private key could have been used to
produce such a signature.
Digital certificates are used with HTTPS to authenticate web clients. The HTTPS
service of most web servers will not run unless a digital certificate has been installed.
Use the procedure outlined in the next section, Creating a Server Certificate, to set up a
digital certificate that can be used by your application or web server to enable SSL.
One tool that can be used to set up a digital certificate is keytool, a key and certificate
management utility that ships with the JDK. This tool enables users to administer their
own public/private key pairs and associated certificates for use in self-authentication,
whereby the user authenticates himself or herself to other users or services, or data
integrity and authentication services, using digital signatures. The tool also allows
users to cache the public keys, in the form of certificates, of their communicating peers.
For a better understanding of keytool and public-key cryptography, see Further
Information about Advanced Security Topics for a link to the keytool documentation.
50.1.1 Creating a Server Certificate
A server certificate has already been created for GlassFish Server and can be found in
the domain-dir/config/ directory. The server certificate is in keystore.jks. The
cacerts.jks file contains all the trusted certificates, including client certificates.
If necessary, you can use keytool to generate certificates. The keytool utility stores the
keys and certificates in a file termed a keystore, a repository of certificates used for
identifying a client or a server. Typically, a keystore is a file that contains one client's or
one server's identity. The keystore protects private keys by using a password.
If you don't specify a directory when specifying the keystore file name, the keystores
are created in the directory from which the keytool command is run. This can be the
directory where the application resides, or it can be a directory common to many
applications.
The general steps for creating a server certificate are as follows.
1.
Create the keystore.
2.
Export the certificate from the keystore.
3.
Sign the certificate.
4.
Import the certificate into a truststore: a repository of certificates used for
verifying the certificates. A truststore typically contains more than one certificate.
The next section provides specific information on using the keytool utility to perform
these steps.
50-2 The Java EE 7 Tutorial
Working with Digital Certificates
50.1.1.1 To Use keytool to Create a Server Certificate
Run keytool to generate a new key pair in the default development keystore file,
keystore.jks. This example uses the alias server-alias to generate a new
public/private key pair and wrap the public key into a self-signed certificate inside
keystore.jks. The key pair is generated by using an algorithm of type RSA, with a
default password of changeit. For more information and other examples of creating
and managing keystore files, read the keytool documentation.
RSA is public-key encryption technology developed by RSA
Data Security, Inc.
Note:
From the directory in which you want to create the key pair, run keytool as shown in
the following steps.
1.
Generate the server certificate.
Enter the keytool command all on one line:
java-home/bin/keytool -genkey -alias server-alias -keyalg RSA
-keypass changeit -storepass changeit -keystore keystore.jks
When you press Enter, keytool prompts you to enter the server name,
organizational unit, organization, locality, state, and country code.
You must enter the server name in response to keytool's first prompt, in which it
asks for first and last names. For testing purposes, this can be localhost.
2.
Export the generated server certificate in keystore.jks into the file server.cer.
Enter the keytool command all on one line:
java-home/bin/keytool -export -alias server-alias -storepass changeit
-file server.cer -keystore keystore.jks
3.
If you want to have the certificate signed by a CA, read the example in the keytool
documentation.
4.
To add the server certificate to the truststore file, cacerts.jks, run keytool from
the directory where you created the keystore and server certificate.
Use the following parameters:
java-home/bin/keytool -import -v -trustcacerts -alias server-alias
-file server.cer -keystore cacerts.jks -keypass changeit
-storepass changeit
Information on the certificate, such as that shown next, will appear:
Owner: CN=localhost, OU=My Company, O=Software, L=Santa Clara, ST=CA, C=US
Issuer: CN=localhost, OU=My Company, O=Software, L=Santa Clara, ST=CA, C=US
Serial number: 3e932169
Valid from: Mon Nov 26 18:15:47 EST 2012 until: Sun Feb 24 18:15:47 EST 2013
Certificate fingerprints:
MD5: 52:9F:49:68:ED:78:6F:39:87:F3:98:B3:6A:6B:0F:90
SHA1: EE:2E:2A:A6:9E:03:9A:3A:1C:17:4A:28:5E:97:20:78:3F:
SHA256: 80:05:EC:7E:50:50:5D:AA:A3:53:F1:11:9B:19:EB:0D:20:67:C1:12:
AF:42:EC:CD:66:8C:BD:99:AD:D9:76:95
Signature algorithm name: SHA256withRSA
Version: 3
...
Trust this certificate? [no]:
Java EE Security: Advanced Topics 50-3
Working with Digital Certificates
5.
Enter yes, then press the Enter or Return key.
The following information appears:
Certificate was added to keystore
[Storing cacerts.jks]
50.1.2 Adding Users to the Certificate Realm
In the certificate realm, user identity is set up in the GlassFish Server security
context and populated with user data obtained from cryptographically verified client
certificates. For step-by-step instructions for creating this type of certificate, see
Working with Digital Certificates.
50.1.3 Using a Different Server Certificate with GlassFish Server
Follow the steps in Creating a Server Certificate to create your own server certificate,
have it signed by a CA, and import the certificate into keystore.jks.
Make sure that when you create the certificate, you follow these rules.
■
■
When you create the server certificate, keytool prompts you to enter your first
and last name. In response to this prompt, you must enter the name of your server.
For testing purposes, this can be localhost.
If you want to replace the existing keystore.jks, you must either change your
keystore's password to the default password (changeit) or change the default
password to your keystore's password.
50.1.3.1 To Specify a Different Server Certificate
To specify that GlassFish Server should use the new keystore for authentication and
authorization decisions, you must set the JVM options for GlassFish Server so that
they recognize the new keystore. To use a different keystore from the one provided for
development purposes, follow these steps.
1.
Start GlassFish Server if you haven't already done so. Information on starting the
GlassFish Server can be found in Starting and Stopping GlassFish Server.
2.
Open the GlassFish Server Administration Console in a web browser at
http://localhost:4848.
3.
Expand Configurations, then expand server-config, then click JVM Settings.
4.
Click the JVM Options tab.
5.
Change the following JVM options so that they point to the location and name of
the new keystore. The current settings are shown below:
-Djavax.net.ssl.keyStore=${com.sun.aas.instanceRoot}/config/keystore.jks
-Djavax.net.ssl.trustStore=${com.sun.aas.instanceRoot}/config/cacerts.jks
6.
If you've changed the keystore password from its default value, you need to add
the password option as well:
-Djavax.net.ssl.keyStorePassword=your-new-password
7.
Click Save, then restart GlassFish Server.
50-4 The Java EE 7 Tutorial
Authentication Mechanisms
50.2 Authentication Mechanisms
This section discusses the client authentication and mutual authentication
mechanisms.
50.2.1 Client Authentication
With client authentication, the web server authenticates the client by using the client's
public key certificate. Client authentication is a more secure method of authentication
than either basic or form-based authentication. It uses HTTP over SSL (HTTPS), in
which the server authenticates the client using the client's public key certificate. SSL
technology provides data encryption, server authentication, message integrity, and
optional client authentication for a TCP/IP connection. You can think of a public key
certificate as the digital equivalent of a passport. The certificate is issued by a trusted
organization, a certificate authority (CA), and provides identification for the bearer.
Before using client authentication, make sure that the client has a valid public key
certificate. For more information on creating and using public key certificates, read
Working with Digital Certificates.
The following example shows how to declare client authentication in your deployment
descriptor:
<login-config>
<auth-method>CLIENT-CERT</auth-method>
</login-config>
50.2.2 Mutual Authentication
With mutual authentication, the server and the client authenticate each other. Mutual
authentication is of two types:
■
Certificate-based (see Figure 50–1)
■
User name/password-based (see Figure 50–2)
When using certificate-based mutual authentication, the following actions occur.
1.
A client requests access to a protected resource.
2.
The web server presents its certificate to the client.
3.
The client verifies the server's certificate.
4.
If successful, the client sends its certificate to the server.
5.
The server verifies the client's credentials.
6.
If successful, the server grants access to the protected resource requested by the
client.
Figure 50–1 shows what occurs during certificate-based mutual authentication.
Java EE Security: Advanced Topics 50-5
Authentication Mechanisms
Figure 50–1 Certificate-Based Mutual Authentication
trustStore
client.cert
3
server.cert
5
Verifies
certificate
Client
Verifies
certificate
1 Requests protected resource
Presents certificate
Server
2
4 Presents certificate
Accesses protected resource 6
client.keystore
server.keystore
client.cert
server.cert
In user name/password-based mutual authentication, the following actions occur.
1.
A client requests access to a protected resource.
2.
The web server presents its certificate to the client.
3.
The client verifies the server's certificate.
4.
If successful, the client sends its user name and password to the server.
5.
The server verifies the client's credentials
6.
If the verification is successful, the server grants access to the protected resource
requested by the client.
Figure 50–2 shows what occurs during user name/password-based mutual
authentication.
50-6 The Java EE 7 Tutorial
Authentication Mechanisms
Figure 50–2 User Name/Password-Based Mutual Authentication
trustStore
server.keystore
server.cert
server.cert
3
5
Verifies
certificate
Verifies
certificate
Client
1 Requests protected resource
Server
Presents certificate
2
4 Sends username:password
Accesses protected resource 6
50.2.2.1 Enabling Mutual Authentication over SSL
This section discusses setting up client-side authentication. Enabling both server-side
and client-side authentication is called mutual, or two-way, authentication. In client
authentication, clients are required to submit certificates issued by a certificate
authority that you choose to accept.
There are at least two ways to enable mutual authentication over SSL.
■
■
The preferred method is to set the method of authentication in the web.xml
application deployment descriptor to CLIENT-CERT. This enforces mutual
authentication by modifying the deployment descriptor of the given application.
In this way, client authentication is enabled only for a specific resource controlled
by the security constraint, and the check is performed only when the application
requires client authentication.
A less commonly used method is to set the clientAuth property in the
certificate realm to true if you want the SSL stack to require a valid certificate
chain from the client before accepting a connection. A false value (which is the
default) will not require a certificate chain unless the client requests a resource
protected by a security constraint that uses CLIENT-CERT authentication. When you
enable client authentication by setting the clientAuth property to true, client
authentication will be required for all the requests going through the specified SSL
port. If you turn clientAuth on, it is on all of the time, which can severely degrade
performance.
When client authentication is enabled in both of these ways, client authentication will
be performed twice.
50.2.2.2 Creating a Client Certificate for Mutual Authentication
If you have a certificate signed by a trusted Certificate Authority (CA) such as
Verisign, and the GlassFish Server cacerts.jks file already contains a certificate
verified by that CA, you do not need to complete this step. You need to install your
certificate in the GlassFish Server certificate file only when your certificate is
self-signed.
Java EE Security: Advanced Topics 50-7
Authentication Mechanisms
From the directory where you want to create the client certificate, run keytool as
outlined here. When you press Enter, keytool prompts you to enter the server name,
organizational unit, organization, locality, state, and country code.
You must enter the server name in response to keytool's first prompt, in which it asks
for first and last names. For testing purposes, this can be localhost. If this example is
to verify mutual authentication and you receive a runtime error stating that the HTTPS
host name is wrong, re-create the client certificate, being sure to use the same host
name you will use when running the example. For example, if your machine name is
duke, then enter duke as the certificate CN or when prompted for first and last names.
When accessing the application, enter a URL that points to the same location (for
example, https://duke:8181/mutualauth/hello). This is necessary because during
SSL handshake, the server verifies the client certificate by comparing the certificate
name to the host name from which it originates.
To create a keystore named client_keystore.jks that contains a client certificate
named client.cer, follow these steps.
1.
Create a backup copy of the server truststore file. To do this,
a.
Change to the directory containing the server's keystore and truststore files,
domain-dir\config.
b.
Copy cacerts.jks to cacerts.backup.jks.
c.
Copy keystore.jks to keystore.backup.jks.
Do not put client certificates in the cacerts.jks file. Any certificate you add to
the cacerts file effectively can be a trusted root for any and all certificate
chains. After you have completed development, delete the development
version of the cacerts file and replace it with the original copy.
2.
Generate the client certificate. Enter the following command from the directory
where you want to generate the client certificate:
java-home\bin\keytool -genkey -alias client-alias -keyalg RSA
-keypass changeit -storepass changeit -keystore client_keystore.jks
3.
Export the generated client certificate into the file client.cer:
java-home\bin\keytool -export -alias client-alias -storepass changeit
-file client.cer -keystore client_keystore.jks
4.
Add the certificate to the truststore file domain-dir/config/cacerts.jks. Run
keytool from the directory where you created the keystore and client certificate.
Use the following parameters:
java-home\bin\keytool -import -v -trustcacerts -alias client-alias
-file client.cer -keystore domain-dir/config/cacerts.jks
-keypass changeit -storepass changeit
The keytool utility returns a message like this one:
Owner: CN=localhost, OU=My Company, O=Software, L=Santa Clara, ST=CA, C=US
Issuer: CN=localhost, OU=My Company, O=Software, L=Santa Clara, ST=CA, C=US
Serial number: 3e39e66a
Valid from: Tue Nov 27 12:22:47 EST 2012 until: Mon Feb 25 12:22:47 EST 2013
Certificate fingerprints:
MD5: 5A:B0:4C:88:4E:F8:EF:E9:E5:8B:53:BD:D0:AA:8E:5A
SHA1:90:00:36:5B:E0:A7:A2:BD:67:DB:EA:37:B9:61:3E:26:B3:89:46:32
Signature algorithm name: SHA1withRSA
Version: 3
Trust this certificate? [no]: yes
50-8 The Java EE 7 Tutorial
Using the JDBC Realm for User Authentication
Certificate was added to keystore
[Storing cacerts.jks]
5.
Restart GlassFish Server.
50.3 Using the JDBC Realm for User Authentication
An authentication realm, sometimes called a security policy domain or security domain, is
a scope over which an application server defines and enforces a common security
policy. A realm contains a collection of users, who may or may not be assigned to a
group. GlassFish Server comes preconfigured with the file, certificate, and
administration realms. An administrator can also set up LDAP, JDBC, digest, or
custom realms.
An application can specify in its deployment descriptor which realm to use. If the
application does not specify a realm, GlassFish Server uses its default realm, the file
realm. If an application specifies that a JDBC realm is to be used for user
authentication, GlassFish Server will retrieve user credentials from a database. The
application server uses the database information and the enabled JDBC realm option
in the configuration file.
A database provides an easy way to add, edit, or delete users at runtime and enables
users to create their own accounts without any administrative assistance. Using a
database has an additional benefit: providing a place to securely store any extra user
information. A realm can be thought of as a database of user names and passwords
that identify valid users of a web application or set of web applications with an
enumeration of the list of roles associated with each valid user. Access to specific web
application resources is granted to all users in a particular role, instead of enumerating
a list of associated users. A user name can have any number of roles associated with it.
Two of the tutorial case studies, Chapter 58, "Duke's Tutoring Case Study Example,"
and Chapter 59, "Duke's Forest Case Study Example," use a JDBC realm for user
authentication.
50.3.1 To Configure a JDBC Authentication Realm
GlassFish Server enables administrators to specify a user's credentials (user name and
password) in the JDBC realm instead of in the connection pool. This prevents other
applications from browsing the database tables for user credentials. By default, storing
passwords as clear text is not supported in the JDBC realm. Under normal
circumstances, passwords should not be stored as clear text.
1.
Create the database tables in which user credentials for the realm will be stored.
2.
Add user credentials to the database tables you created.
3.
Create a JDBC connection pool for the database.
You can use the Administration Console or the command line to create a
connection pool.
4.
Create a JDBC resource for the database.
You can use the Administration Console or the command line to create a JDBC
resource.
5.
Create a realm.
This step needs to associate the resource with the realm, define the tables and
columns for users and groups used for authentication, and define the digest
algorithm that will be used for storing passwords in the database.
Java EE Security: Advanced Topics 50-9
Securing HTTP Resources
You can use the Administration Console or the command line to create a realm.
6.
Modify the deployment descriptor for your application to specify the JDBC realm.
■
■
■
For an enterprise application in an EAR file, modify the
glassfish-application.xml file.
For a web application in a WAR file, modify the web.xml file.
For an enterprise bean in an EJB JAR file, modify the glassfish-ejb-jar.xml
file.
For example, for a hypothetical application, the web.xml file could specify the
jdbcRealm realm, as follows:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>jdbcRealm</realm-name>
<form-login-config>
<form-login-page>/login.xhtml</form-login-page>
<form-error-page>/login.xhtml</form-error-page>
</form-login-config>
</login-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>Secure Pages</web-resource-name>
<description/>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>ADMINS</role-name>
</auth-constraint>
</security-constraint>
Form-based login is specified for all web pages under /admin. Access to those
pages will be allowed only to users in the ADMINS role.
7.
Assign security roles to users or groups of users in the realm.
To assign a security role to a group or to a user, add a security-role-mapping
element to the application server-specific deployment descriptor, in this case
glassfish-web.xml:
<security-role-mapping>
<role-name>USERS</role-name>
<group-name>USERS</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>ADMINS</role-name>
<group-name>ADMINS</group-name>
</security-role-mapping>
Since GlassFish Server users are assigned to groups during the user creation
process, this is more efficient than mapping security roles to individual users.
50.4 Securing HTTP Resources
When a request URI is matched by multiple constrained URL patterns, the constraints
that apply to the request are those that are associated with the best matching URL
pattern. The servlet matching rules defined in Chapter 12, "Mapping Requests To
Servlets," in the Java Servlet 3.1 Specification, are used to determine the best matching
URL pattern to the request URI. No protection requirements apply to a request URI
50-10 The Java EE 7 Tutorial
Securing HTTP Resources
that is not matched by a constrained URL pattern. The HTTP method of the request
plays no role in selecting the best matching URL pattern for a request.
When HTTP methods are listed within a constraint definition, the protections defined
by the constraint are applied to the listed methods only.
When HTTP methods are not listed within a constraint definition, the protections
defined by the constraint apply to the complete set of HTTP methods, including HTTP
extension methods.
When constraints with different protection requirements apply to the same
combination of URL patterns and HTTP methods, the rules for combining the
protection requirements are as defined in Section 13.8.1, "Combining Constraints," in
the Java Servlet 3.1 Specification.
Follow these guidelines to properly secure a web application.
■
Do not list HTTP methods within constraint definitions. This is the simplest way
to ensure that you are not leaving HTTP methods unprotected. For example:
<!-- SECURITY CONSTRAINT #1 -->
<security-constraint>
<display-name>Do not enumerate Http Methods</display-name>
<web-resource-collection>
<url-pattern>/company/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>sales</role-name>
</auth-constraint>
</security-constraint>
If you list methods in a constraint, all non-listed methods of the effectively infinite
set of possible HTTP methods, including extension methods, will be unprotected.
Use such a constraint only if you are certain that this is the protection scheme you
intend to define. The following example shows a constraint that lists the GET
method and thus defines no protection on any of the other possible HTTP
methods:
<!-- SECURITY CONSTRAINT #2 -->
<security-constraint>
<display-name>
Protect GET only, leave all other methods unprotected
</display-name>
<web-resource-collection>
<url-pattern>/company/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>sales</role-name>
</auth-constraint>
</security-constraint>
■
If you need to apply specific types of protection to specific HTTP methods, make
sure that you define constraints to cover every method that you want to permit,
with or without constraint, at the corresponding URL patterns. If there are any
methods that you do not want to permit, you must also create a constraint that
denies access to those methods at the same patterns; for an example, see security
constraint #5 in the next bullet.
For example, to permit GET and POST, where POST requires authentication and
GET is permitted without constraint, you could define the following constraints:
Java EE Security: Advanced Topics
50-11
Securing HTTP Resources
<!-- SECURITY CONSTRAINT #3 -->
<security-constraint>
<display-name>Allow unprotected GET</display-name>
<web-resource-collection>
<url-pattern>/company/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
</security-constraint>
<!-- SECURITY CONSTRAINT #4 -->
<security-constraint>
<display-name>Require authentication for POST</display-name>
<web-resource-collection>
<url-pattern>/company/*</url-pattern>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>sales</role-name>
</auth-constraint>
</security-constraint>
■
The simplest way to ensure that you deny all HTTP methods except those that you
want to be permitted is to use http-method-omission elements to omit those
HTTP methods from the security constraint, and also to define an
auth-constraint that names no roles. The security constraint will apply to all
methods except those that were named in the omissions, and the constraint will
apply only to the resources matched by the patterns in the constraint.
For example, the following constraint excludes access to all methods except GET
and POST at the resources matched by the pattern /company/*:
<!-- SECURITY CONSTRAINT #5 -->
<security-constraint>
<display-name>Deny all HTTP methods except GET and POST</display-name>
<web-resource-collection>
<url-pattern>/company/*</url-pattern>
<http-method-omission>GET</http-method-omission>
<http-method-omission>POST</http-method-omission>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
If you want to extend these exclusions to the unconstrained parts of your
application, also include the URL pattern / (forward slash):
<!-- SECURITY CONSTRAINT #6 -->
<security-constraint>
<display-name>Deny all HTTP methods except GET and POST</display-name>
<web-resource-collection>
<url-pattern>/company/*</url-pattern>
<url-pattern>/</url-pattern>
<http-method-omission>GET</http-method-omission>
<http-method-omission>POST</http-method-omission>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
■
If, for your web application, you do not want any resource to be accessible unless
you explicitly define a constraint that permits access to it, you can define an
auth-constraint that names no roles and associate it with the URL pattern /. The
50-12 The Java EE 7 Tutorial
Securing Application Clients
URL pattern / is the weakest matching pattern. Do not list any HTTP methods in
this constraint:
<!-- SECURITY CONSTRAINT #7 -->
<security-constraint>
<display-name>
Switch from Constraint to Permission model
(where everything is denied by default)
</display-name>
<web-resource-collection>
<url-pattern>/</url-pattern>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
50.5 Securing Application Clients
The Java EE authentication requirements for application clients are the same as for
other Java EE components, and the same authentication techniques can be used as for
other Java EE application components. No authentication is necessary when accessing
unprotected web resources.
When accessing protected web resources, the usual varieties of authentication can be
used: HTTP basic authentication, HTTP login-form authentication, or SSL client
authentication. Specifying an Authentication Mechanism in the Deployment
Descriptor describes how to specify HTTP basic authentication and HTTP login-form
authentication. Client Authentication describes how to specify SSL client
authentication.
Authentication is required when accessing protected enterprise beans. The
authentication mechanisms for enterprise beans are discussed in Securing Enterprise
Beans.
An application client makes use of an authentication service provided by the
application client container for authenticating its users. The container's service can be
integrated with the native platform's authentication system so that a single sign-on
capability is used. The container can authenticate the user either when the application
is started or when a protected resource is accessed.
An application client can provide a class, called a login module, to gather
authentication data. If so, the javax.security.auth.callback.CallbackHandler
interface must be implemented, and the class name must be specified in its
deployment descriptor. The application's callback handler must fully support
Callback objects specified in the javax.security.auth.callback package.
50.5.1 Using Login Modules
An application client can use the Java Authentication and Authorization Service
(JAAS) to create login modules for authentication. A JAAS-based application
implements the javax.security.auth.callback.CallbackHandler interface so that it
can interact with users to enter specific authentication data, such as user names or
passwords, or to display error and warning messages.
Applications implement the CallbackHandler interface and pass it to the login
context, which forwards it directly to the underlying login modules. A login module
uses the callback handler both to gather input, such as a password or smart card PIN,
from users and to supply information, such as status information, to users. Because the
application specifies the callback handler, an underlying login module can remain
independent of the various ways applications interact with users.
Java EE Security: Advanced Topics
50-13
Securing Enterprise Information Systems Applications
For example, the implementation of a callback handler for a GUI application might
display a window to solicit user input, or the implementation of a callback handler for
a command-line tool might simply prompt the user for input directly from the
command line.
The login module passes an array of appropriate callbacks to the callback handler's
handle method, such as a NameCallback for the user name and a PasswordCallback for
the password; the callback handler performs the requested user interaction and sets
appropriate values in the callbacks. For example, to process a NameCallback, the
CallbackHandler might prompt for a name, retrieve the value from the user, and call
the setName method of the NameCallback to store the name.
For more information on using JAAS for authentication in login modules, refer to the
documentation listed in Further Information about Advanced Security Topics.
50.5.2 Using Programmatic Login
Programmatic login enables the client code to supply user credentials. If you are using
an EJB client, you can use the com.sun.appserv.security.ProgrammaticLogin class
with its convenient login and logout methods. Programmatic login is specific to a
server.
50.6 Securing Enterprise Information Systems Applications
In Enterprise Information Systems (EIS) applications, components request a
connection to an EIS resource. As part of this connection, the EIS can require a sign-on
for the requester to access the resource. The application component provider has two
choices for the design of the EIS sign-on.
■
■
Container-managed sign-on: The application component lets the container take
the responsibility of configuring and managing the EIS sign-on. The container
determines the user name and password for establishing a connection to an EIS
instance. For more information, see Container-Managed Sign-On.
Component-managed sign-on: The application component code manages EIS
sign-on by including code that performs the sign-on process to an EIS. For more
information, see Component-Managed Sign-On.
You can also configure security for resource adapters. See Configuring Resource
Adapter Security.
50.6.1 Container-Managed Sign-On
In container-managed sign-on, an application component does not have to pass any
sign-on security information to the getConnection() method. The security
information is supplied by the container, as shown in the following example (the
method call is highlighted in bold):
// Business method in an application component
Context initctx = new InitialContext();
// Perform JNDI lookup to obtain a connection factory
javax.resource.cci.ConnectionFactory cxf =
(javax.resource.cci.ConnectionFactory)initctx.lookup(
"java:comp/env/eis/MainframeCxFactory");
// Invoke factory to obtain a connection. The security
// information is not passed in the getConnection method
javax.resource.cci.Connection cx = cxf.getConnection();
...
50-14 The Java EE 7 Tutorial
Securing Enterprise Information Systems Applications
50.6.2 Component-Managed Sign-On
In component-managed sign-on, an application component is responsible for passing
the needed sign-on security information for the resource to the getConnection
method. For example, security information might be a user name and password, as
shown here (the method call is highlighted in bold):
// Method in an application component
Context initctx = new InitialContext();
// Perform JNDI lookup to obtain a connection factory
javax.resource.cci.ConnectionFactory cxf =
(javax.resource.cci.ConnectionFactory)initctx.lookup(
"java:comp/env/eis/MainframeCxFactory");
// Get a new ConnectionSpec
com.myeis.ConnectionSpecImpl properties = //..
// Invoke factory to obtain a connection
properties.setUserName("...");
properties.setPassword("...");
javax.resource.cci.Connection cx =
cxf.getConnection(properties);
...
50.6.3 Configuring Resource Adapter Security
A resource adapter is a system-level software component that typically implements
network connectivity to an external resource manager. A resource adapter can extend
the functionality of the Java EE platform either by implementing one of the Java EE
standard service APIs, such as a JDBC driver, or by defining and implementing a
resource adapter for a connector to an external application system. Resource adapters
can also provide services that are entirely local, perhaps interacting with native
resources. Resource adapters interface with the Java EE platform through the Java EE
service provider interfaces (Java EE SPI). A resource adapter that uses the Java EE SPIs
to attach to the Java EE platform will be able to work with all Java EE products.
To configure the security settings for a resource adapter, you need to edit the resource
adapter descriptor file, ra.xml. Here is an example of the part of an ra.xml file that
configures security properties for a resource adapter:
<authentication-mechanism>
<authentication-mechanism-type>
BasicPassword
</authentication-mechanism-type>
<credential-interface>
javax.resource.spi.security.PasswordCredential
</credential-interface>
</authentication-mechanism>
<reauthentication-support>false</reauthentication-support>
You can find out more about the options for configuring resource adapter security by
reviewing as-install/lib/schemas/connector_1_7.xsd. You can configure the
following elements in the resource adapter deployment descriptor file.
■
Authentication mechanisms: Use the authentication-mechanism element to
specify an authentication mechanism supported by the resource adapter. This
support is for the resource adapter, not for the underlying EIS instance.
There are two supported mechanism types:
Java EE Security: Advanced Topics
50-15
Securing Enterprise Information Systems Applications
–
BasicPassword, which supports the following interface:
javax.resource.spi.security.PasswordCredential
–
Kerbv5, which supports the following interface:
javax.resource.spi.security.GenericCredential
GlassFish Server does not currently support this mechanism type.
■
■
Reauthentication support: Use the reauthentication-support element to specify
whether the resource adapter implementation supports reauthentication of
existing Managed-Connection instances. Options are true or false.
Security permissions: Use the security-permission element to specify a security
permission that is required by the resource adapter code. Support for security
permissions is optional and is not supported in the current release of GlassFish
Server. You can, however, manually update the server.policy file to add the
relevant permissions for the resource adapter.
The security permissions listed in the deployment descriptor are different from
those required by the default permission set as specified in the connector
specification.
For more information on the implementation of the security permission
specification, see the security policy file documentation listed in Further
Information about Advanced Security Topics.
In addition to specifying resource adapter security in the ra.xml file, you can create a
security map for a connector connection pool to map an application principal or a user
group to a back-end EIS principal. The security map is usually used if one or more EIS
back-end principals are used to execute operations (on the EIS) initiated by various
principals or user groups in the application.
50.6.4 Mapping an Application Principal to EIS Principals
When using GlassFish Server, you can use security maps to map the caller identity of
the application (principal or user group) to a suitable EIS principal in
container-managed transaction-based scenarios. When an application principal
initiates a request to an EIS, GlassFish Server first checks for an exact principal by
using the security map defined for the connector connection pool to determine the
mapped back-end EIS principal. If there is no exact match, GlassFish Server uses the
wildcard character specification, if any, to determine the mapped back-end EIS
principal. Security maps are used when an application user needs to execute an EIS
operation that requires execution as a specific identity in the EIS.
To work with security maps, use the Administration Console. From the
Administration Console, follow these steps to get to the security maps page.
1.
In the navigation tree, expand the Resources node.
2.
Expand the Connectors node.
3.
Select the Connector Connection Pools node.
4.
On the Connector Connection Pools page, click the name of the connection pool
for which you want to create a security map.
5.
Click the Security Maps tab.
6.
Click New to create a new security map for the connection pool.
50-16 The Java EE 7 Tutorial
Configuring Security Using Deployment Descriptors
7.
Enter a name by which you will refer to the security map, as well as the other
required information.
Click Help for more information on the individual options.
50.7 Configuring Security Using Deployment Descriptors
The recommended way to configure security in the Java EE 7 platform is with
annotations. If you wish to override the security settings at deployment time, you can
use security elements in the web.xml deployment descriptor to do so. This section
describes how to use the deployment descriptor to specify basic authentication and to
override default principal-to-role mapping.
50.7.1 Specifying Security for Basic Authentication in the Deployment Descriptor
The elements of the deployment descriptor that add basic authentication to an
example tell the server or browser to perform the following tasks.
■
Send a standard login dialog box to collect user name and password data.
■
Verify that the user is authorized to access the application.
■
If authorized, display the servlet to the user.
The following sample code shows the security elements for a deployment descriptor
that could be used in the example of basic authentication found in the
tut-install/examples/security/hello2_basicauth/ directory:
<security-constraint>
<display-name>SecurityConstraint</display-name>
<web-resource-collection>
<web-resource-name>WRCollection</web-resource-name>
<url-pattern>/greeting</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>TutorialUser</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>file</realm-name>
</login-config>
<security-role>
<role-name>TutorialUser</role-name>
</security-role>
This deployment descriptor specifies that the request URI /greeting can be accessed
only by users who have entered their user names and passwords and have been
authorized to access this URL because they have been verified to be in the role
TutorialUser. The user name and password data will be sent over a protected
transport in order to keep it from being read in transit.
50.7.2 Specifying Non-Default Principal-to-Role Mapping in the Deployment Descriptor
To map a role name permitted by the application or module to principals (users) and
groups defined on the server, use the security-role-mapping element in the runtime
deployment descriptor file (glassfish-application.xml, glassfish-web.xml, or
Java EE Security: Advanced Topics
50-17
Further Information about Advanced Security Topics
glassfish-ejb-jar.xml). The entry needs to declare a mapping between a security
role used in the application and one or more groups or principals defined for the
applicable realm of GlassFish Server. An example for the glassfish-web.xml file is
shown below:
<glassfish-web-app>
<security-role-mapping>
<role-name>DIRECTOR</role-name>
<principal-name>schwartz</principal-name>
</security-role-mapping>
<security-role-mapping>
<role-name>DEPT-ADMIN</role-name>
<group-name>dept-admins</group-name>
</security-role-mapping>
</glassfish-web-app>
The role name can be mapped to either a specific principal (user), a group, or both. The
principal or group names referenced must be valid principals or groups in the current
default realm of GlassFish Server. The role-name in this example must exactly match
the role-name in the security-role element of the corresponding web.xml file or the
role name defined in the @DeclareRoles and/or @RolesAllowed annotations.
50.8 Further Information about Advanced Security Topics
For more information about the security topics covered in this chapter, see
■
Documentation on the keytool command:
http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/
keytool.html
■
Java Authentication and Authorization Service (JAAS) Reference Guide:
http://docs.oracle.com/javase/7/docs/technotes/guides/securit
y/jaas/JAASRefGuide.html
■
Java Authentication and Authorization Service (JAAS): LoginModule Developer’s Guide:
http://docs.oracle.com/javase/7/docs/technotes/guides/securit
y/jaas/JAASLMDevGuide.html
■
Documentation on security policy file syntax:
http://docs.oracle.com/javase/7/docs/technotes/guides/securit
y/PolicyFiles.html#FileSyntax
50-18 The Java EE 7 Tutorial
Part XI
Part XI
Java EE Supporting Technologies
Part XI explores several technologies that support the Java EE platform. This part
contains the following chapters:
■
Chapter 51, "Transactions"
■
Chapter 52, "Resource Adapters and Contracts"
■
Chapter 53, "The Resource Adapter Examples"
■
Chapter 54, "Using Java EE Interceptors"
■
Chapter 55, "Batch Processing"
■
Chapter 56, "Concurrency Utilities for Java EE"
51
Transactions
51
A typical enterprise application accesses and stores information in one or more
databases. Because this information is critical for business operations, it must be
accurate, current, and reliable. Data integrity would be lost if multiple programs were
allowed to update the same information simultaneously or if a system that failed while
processing a business transaction were to leave the affected data only partially
updated. By preventing both of these scenarios, software transactions ensure data
integrity. Transactions control the concurrent access of data by multiple programs. In
the event of a system failure, transactions make sure that after recovery, the data will
be in a consistent state.
The following topics are addressed here:
■
Transactions in Java EE Applications
■
What Is a Transaction?
■
Container-Managed Transactions
■
Bean-Managed Transactions
■
Transaction Timeouts
■
Updating Multiple Databases
■
Transactions in Web Components
■
Further Information about Transactions
51.1 Transactions in Java EE Applications
In a Java EE application, a transaction is a series of actions that must all complete
successfully, or else all the changes in each action are backed out. Transactions end in
either a commit or a rollback.
The Java Transaction API (JTA) allows applications to access transactions in a manner
that is independent of specific implementations. JTA specifies standard Java interfaces
between a transaction manager and the parties involved in a distributed transaction
system: the transactional application, the Java EE server, and the manager that controls
access to the shared resources affected by the transactions.
The JTA defines the UserTransaction interface that applications use to start, commit,
or roll back transactions. Application components get a UserTransaction object
through a JNDI lookup by using the name java:comp/UserTransaction or by
requesting injection of a UserTransaction object. An application server uses a number
of JTA-defined interfaces to communicate with a transaction manager; a transaction
manager uses JTA-defined interfaces to interact with a resource manager.
Transactions 51-1
What Is a Transaction?
The JTA 1.2 specification is available at
http://jcp.org/en/jsr/detail?id=907.
51.2 What Is a Transaction?
To emulate a business transaction, a program may need to perform several steps. A
financial program, for example, might transfer funds from a checking account to a
savings account by using the steps listed in the following pseudocode:
begin transaction
debit checking account
credit savings account
update history log
commit transaction
Either all or none of the three steps must complete. Otherwise, data integrity is lost.
Because the steps within a transaction are a unified whole, a transaction is often
defined as an indivisible unit of work.
A transaction can end in two ways: with a commit or with a rollback. When a
transaction commits, the data modifications made by its statements are saved. If a
statement within a transaction fails, the transaction rolls back, undoing the effects of
all statements in the transaction. In the pseudocode, for example, if a disk drive were
to crash during the credit step, the transaction would roll back and undo the data
modifications made by the debit statement. Although the transaction fails, data
integrity would be intact because the accounts still balance.
In the preceding pseudocode, the begin and commit statements mark the boundaries of
the transaction. When designing an enterprise bean, you determine how the
boundaries are set by specifying either container-managed or bean-managed
transactions.
51.3 Container-Managed Transactions
In an enterprise bean with container-managed transaction demarcation, the EJB
container sets the boundaries of the transactions. You can use container-managed
transactions with any type of enterprise bean: session or message-driven.
Container-managed transactions simplify development because the enterprise bean
code does not explicitly mark the transaction's boundaries. The code does not include
statements that begin and end the transaction. By default, if no transaction
demarcation is specified, enterprise beans use container-managed transaction
demarcation.
Typically, the container begins a transaction immediately before an enterprise bean
method starts and commits the transaction just before the method exits. Each method
can be associated with a single transaction. Nested or multiple transactions are not
allowed within a method.
Container-managed transactions do not require all methods to be associated with
transactions. When developing a bean, you can set the transaction attributes to specify
which of the bean's methods are associated with transactions.
Enterprise beans that use container-managed transaction demarcation must not use
any transaction-management methods that interfere with the container's transaction
demarcation boundaries. Examples of such methods are the commit, setAutoCommit,
and rollback methods of java.sql.Connection or the commit and rollback methods
of javax.jms.Session. If you require control over the transaction demarcation, you
must use application-managed transaction demarcation.
51-2 The Java EE 7 Tutorial
Container-Managed Transactions
Enterprise beans that use container-managed transaction demarcation also must not
use the javax.transaction.UserTransaction interface.
51.3.1 Transaction Attributes
A transaction attribute controls the scope of a transaction. Figure 51–1 illustrates why
controlling the scope is important. In the diagram, method-A begins a transaction and
then invokes method-B of Bean-2. When method-B executes, does it run within the
scope of the transaction started by method-A, or does it execute with a new
transaction? The answer depends on the transaction attribute of method-B.
Figure 51–1 Transaction Scope
Bean-1
TX1
method-A(){
bean-2.method-B()
}
Bean-2
method-B(){
}
TX?
A transaction attribute can have one of the following values:
■
Required
■
RequiresNew
■
Mandatory
■
NotSupported
■
Supports
■
Never
51.3.1.1 Required Attribute
If the client is running within a transaction and invokes the enterprise bean's method,
the method executes within the client's transaction. If the client is not associated with a
transaction, the container starts a new transaction before running the method.
The Required attribute is the implicit transaction attribute for all enterprise bean
methods running with container-managed transaction demarcation. You typically do
not set the Required attribute unless you need to override another transaction
attribute. Because transaction attributes are declarative, you can easily change them
later.
51.3.1.2 RequiresNew Attribute
If the client is running within a transaction and invokes the enterprise bean's method,
the container takes the following steps:
1.
Suspends the client's transaction
2.
Starts a new transaction
3.
Delegates the call to the method
4.
Resumes the client's transaction after the method completes
Transactions 51-3
Container-Managed Transactions
If the client is not associated with a transaction, the container starts a new transaction
before running the method.
You should use the RequiresNew attribute when you want to ensure that the method
always runs within a new transaction.
51.3.1.3 Mandatory Attribute
If the client is running within a transaction and invokes the enterprise bean's method,
the method executes within the client's transaction. If the client is not associated with a
transaction, the container throws a TransactionRequiredException.
Use the Mandatory attribute if the enterprise bean's method must use the transaction of
the client.
51.3.1.4 NotSupported Attribute
If the client is running within a transaction and invokes the enterprise bean's method,
the container suspends the client's transaction before invoking the method. After the
method has completed, the container resumes the client's transaction.
If the client is not associated with a transaction, the container does not start a new
transaction before running the method.
Use the NotSupported attribute for methods that don't need transactions. Because
transactions involve overhead, this attribute may improve performance.
51.3.1.5 Supports Attribute
If the client is running within a transaction and invokes the enterprise bean's method,
the method executes within the client's transaction. If the client is not associated with a
transaction, the container does not start a new transaction before running the method.
Because the transactional behavior of the method may vary, you should use the
Supports attribute with caution.
51.3.1.6 Never Attribute
If the client is running within a transaction and invokes the enterprise bean's method,
the container throws a RemoteException. If the client is not associated with a
transaction, the container does not start a new transaction before running the method.
51.3.1.7 Summary of Transaction Attributes
Table 51–1 summarizes the effects of the transaction attributes. Both the T1 and the T2
transactions are controlled by the container. A T1 transaction is associated with the
client that calls a method in the enterprise bean. In most cases, the client is another
enterprise bean. A T2 transaction is started by the container just before the method
executes.
In the last column of Table 51–1, the word "None" means that the business method
does not execute within a transaction controlled by the container. However, the
database calls in such a business method might be controlled by the transaction
manager of the database management system.
Table 51–1
Transaction Attributes and Scope
Transaction Attribute
Client's Transaction
Business Method's Transaction
Required
None
T2
Required
T1
T1
51-4 The Java EE 7 Tutorial
Container-Managed Transactions
Table 51–1 (Cont.) Transaction Attributes and Scope
Transaction Attribute
Client's Transaction
Business Method's Transaction
RequiresNew
None
T2
RequiresNew
T1
T2
Mandatory
None
Error
Mandatory
T1
T1
NotSupported
None
None
NotSupported
T1
None
Supports
None
None
Supports
T1
T1
Never
None
None
Never
T1
Error
51.3.1.8 Setting Transaction Attributes
Transaction attributes are specified by decorating the enterprise bean class or method
with a javax.ejb.TransactionAttribute annotation and setting it to one of the
javax.ejb.TransactionAttributeType constants.
If you decorate the enterprise bean class with @TransactionAttribute, the specified
TransactionAttributeType is applied to all the business methods in the class.
Decorating a business method with @TransactionAttribute applies the
TransactionAttributeType only to that method. If a @TransactionAttribute
annotation decorates both the class and the method, the method
TransactionAttributeType overrides the class TransactionAttributeType.
The TransactionAttributeType constants shown in Table 51–2 encapsulate the
transaction attributes described earlier in this section.
Table 51–2
TransactionAttributeType Constants
Transaction Attribute
TransactionAttributeType Constant
Required
TransactionAttributeType.REQUIRED
RequiresNew
TransactionAttributeType.REQUIRES_NEW
Mandatory
TransactionAttributeType.MANDATORY
NotSupported
TransactionAttributeType.NOT_SUPPORTED
Supports
TransactionAttributeType.SUPPORTS
Never
TransactionAttributeType.NEVER
The following code snippet demonstrates how to use the @TransactionAttribute
annotation:
@TransactionAttribute(NOT_SUPPORTED)
@Stateful
public class TransactionBean implements Transaction {
...
@TransactionAttribute(REQUIRES_NEW)
public void firstMethod() {...}
@TransactionAttribute(REQUIRED)
public void secondMethod() {...}
Transactions 51-5
Container-Managed Transactions
public void thirdMethod() {...}
public void fourthMethod() {...}
}
In this example, the TransactionBean class's transaction attribute has been set to
NotSupported, firstMethod has been set to RequiresNew, and secondMethod has been
set to Required. Because a @TransactionAttribute set on a method overrides the class
@TransactionAttribute, calls to firstMethod will create a new transaction, and calls
to secondMethod will either run in the current transaction or start a new transaction.
Calls to thirdMethod or fourthMethod do not take place within a transaction.
51.3.2 Rolling Back a Container-Managed Transaction
There are two ways to roll back a container-managed transaction. First, if a system
exception is thrown, the container will automatically roll back the transaction. Second,
by invoking the setRollbackOnly method of the EJBContext interface, the bean
method instructs the container to roll back the transaction. If the bean throws an
application exception, the rollback is not automatic but can be initiated by a call to
setRollbackOnly.
51.3.3 Synchronizing a Session Bean's Instance Variables
The SessionSynchronization interface, which is optional, allows stateful session bean
instances to receive transaction synchronization notifications. For example, you could
synchronize the instance variables of an enterprise bean with their corresponding
values in the database. The container invokes the SessionSynchronization methods
(afterBegin, beforeCompletion, and afterCompletion) at each of the main stages of a
transaction.
The afterBegin method informs the instance that a new transaction has begun. The
container invokes afterBegin immediately before it invokes the business method.
The container invokes the beforeCompletion method after the business method has
finished but just before the transaction commits. The beforeCompletion method is the
last opportunity for the session bean to roll back the transaction (by calling
setRollbackOnly).
The afterCompletion method indicates that the transaction has completed. This
method has a single boolean parameter whose value is true if the transaction was
committed and false if it was rolled back.
51.3.4 Methods Not Allowed in Container-Managed Transactions
You should not invoke any method that might interfere with the transaction
boundaries set by the container. The following methods are prohibited:
■
The commit, setAutoCommit, and rollback methods of java.sql.Connection
■
The getUserTransaction method of javax.ejb.EJBContext
■
Any method of javax.transaction.UserTransaction
You can, however, use these methods to set boundaries in application-managed
transactions.
51-6 The Java EE 7 Tutorial
Bean-Managed Transactions
51.4 Bean-Managed Transactions
In bean-managed transaction demarcation, the code in the session or message-driven
bean explicitly marks the boundaries of the transaction. Although beans with
container-managed transactions require less coding, they have one limitation: When a
method is executing, it can be associated with either a single transaction or no
transaction at all. If this limitation will make coding your bean difficult, you should
consider using bean-managed transactions.
The following pseudocode illustrates the kind of fine-grained control you can obtain
with application-managed transactions. By checking various conditions, the
pseudocode decides whether to start or stop certain transactions within the business
method:
begin transaction
...
update table-a
...
if (condition-x)
commit transaction
else if (condition-y)
update table-b
commit transaction
else
rollback transaction
begin transaction
update table-c
commit transaction
When coding an application-managed transaction for session or message-driven
beans, you must decide whether to use Java Database Connectivity or JTA
transactions. The sections that follow discuss both types of transactions.
51.4.1 JTA Transactions
JTA, or the Java Transaction API, allows you to demarcate transactions in a manner
that is independent of the transaction manager implementation. GlassFish Server
implements the transaction manager with the Java Transaction Service (JTS). However,
your code doesn't call the JTS methods directly but instead invokes the JTA methods,
which then call the lower-level JTS routines.
A JTA transaction is controlled by the Java EE transaction manager. You may want to
use a JTA transaction because it can span updates to multiple databases from different
vendors. A particular DBMS's transaction manager may not work with heterogeneous
databases. However, the Java EE transaction manager does have one limitation: It does
not support nested transactions. In other words, it cannot start a transaction for an
instance until the preceding transaction has ended.
To demarcate a JTA transaction, you invoke the begin, commit, and rollback methods
of the javax.transaction.UserTransaction interface.
51.4.2 Returning without Committing
In a stateless session bean with bean-managed transactions, a business method must
commit or roll back a transaction before returning. However, a stateful session bean
does not have this restriction.
In a stateful session bean with a JTA transaction, the association between the bean
instance and the transaction is retained across multiple client calls. Even if each
Transactions 51-7
Transaction Timeouts
business method called by the client opens and closes the database connection, the
association is retained until the instance completes the transaction.
In a stateful session bean with a JDBC transaction, the JDBC connection retains the
association between the bean instance and the transaction across multiple calls. If the
connection is closed, the association is not retained.
51.4.3 Methods Not Allowed in Bean-Managed Transactions
Do not invoke the getRollbackOnly and setRollbackOnly methods of the EJBContext
interface in bean-managed transactions. These methods should be used only in
container-managed transactions. For bean-managed transactions, invoke the
getStatus and rollback methods of the UserTransaction interface.
51.5 Transaction Timeouts
For container-managed transactions, you can use the Administration Console to
configure the transaction timeout interval. See Starting the Administration Console.
For enterprise beans with bean-managed JTA transactions, you invoke the
setTransactionTimeout method of the UserTransaction interface.
51.5.1 To Set a Transaction Timeout
1.
In the Administration Console, expand the Configurations node, then expand the
server-config node and select Transaction Service.
2.
On the Transaction Service page, set the value of the Transaction Timeout field to
the value of your choice (for example, 5).
With this setting, if the transaction has not completed within 5 seconds, the EJB
container rolls it back.
The default value is 0, meaning that the transaction will not time out.
3.
Click Save.
51.6 Updating Multiple Databases
The Java EE transaction manager controls all enterprise bean transactions except for
bean-managed JDBC transactions. The Java EE transaction manager allows an
enterprise bean to update multiple databases within a transaction. Figure 51–2 and
Figure 51–3 show two scenarios for updating multiple databases in a single
transaction.
In Figure 51–2, the client invokes a business method in Bean-A. The business method
begins a transaction, updates Database X, updates Database Y, and invokes a business
method in Bean-B. The second business method updates Database Z and returns
control to the business method in Bean-A, which commits the transaction. All three
database updates occur in the same transaction.
In Figure 51–3, the client calls a business method in Bean-A, which begins a transaction
and updates Database X. Then Bean-A invokes a method in Bean-B, which resides in a
remote Java EE server. The method in Bean-B updates Database Y. The transaction
managers of the Java EE servers ensure that both databases are updated in the same
transaction.
51-8 The Java EE 7 Tutorial
Further Information about Transactions
Figure 51–2 Updating Multiple Databases
Client
Java EE Server
Bean-A
Bean-B
Databases
Y
X
Z
Figure 51–3 Updating Multiple Databases Across Java EE Servers
Client
Java EE Server
Java EE Server
Bean-A
Bean-B
Databases
X
Y
51.7 Transactions in Web Components
You can demarcate a transaction in a web component by using either the
java.sql.Connection or the javax.transaction.UserTransaction interface. These
are the same interfaces that a session bean with bean-managed transactions can use.
Transactions demarcated with the UserTransaction interface are discussed in JTA
Transactions.
51.8 Further Information about Transactions
For more information about transactions, see the Java Transaction API 1.2 specification
at https://www.jcp.org/en/jsr/detail?id=907.
Transactions 51-9
Further Information about Transactions
51-10 The Java EE 7 Tutorial
52
Resource Adapters and Contracts
52
This chapter examines resource adapters and explains how communications between
Java EE servers and EIS systems are mediated by them.
The following topics are addressed here:
■
What Is a Resource Adapter?
■
Metadata Annotations
■
Common Client Interface
■
■
Using Resource Adapters with Contexts and Dependency Injection for Java EE
(CDI)
Further Information about Resource Adapters
52.1 What Is a Resource Adapter?
A resource adapter is a Java EE component that implements the Java EE Connector
Architecture for a specific EIS. Examples of EISs include enterprise resource planning,
mainframe transaction processing, and database systems. In a Java EE server, the Java
Message Server and JavaMail also act as EISs that you access using resource adapters.
As illustrated in Figure 52–1, the resource adapter facilitates communication between a
Java EE application and an EIS.
Figure 52–1 Resource Adapters
Java EE Server
Enterprise Bean
Application
Contract
Managers
Transaction
Connection Security
Web Component
System
Contracts
Resource
Adapter
EIS
Application
Contract
Resource Adapters and Contracts 52-1
What Is a Resource Adapter?
Stored in a Resource Adapter Archive (RAR) file, a resource adapter can be deployed
on any Java EE server, much like a Java EE application. A RAR file may be contained
in an Enterprise Archive (EAR) file, or it may exist as a separate file.
A resource adapter is analogous to a JDBC driver. Both provide a standard API
through which an application can access a resource that is outside the Java EE server.
For a resource adapter, the target system is an EIS; for a JDBC driver, it is a DBMS.
Resource adapters and JDBC drivers are rarely created by application developers. In
most cases, both types of software are built by vendors that sell tools, servers, or
integration software.
The resource adapter mediates communication between the Java EE server and the EIS
by means of contracts. The application contract defines the API through which a Java
EE component, such as an enterprise bean, accesses the EIS. This API is the only view
that the component has of the EIS. The system contracts link the resource adapter to
important services that are managed by the Java EE server. The resource adapter itself
and its system contracts are transparent to the Java EE component.
52.1.1 Management Contracts
The Java EE Connector Architecture defines system contracts that enable resource
adapter lifecycle and thread management.
52.1.1.1 Lifecycle Management
The Connector Architecture specifies a lifecycle management contract that allows an
application server to manage the lifecycle of a resource adapter. This contract provides
a mechanism for the application server to bootstrap a resource adapter instance during
the deployment or application server startup. This contract also provides a means for
the application server to notify the resource adapter instance when it is undeployed or
when an orderly shutdown of the application server takes place.
52.1.1.2 Work Management Contract
The Connector Architecture work management contract ensures that resource adapters
use threads in the proper, recommended manner. This contract also enables an
application server to manage threads for resource adapters.
Resource adapters that improperly use threads can jeopardize the entire application
server environment. For example, a resource adapter might create too many threads or
might not properly release threads it has created. Poor thread handling inhibits
application server shutdown and impacts the application server's performance
because creating and destroying threads are expensive operations.
The work management contract establishes a means for the application server to pool
and reuse threads, similar to pooling and reusing connections. By adhering to this
contract, the resource adapter does not have to manage threads itself. Instead, the
resource adapter has the application server create and provide needed threads. When
it is finished with a given thread, the resource adapter returns the thread to the
application server. The application server manages the thread, either returning it to a
pool for later reuse or destroying it. Handling threads in this manner results in
increased application server performance and more efficient use of resources.
In addition to moving thread management to the application server, the Connector
Architecture provides a flexible model for a resource adapter that uses threads.
■
The requesting thread can choose to block (stop its own execution) until the work
thread completes.
52-2 The Java EE 7 Tutorial
What Is a Resource Adapter?
■
■
The requesting thread can block while it waits to get the work thread. When the
application server provides a work thread, the requesting thread and the work
thread execute in parallel.
The resource adapter can opt to submit the work for the thread to a queue. The
thread executes the work from the queue at some later point. The resource adapter
continues its own execution from the point it submitted the work to the queue, no
matter when the thread executes it.
With the latter two approaches, the submitting thread and the work thread may
execute simultaneously or independently. For these approaches, the contract specifies
a listener mechanism to notify the resource adapter that the thread has completed its
operation. The resource adapter can also specify the execution context for the thread,
and the work management contract controls the context in which the thread executes.
52.1.2 Generic Work Context Contract
The work management contract between the application server and a resource adapter
enables a resource adapter to do a task, such as communicating with the EIS or
delivering messages, by delivering Work instances for execution.
A generic work context contract enables a resource adapter to control the contexts in
which the Work instances that it submits are executed by the application server's
WorkManager. A generic work context mechanism also enables an application server to
support message inflow and delivery schemes. It also provides a richer contextual
Work execution environment to the resource adapter while still maintaining control
over concurrent behavior in a managed environment.
The generic work context contract standardizes the transaction context and the
security context.
52.1.3 Outbound and Inbound Contracts
The Connector Architecture defines the following outbound contracts, system-level
contracts between an application server and an EIS that enable outbound connectivity
to an EIS.
■
■
The connection management contract supports connection pooling, a technique
that enhances application performance and scalability. Connection pooling is
transparent to the application, which simply obtains a connection to the EIS.
The transaction management contract extends the connection management
contract and provides support for management of both local and XA transactions.
A local transaction is limited in scope to a single EIS system, and the EIS resource
manager itself manages such a transaction. An XA transaction or global
transaction can span multiple resource managers. This form of transaction requires
transaction coordination by an external transaction manager, typically bundled
with an application server. A transaction manager uses a two-phase commit
protocol to manage a transaction that spans multiple resource managers or EISs,
and uses one-phase commit optimization if only one resource manager is
participating in an XA transaction.
■
The security management contract provides mechanisms for authentication,
authorization, and secure communication between a Java EE server and an EIS to
protect the information in the EIS.
A work security map matches EIS identities to the application server domain's
identities.
Resource Adapters and Contracts 52-3
Metadata Annotations
Inbound contracts are system contracts between a Java EE server and an EIS that
enable inbound connectivity from the EIS: pluggability contracts for message
providers and contracts for importing transactions.
52.2 Metadata Annotations
Java EE Connector Architecture provides a set of annotations to minimize the need for
deployment descriptors.
■
The @Connector annotation can be used by the resource adapter developer to
specify that the JavaBeans component is a resource adapter JavaBeans component.
This annotation is used for providing metadata about the capabilities of the
resource adapter. Optionally, you can provide a JavaBeans component
implementing the ResourceAdapter interface, as in the following example:
@Connector(
displayName = "TrafficResourceAdapter",
vendorName = "Java EE Tutorial",
version = "7.0"
)
public class TrafficResourceAdapter implements ResourceAdapter,
Serializable {
...
}
■
The @ConnectionDefinition annotation defines a set of connection interfaces and
classes pertaining to a particular connection type, as in the following example:
@ConnectionDefinition(
connectionFactory = ConnectionFactory.class,
connectionFactoryImpl = TradeConnectionFactory.class,
connection = Connection.class,
connectionImpl = TradeConnection.class
)
public class TradeManagedConnectionFactory ... {
...
}
■
■
The @AdministeredObject annotation designates a JavaBeans component as an
administered object.
The @Activation annotation contains configuration information pertaining to
inbound connectivity from an EIS instance, as in the following example:
@Activation(
messageListeners = { TrafficListener.class }
)
public class TrafficActivationSpec implements ActivationSpec,
Serializable {
...
@ConfigProperty()
/* port to listen to requests from the EIS */
private String port;
...
}
■
The @ConfigProperty annotation can be used on JavaBeans components to
provide additional configuration information that may be used by the deployer
and resource adapter provider. The preceding example code shows several
@ConfigProperty annotations.
52-4 The Java EE 7 Tutorial
Common Client Interface
■
The @ConnectionFactoryDefinition annotation is a resource definition
annotation that is used to define a connector connection factory and register it in
JNDI under the name specified in the mandatory name annotation element. The
mandatory interfaceName annotation element specifies the fully qualified name
of the connection factory interface class. The transactionSupport annotation
element specifies the level of transaction support the connection factory needs to
support. The minPoolSize and maxPoolSize annotation elements specify the
minimum or maximum number of connections that should be allocated for a
connection pool that backs this connection factory resource. Additional properties
associated with the connection factory being defined can be specified through the
properties element.
Since repeated annotations are not allowed, the @ConnectionFactoryDefinitions
annotation acts as a container for multiple connector connection factory
definitions. The value annotation element contains the multiple connector
connection factory definitions.
■
The @AdministeredObjectDefinition annotation is a resource definition
annotation that is used to define an administered object and register it in JNDI
under the name specified in the mandatory name annotation element. The
mandatory fully qualified name of the administered object's class must be
indicated by the className element. Additional properties that must be
configured in the administered object can be specified through the properties
element.
Since repeated annotations are not allowed, the @AdministeredObjectDefinitions
annotation acts as a container for multiple administered object definitions. The
value annotation element contains the multiple administered object definitions.
The specification allows a resource adapter to be developed in mixed-mode form, that
is the ability for a resource adapter developer to use both metadata annotations and
deployment descriptors in applications. An application assembler or deployer may use
the deployment descriptor to override the metadata annotations specified by the
resource adapter developer.
The deployment descriptor for a resource adapter, if present, is named ra.xml. The
metadata-complete attribute defines whether the deployment descriptor for the
resource adapter module is complete or whether the class files available to the module
and packaged with the resource adapter need to be examined for annotations that
specify deployment information.
For the complete list of annotations and JavaBeans components provided in the Java
EE 7 platform, see the Java EE Connector Architecture 1.7 specification.
52.3 Common Client Interface
This section explains how components use the Connector Architecture Common Client
Interface (CCI) API and a resource adapter to access data from an EIS. The CCI API
defines a set of interfaces and classes whose methods allow a client to perform typical
data access operations. The CCI interfaces and classes are as follows.
■
■
■
ConnectionFactory: Provides an application component with a Connection
instance to an EIS.
Connection: Represents the connection to the underlying EIS.
ConnectionSpec: Provides a means for an application component to pass
connection-request-specific properties to the ConnectionFactory when making a
connection request.
Resource Adapters and Contracts 52-5
Using Resource Adapters with Contexts and Dependency Injection for Java EE (CDI)
■
■
■
■
■
Interaction: Provides a means for an application component to execute EIS
functions, such as database stored procedures.
InteractionSpec: Holds properties pertaining to an application component's
interaction with an EIS.
Record: The superinterface for the various kinds of record instances. Record
instances can be MappedRecord, IndexedRecord, or ResultSet instances, all of
which inherit from the Record interface.
RecordFactory: Provides an application component with a Record instance.
IndexedRecord: Represents an ordered collection of Record instances based on the
java.util.List interface.
A client or application component that uses the CCI to interact with an underlying EIS
does so in a prescribed manner. The component must establish a connection to the
EIS's resource manager, and it does so using the ConnectionFactory. The Connection
object represents the connection to the EIS and is used for subsequent interactions with
the EIS.
The component performs its interactions with the EIS, such as accessing data from a
specific table, using an Interaction object. The application component defines the
Interaction object by using an InteractionSpec object. When it reads data from the
EIS, such as from database tables, or writes to those tables, the application component
does so by using a particular type of Record instance: a MappedRecord, an
IndexedRecord, or a ResultSet instance.
Note, too, that a client application that relies on a CCI resource adapter is very much
like any other Java EE client that uses enterprise bean methods.
52.4 Using Resource Adapters with Contexts and Dependency Injection
for Java EE (CDI)
For details about CDI, see Chapter 23, "Introduction to Contexts and Dependency
Injection for Java EE" and Chapter 25, "Contexts and Dependency Injection for Java EE:
Advanced Topics."
Do not specify the following classes in the resource adapter as CDI managed beans
(that is, do not inject them), because the behavior of these classes as CDI managed
beans has not been portably defined.
■
■
■
■
Resource adapter beans: These beans are classes that are annotated with the
javax.resource.spi.Connector annotation or are declared as corresponding
elements in the resource adapter deployment descriptor, ra.xml.
Managed connection factory beans: These beans are classes that are annotated
with the javax.resource.spi.ConnectorDefinition annotation or the
javax.resource.spi.ConnectorDefinitions annotation or are declared as
corresponding elements in ra.xml.
Activation specification beans: These beans are classes that are annotated with
the javax.resource.spi.Activation annotation or are declared as corresponding
elements in ra.xml.
Administered object beans: These beans are classes that are annotated with the
javax.resource.spi.AdministeredObject annotation or are declared as
corresponding elements in ra.xml.
Other types of classes in the resource adapter can be CDI managed beans and will
behave in a portable manner.
52-6 The Java EE 7 Tutorial
Further Information about Resource Adapters
52.5 Further Information about Resource Adapters
For more information about resource adapters and annotations, see
■
Java EE 7 Platform Specification (JSR 342):
http://jcp.org/en/jsr/detail?id=342
■
Java EE Connector Architecture 1.7 specification:
http://jcp.org/en/jsr/detail?id=322
■
EJB 3.2 specification:
http://jcp.org/en/jsr/detail?id=345
■
Common Annotations for the Java Platform:
http://www.jcp.org/en/jsr/detail?id=250
Resource Adapters and Contracts 52-7
Further Information about Resource Adapters
52-8 The Java EE 7 Tutorial
53
The Resource Adapter Examples
53
This chapter describes two examples that demonstrate how to use resource adapters in
Java EE applications and how to implement simple resource adapters. The trading
example shows how to use a simple custom client interface to connect to an EIS from a
web application. The resource adapter in this example implements the outbound
contract and the custom client interface. The traffic example shows how to use a
message-driven bean (MDB) to process traffic information updates from an EIS. The
resource adapter in this example implements the inbound and work management
contracts.
The following topics are addressed here:
■
The trading Example
■
The traffic Example
53.1 The trading Example
The trading example demonstrates how to implement and use a simple outbound
resource adapter that submits requests to a legacy EIS using a TCP socket. The
example demonstrates the scenario in Figure 53–1 and consists of the following
modules:
■
trading-eis: A Java SE program that simulates a legacy EIS
■
trading-rar: The outbound resource adapter implementation
■
trading-war: A web application that uses the resource adapter
■
trading-ear: An enterprise archive that contains the resource adapter and the
web application
Figure 53–1 The trading Example
Java EE Server
trading-war
(WAR)
trading.rar.api.*
trading-rar
(Resource Adapter)
TCP Socket
trading-eis
(EIS)
The trading-eis module is an auxiliary project that resembles a legacy stock trading
execution platform. It contains a Java SE program that listens for trading requests in
The Resource Adapter Examples 53-1
The trading Example
plain text on a TCP socket. The program replies to trading requests with a status value,
a confirmation number, and the dollar amounts for the requested shares and fees. For
example, a request-response pair would look like this:
>> BUY 1000 ZZZZ MARKET
<< EXECUTED #1234567 TOTAL 50400.00 FEE 252.00
The trading-rar module implements the outbound contract of the Java EE Connector
Architecture to submit requests and obtain responses from the legacy stock trading
execution platform. The trading-rar module provides and implements a custom
client interface for Java EE applications to use. This interface is simpler than the
Common Client Interface (CCI).
The trading-war module is a web application with a JavaServer Faces interface and a
managed bean. This application enables clients to submit trades to the EIS using the
resource adapter provided by the trading-rar module. The trading-war module uses
the custom client interface provided by the resource adapter to obtain connections to
the EIS.
53.1.1 Using the Outbound Resource Adapter
In most cases, Java EE application developers use outbound resource adapters
developed by a third party. Outbound resource adapters either implement the
Common Client Interface (CCI) or provide a custom interface for applications to
interact with the EIS. Outbound resource adapters provide Java EE applications with
the following elements:
■
Connection factories
■
Connection handles
■
Other interfaces and objects specific to the EIS domain
Java EE applications obtain an instance of the connection factory via resource injection
and then use the factory object to obtain connection handles to the EIS. The connection
handles enable the application to make requests and obtain information from the EIS.
The trading-rar module provides a custom client interface that consists of the classes
listed in Table 53–1.
Table 53–1
Classes and Interfaces in the javaeetutorial.trading.rar.api Package
API Component
Description
TradeOrder
Represents a trade order for the EIS
TradeResponse
Represents a response from the EIS to a trade request
TradeConnection
Represents a connection handle to the EIS
Provides a method for applications to submit trades to the EIS
TradeConnectionFactory
Enables applications to obtain connection handles to the EIS
TradeProcessingException
Indicates that a problem occurred processing a trade request
The ResourceAccessBean managed bean in the trading-war module configures a
connection factory for the trading-rar resource adapter by using the
@ConnectionFactoryDefinition annotation as follows:
@Named
@SessionScoped
@ConnectionFactoryDefinition(
name = "java:comp/env/eis/TradeConnectionFactory",
53-2 The Java EE 7 Tutorial
The trading Example
interfaceName = "javaeetutorial.trading.rar.api.TradeConnectionFactory",
resourceAdapter = "#trading-rar",
minPoolSize = 5,
transactionSupport =
TransactionSupport.TransactionSupportLevel.NoTransaction
)
public class ResourceAccessBean implements Serializable { ... }
The name parameter specifies the JNDI name for the connection factory. This example
registers the connection factory in the java:comp scope. You can use the
ConnectionFactoryDefinition annotation to specify a different scope, such as
java:global, java:app, or java:module. The AdministeredObjectDefinition
annotation also enables you to register administered connector objects in the JNDI
namespace.
The interfaceName parameter specifies the interface implemented by the connection
factory included in the resource adapter. In this example, this is a custom interface.
The resourceAdapter parameter specifies the name of the resource adapter that
contains the connection factory implementation. The # prefix in #trading-rar
indicates that trading-rar is an embedded resource adapter that is bundled in the
same EAR as this web application.
Note: You can also configure a connection factory for a previously
deployed outbound resource adapter using the administration
commands from your application server. However, this is a
vendor-specific procedure.
The managed bean obtains a connection factory object using resource injection as
follows:
...
public class ResourceAccessBean implements Serializable {
@Resource(lookup = "java:comp/env/eis/TradeConnectionFactory")
private TradeConnectionFactory connectionFactory;
...
}
The managed bean uses the connection factory to obtain connection handles as
follows:
TradeConnection connection = connectionFactory.getConnection();
The resource adapter returns a connection handle associated with a physical
connection to the EIS. Once a connection handle is available, the managed bean
submits a trade and obtains the response as follows:
TradeOrder order = new TradeOrder();
order.setNShares(1000);
order.setTicker(TradeOrder.Ticker.YYYY);
order.setOrderType(TradeOrder.OrderType.BUY);
order.setOrderClass(TradeOrder.OrderClass.MARKET);
...
try {
TradeResponse response = connection.submitOrder(order);
...
} catch (TradeProcessingException ex) { ... }
The Resource Adapter Examples 53-3
The trading Example
53.1.2 Implementing the Outbound Resource Adapter
The trading-rar module implements the outbound contract and a custom client
interface for the simple legacy stock trading platform EIS used in this example. The
architecture of the outbound resource adapter is shown in Figure 53–2.
Figure 53–2 Architecture of the trading Example
trading-war
trading.war
Web Pages
index.xhtml
ResourceAccessBean.java
trade.xhtml
Uses
trading-rar
trading.rar.api
trading.rar
TradeOrder.java
TradeResourceAdapter.java
TradeResponse.java
trading.rar.outbound
TradeConnection.java
Implements
TradeConnectionImpl.java
TradeConnectionFactory.java
Implements
TradeConnectionFactoryImpl.java
TradeManagedConnection.java
TradeProcessingException.java
Connects
to EIS
TradeManagedConnectionFactory.java
Connection Manager
The trading-rar module implements the interfaces listed in Table 53–2.
Table 53–2
Interfaces Implemented in the trading-rar Module
Package
Interface
Description
javax.resource.spi
ResourceAdapter
Defines the lifecycle methods of the
resource adapter
javax.resource.spi
ManagedConnectionFactory
Defines a connection factory that the
connection manager from the
application server uses to obtain
physical connections to the EIS
javax.resource.spi
ManagedConnection
Defines a physical connection to the
EIS that can be managed by the
connection manager
trading.rar.api
TradeConnectionFactory
Defines a connection factory that
applications use to obtain connection
handles
trading.rar.api
TradeConnection
Defines a connection handle that
applications use to interact with the
EIS
53-4 The Java EE 7 Tutorial
The trading Example
When the trading-ear archive is deployed and a connection pool resource is
configured as described in Using the Outbound Resource Adapter, the application
server creates TradeConnectionFactory objects that applications can obtain using
resource injection. The TradeConnectionFactory implementation delegates creating
connections to the connection manager provided by the application server.
The connection manager uses the ManagedConnectionFactory implementation to
obtain physical connections to the EIS and maintains a pool of active physical
connections. When an application requests a connection handle, the connection
manager associates a connection from the pool with a new connection handle that the
application can use. Connection pooling improves application performance and
simplifies resource adapter development.
For more details, see the code and the comments in the trading-rar module.
53.1.3 Running the trading Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
trading example.
53.1.3.1 To Run the trading Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/connectors
4.
Select the trading folder.
5.
Click Open Project.
6.
In the Projects tab, expand the trading node.
7.
Right-click the trading-eis module and select Open Project.
8.
Right-click the trading-eis project and select Run.
The messages from the EIS appear in the Output tab:
Trade execution server listening on port 4004.
9.
Right-click the trading-ear project and select Build.
This command packages the resource adapter and the web application in an EAR
file and deploys it to GlassFish Server.
10. Open the following URL in a web browser:
http://localhost:8080/trading/
The web interface enables you to connect to the EIS and submit trades. The server
log shows the requests from the web application and the call sequence that
provides connection handles from the resource adapter.
11. Before undeploying the trading-ear application, close the trading-eis
application from the status bar.
The Resource Adapter Examples 53-5
The traffic Example
53.1.3.2 To Run the trading Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/connectors/trading/
3.
Enter the following command:
mvn install
This command builds and packages the resource adapter and the web application
into an EAR archive and deploys it to GlassFish Server.
4.
In the same terminal window, go to the trading-eis directory:
cd trading-eis
5.
Enter the following command to run the trade execution platform:
mvn exec:java
The messages from the EIS appear in the terminal window:
Trade execution server listening on port 4004.
6.
Open the following URL in a web browser:
http://localhost:8080/trading/
The web interface enables you to connect to the EIS and submit trades. The server
log shows the requests from the web application and the call sequence that
provides connection handles from the resource adapter.
7.
Before undeploying the trading-ear application, press Ctrl+C on the terminal
window to close the trading-eis application.
53.2 The traffic Example
The traffic example demonstrates how to implement and use a simple inbound
resource adapter that receives data from a legacy EIS using a TCP socket.
The example is in the tut-install/examples/connectors/traffic directory. See
Chapter 2, "Using the Tutorial Examples," for basic information on building and
running sample applications.
The example demonstrates the scenario in Figure 53–3 and consists of the following
modules:
■
traffic-eis: A Java SE program that simulates an EIS
■
traffic-rar: The inbound resource adapter implementation
■
traffic-ejb: A message-driven bean that is the endpoint for incoming messages
■
■
traffic-war: A web application that displays information from the
message-driven bean
traffic-ear: An enterprise archive that contains the resource adapter, the
message-driven bean, and the web application
53-6 The Java EE 7 Tutorial
The traffic Example
Figure 53–3 The traffic Example
Java EE Server
traffic-war
(WAR)
JMS
Topic
traffic-ejb
(EJB)
@traffic.rar.TrafficCommand
traffic-rar
(Resource Adapter)
TCP Socket
traffic-eis
(EIS)
The traffic-eis module is an auxiliary project that resembles a legacy traffic
information system. It contains a Java SE program that sends traffic status updates for
several cities to any subscribed client. The program sends the updates in JSON format
over a TCP socket. For example, a traffic update looks like this:
{"report":[
{"city":"City1", "access":"AccessA", "status":"GOOD"},
{"city":"City1", "access":"AccessB", "status":"CONGESTED"},
...
{"city":"City5", "access":"AccessE", "status":"SLOW"}
]}
The traffic-rar module implements the inbound contract of the Java EE Connector
Architecture. This module subscribes to the traffic information system using the TCP
port indicated by the configuration provided by the MDB and invokes the methods of
the MDB to process traffic information updates.
The traffic-ejb module contains a message-driven bean that activates the resource
adapter with a configuration parameter (the TCP port to subscribe to the traffic
information system). The MDB contains a method to process the traffic information
updates. This method filters the updates for a particular city and publishes the results
to a Java Message Service (JMS) topic.
The traffic-war module contains a message-driven bean that receives filtered traffic
information updates from the JMS topic asynchronously and sends them to the clients
using a WebSocket endpoint.
53.2.1 Using the Inbound Resource Adapter
In most cases, Java EE application developers use inbound resource adapters
developed by a third party. To use an inbound resource adapter, a Java EE application
includes a message-driven bean with the following characteristics.
■
The MDB implements the business interface defined by the resource adapter.
■
The MDB specifies configuration parameters to activate the resource adapter.
The business interface defined by the resource adapter is not specified in the Java EE
Connector Architecture; it is specific to the EIS.
The Resource Adapter Examples 53-7
The traffic Example
The MDB in this example is defined as follows:
@MessageDriven(
activationConfig = {
@ActivationConfigProperty(propertyName = "port",
propertyValue = "4008")
}
)
public class TrafficMdb implements TrafficListener { ... }
The TrafficListener interface is defined in the API package of the resource adapter.
The resource adapter requires the MDB to provide the port property.
When the MDB is deployed, it activates the traffic-rar resource adapter, which
invokes the methods of the MDB to process traffic information updates. Then the MDB
filters the updates for a particular city and publishes the results to a JMS topic.
In this particular example, the TrafficListener interface is empty. In addition to this
interface, the resource adapter provides the TrafficCommand annotation and uses
reflection to discover which methods in the MDB are decorated with this annotation:
@MessageDriven(...)
public class TrafficMdb implements TrafficListener {
@TrafficCommand(name="report", info="Process report")
public void processReport(String jsonReport) { ... }
...
}
This approach enables you to adapt the MDB to support new features in the EIS
without having to modify the TrafficListener interface or the resource adapter
module.
53.2.2 Implementing the Inbound Resource Adapter
The traffic-rar module implements the inbound resource adapter contract from the
Java EE Connector Architecture for the simple traffic information system (EIS) used in
this example. The architecture of the inbound resource adapter is shown in
Figure 53–4.
53-8 The Java EE 7 Tutorial
The traffic Example
Figure 53–4 Architecture of the traffic Example
traffic-war
traffic.war
Web Pages
Accesses
TrafficEndpoint.java
index.xhtml
Invokes
WebMDB.java
Sends Updates
JMS
Topic
Publishes to
traffic-ejb
trafficmdb
Invokes
Methods
TrafficMdb.java
Uses and
Implements
Activates and
Configures
Inspects via
Reflection
traffic-rar
traffic.rar.api
traffic.rar
traffic.rar.inbound
TrafficCommand.java
TrafficResourceAdapter.java
TrafficActivationSpec.java
TrafficListener.java
TrafficServiceSubscriber.java
EIS sends updates to
The traffic-rar module implements the interfaces listed in Table 53–3.
Table 53–3
Interfaces Implemented in the traffic-rar Module
Package
Interface
Description
javax.resource.spi
ResourceAdapter
Defines the lifecycle methods of the resource
adapter.
javax.resource.spi
ActivationSpec
Defines the configuration parameters that the
MDB provides to activate the inbound resource
adapter.
javax.resource.spi
Work
The traffic service subscriber implements this
interface from the work management contract
to wait for traffic updates on a separate thread.
When an MDB activates the inbound resource adapter, the container invokes the
endpointActivation method in the TrafficResourceAdapter class:
@Connector(...)
public class TrafficResourceAdapter implements ResourceAdapter, Serializable {
...
The Resource Adapter Examples 53-9
The traffic Example
@Override
public void endpointActivation(MessageEndpointFactory endpointFactory,
ActivationSpec spec)
throws ResourceException {
Class endpointClass = endpointFactory.getEndpointClass();
/* this method is called from a new thread in the example:
MessageEndpoint endpoint = endpointFactory.createEndpoint(null); */
}
}
The getEndpointClass method returns the Class type of the MDB performing the
activation, which enables the resource adapter to use reflection to find methods
annotated with @TrafficCommand in the MDB.
The createEndpoint method returns an instance of the MDB. The resource adapter
uses this instance to invoke the methods of the MDB when it receives requests from
the EIS.
After obtaining the message endpoint instance (MDB), the resource adapter uses the
work management contract to create the traffic service subscriber thread that receives
traffic updates from the EIS. The resource adapter obtains the WorkManager instance
from the bootstrap context as follows:
WorkManager workManager;
...
@Override
public void start(BootstrapContext ctx) ... {
workManager = ctx.getWorkManager();
}
The resource adapter schedules the traffic service subscriber thread using the work
manager:
tSubscriber = new TrafficServiceSubscriber(tSpec, endpoint);
workManager.scheduleWork(tSubscriber);
The TrafficServiceSubscriber class implements the javax.resource.spi.Work
interface from the work management contract.
The traffic service subscriber thread uses reflection to invoke the methods in the MDB:
private String callMdb(MessageEndpoint mdb, Method command,
String... params) ... {
String resp;
/* this code contains proper exception handling in the sources */
mdb.beforeDelivery(command);
Object ret = command.invoke(mdb, (Object[]) params);
resp = (String) ret;
mdb.afterDelivery();
return resp;
}
For more details, see the code and the comments in the traffic-rar module.
53.2.3 Running the traffic Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
traffic example.
53-10 The Java EE 7 Tutorial
The traffic Example
53.2.3.1 To Run the traffic Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/connectors
4.
Select the traffic folder.
5.
Click Open Project.
6.
In the Projects tab, expand the traffic node.
7.
Right-click the traffic-eis module and select Open Project.
8.
Right-click the traffic-eis project and select Run.
The messages from the EIS appear on the Output tab:
Traffic EIS accepting connections on port 4008
9.
In the Projects tab, right-click the traffic project and select Clean and Build.
This command builds and packages the resource adapter, the MDB, and the web
application into an EAR archive and deploys it. The server log shows the call
sequence that activates the resource adapter and the filtered traffic updates for
City1.
10. Open the following URL in a web browser:
http://localhost:8080/traffic/
The web interface shows filtered traffic updates for City1 every few seconds.
11. After undeploying the traffic-ear application, close the traffic-eis application
from the status bar.
53.2.3.2 To Run the traffic Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/connectors/traffic/traffic-eis/
3.
Enter the following command in the terminal window:
mvn install
This command builds and packages the traffic EIS.
4.
Enter the following command in the terminal window:
mvn exec:java
The messages from the EIS appear in the terminal window:
Traffic EIS accepting connections on port 4008
Leave this terminal window open.
5.
Open a new terminal window and go to:
The Resource Adapter Examples
53-11
The traffic Example
tut-install/examples/connectors/traffic/
6.
Enter the following command:
mvn install
This command builds and packages the resource adapter, the MDB, and the web
application into an EAR archive and deploys it. The server log shows the call
sequence that activates the resource adapter and the filtered traffic updates for
City1.
7.
Open the following URL in a web browser:
http://localhost:8080/traffic/
The web interface shows the filtered traffic updates for City1 every few seconds.
8.
After undeploying the traffic-ear application, press Ctrl+C in the first terminal
window to close the traffic-eis application.
53-12 The Java EE 7 Tutorial
54
Using Java EE Interceptors
54
This chapter discusses how to create interceptor classes and methods that interpose on
method invocations or lifecycle events on a target class.
The following topics are addressed here:
■
Overview of Interceptors
■
Using Interceptors
■
The interceptor Example Application
54.1 Overview of Interceptors
Interceptors are used in conjunction with Java EE managed classes to allow developers
to invoke interceptor methods on an associated target class, in conjunction with
method invocations or lifecycle events. Common uses of interceptors are logging,
auditing, and profiling.
Although interceptors are part of Enterprise JavaBeans 3.2 and Contexts and
Dependency Injection for Java EE 1.1, the Interceptors 1.2 specification is
downloadable as part of a maintenance release of JSR 318, Enterprise JavaBeans 3.1,
available from http://jcp.org/en/jsr/detail?id=318. You can use
interceptors with session beans, message-driven beans, and CDI managed beans. In all
of these cases, the interceptor target class is the bean class.
An interceptor can be defined within a target class as an interceptor method, or in an
associated class called an interceptor class. Interceptor classes contain methods that
are invoked in conjunction with the methods or lifecycle events of the target class.
Interceptor classes and methods are defined using metadata annotations, or in the
deployment descriptor of the application that contains the interceptors and target
classes.
Note: Applications that use the deployment descriptor to define
interceptors are not portable across Java EE servers.
Interceptor methods within the target class or in an interceptor class are annotated
with one of the metadata annotations defined in Table 54–1.
Using Java EE Interceptors 54-1
Using Interceptors
Table 54–1
Interceptor Metadata Annotations
Interceptor Metadata Annotation
Description
javax.interceptor.AroundConstruct
Designates the method as an interceptor method
that receives a callback after the target class is
constructed
javax.interceptor.AroundInvoke
Designates the method as an interceptor method
javax.interceptor.AroundTimeout
Designates the method as a timeout interceptor for
interposing on timeout methods for enterprise bean
timers
javax.annotation.PostConstruct
Designates the method as an interceptor method for
post-construct lifecycle events
javax.annotation.PreDestroy
Designates the method as an interceptor method for
pre-destroy lifecycle events
54.1.1 Interceptor Classes
Interceptor classes may be designated with the optional
javax.interceptor.Interceptor annotation, but interceptor classes are not required
to be so annotated. An interceptor class must have a public, no-argument constructor.
The target class can have any number of interceptor classes associated with it. The
order in which the interceptor classes are invoked is determined by the order in which
the interceptor classes are defined in the javax.interceptor.Interceptors
annotation. However, this order can be overridden in the deployment descriptor.
Interceptor classes may be targets of dependency injection. Dependency injection
occurs when the interceptor class instance is created, using the naming context of the
associated target class, and before any @PostConstruct callbacks are invoked.
54.1.2 Interceptor Lifecycle
Interceptor classes have the same lifecycle as their associated target class. When a
target class instance is created, an interceptor class instance is also created for each
declared interceptor class in the target class. That is, if the target class declares multiple
interceptor classes, an instance of each class is created when the target class instance is
created. The target class instance and all interceptor class instances are fully
instantiated before any @PostConstruct callbacks are invoked, and any @PreDestroy
callbacks are invoked before the target class and interceptor class instances are
destroyed.
54.1.3 Interceptors and CDI
Contexts and Dependency Injection for Java EE (CDI) builds on the basic functionality
of Java EE interceptors. For information on CDI interceptors, including a discussion of
interceptor binding types, see Using Interceptors in CDI Applications.
54.2 Using Interceptors
To define an interceptor, use one of the interceptor metadata annotations listed in
Table 54–1 within the target class, or in a separate interceptor class. The following code
declares an @AroundTimeout interceptor method within a target class:
@Stateless
public class TimerBean {
...
54-2 The Java EE 7 Tutorial
Using Interceptors
@Schedule(minute="*/1", hour="*")
public void automaticTimerMethod() { ... }
@AroundTimeout
public void timeoutInterceptorMethod(InvocationContext ctx) { ... }
...
}
If you are using interceptor classes, use the javax.interceptor.Interceptors
annotation to declare one or more interceptors at the class or method level of the target
class. The following code declares interceptors at the class level:
@Stateless
@Interceptors({PrimaryInterceptor.class, SecondaryInterceptor.class})
public class OrderBean { ... }
The following code declares a method-level interceptor class:
@Stateless
public class OrderBean {
...
@Interceptors(OrderInterceptor.class)
public void placeOrder(Order order) { ... }
...
}
54.2.1 Intercepting Method Invocations
Use the @AroundInvoke annotation to designate interceptor methods for managed
object methods. Only one around-invoke interceptor method per class is allowed.
Around-invoke interceptor methods have the following form:
@AroundInvoke
visibility Object method-name(InvocationContext) throws Exception { ... }
For example:
@AroundInvoke
public void interceptOrder(InvocationContext ctx) { ... }
Around-invoke interceptor methods can have public, private, protected, or
package-level access, and must not be declared static or final.
An around-invoke interceptor can call any component or resource that is callable by
the target method on which it interposes, can have the same security and transaction
context as the target method, and can run in the same Java virtual machine call stack
as the target method.
Around-invoke interceptors can throw runtime exceptions and any exception allowed
by the throws clause of the target method. They may catch and suppress exceptions,
and then recover by calling the InvocationContext.proceed method.
54.2.1.1 Using Multiple Method Interceptors
Use the @Interceptors annotation to declare multiple interceptors for a target method
or class:
@Interceptors({PrimaryInterceptor.class, SecondaryInterceptor.class,
LastInterceptor.class})
public void updateInfo(String info) { ... }
Using Java EE Interceptors 54-3
Using Interceptors
The order of the interceptors in the @Interceptors annotation is the order in which the
interceptors are invoked.
You can also define multiple interceptors in the deployment descriptor. The order of
the interceptors in the deployment descriptor is the order in which the interceptors
will be invoked:
...
<interceptor-binding>
<target-name>myapp.OrderBean</target-name>
<interceptor-class>myapp.PrimaryInterceptor.class</interceptor-class>
<interceptor-class>myapp.SecondaryInterceptor.class</interceptor-class>
<interceptor-class>myapp.LastInterceptor.class</interceptor-class>
<method-name>updateInfo</method-name>
</interceptor-binding>
...
To explicitly pass control to the next interceptor in the chain, call the
InvocationContext.proceed method.
Data can be shared across interceptors.
■
■
The same InvocationContext instance is passed as an input parameter to each
interceptor method in the interceptor chain for a particular target method. The
InvocationContext instance's contextData property is used to pass data across
interceptor methods. The contextData property is a java.util.Map<String,
Object> object. Data stored in contextData is accessible to interceptor methods
further down the interceptor chain.
The data stored in contextData is not sharable across separate target class method
invocations. That is, a different InvocationContext object is created for each
invocation of the method in the target class.
54.2.1.2 Accessing Target Method Parameters from an Interceptor Class
You can use the InvocationContext instance passed to each around-invoke method to
access and modify the parameters of the target method. The parameters property of
InvocationContext is an array of Object instances that corresponds to the parameter
order of the target method. For example, for the following target method, the
parameters property, in the InvocationContext instance passed to the around-invoke
interceptor method in PrimaryInterceptor, is an Object array containing two String
objects (firstName and lastName) and a Date object (date):
@Interceptors(PrimaryInterceptor.class)
public void updateInfo(String firstName, String lastName, Date date) { ... }
You can access and modify the parameters by using the
InvocationContext.getParameters and InvocationContext.setParameters
methods, respectively.
54.2.2 Intercepting Lifecycle Callback Events
Interceptors for lifecycle callback events (around-construct, post-construct, and
pre-destroy) may be defined in the target class or in interceptor classes. The
javax.interceptor.AroundConstruct annotation designates the method as an
interceptor method that interposes on the invocation of the target class's constructor.
The javax.annotation.PostConstruct annotation is used to designate a method as a
post-construct lifecycle event interceptor. The javax.annotation.PreDestroy
annotation is used to designate a method as a pre-destroy lifecycle event interceptor.
54-4 The Java EE 7 Tutorial
Using Interceptors
Lifecycle event interceptors defined within the target class have the following form:
void method-name() { ... }
For example:
@PostConstruct
void initialize() { ... }
Lifecycle event interceptors defined in an interceptor class have the following form:
void method-name(InvocationContext) { ... }
For example:
@PreDestroy
void cleanup(InvocationContext ctx) { ... }
Lifecycle interceptor methods can have public, private, protected, or package-level
access, and must not be declared static or final. Lifecycle interceptors may throw
runtime exceptions but cannot throw checked exceptions.
Lifecycle interceptor methods are called in an unspecified security and transaction
context. That is, portable Java EE applications should not assume the lifecycle event
interceptor method has access to a security or transaction context. Only one interceptor
method for each lifecycle event (post-create and pre-destroy) is allowed per class.
54.2.2.1 Using AroundConstruct Interceptor Methods
@AroundConstruct methods are interposed on the invocation of the target class's
constructor. Methods decorated with @AroundConstruct may only be defined within
interceptor classes or superclasses of interceptor classes. You may not use
@AroundConstruct methods within the target class.
The @AroundConstruct method is called after dependency injection has been
completed for all interceptors associated with the target class. The target class is
created and the target class's constructor injection is performed after all associated
@AroundConstruct methods have called the Invocation.proceed method. At that
point, dependency injection for the target class is completed, and then any
@PostConstruct callback methods are invoked.
@AroundConstruct methods can access the constructed target instance after calling
Invocation.proceed by calling the InvocationContext.getTarget method.
Calling methods on the target instance from an
@AroundConstruct method is dangerous because dependency
injection may not have completed on the target instance.
Caution:
@AroundConstruct methods must call Invocation.proceed in order to create the target
instance. If an @AroundConstruct method does not call Invocation.proceed, the target
instance will not be created.
54.2.2.2 Using Multiple Lifecycle Callback Interceptors
You can define multiple lifecycle interceptors for a target class by specifying the
interceptor classes in the @Interceptors annotation:
@Interceptors({PrimaryInterceptor.class, SecondaryInterceptor.class,
LastInterceptor.class})
@Stateless
Using Java EE Interceptors 54-5
Using Interceptors
public class OrderBean { ... }
Data stored in the contextData property of InvocationContext is not sharable across
different lifecycle events.
54.2.3 Intercepting Timeout Events
You can define interceptors for EJB timer service timeout methods by using the
@AroundTimeout annotation on methods in the target class or in an interceptor class.
Only one @AroundTimeout method per class is allowed.
Timeout interceptors have the following form:
Object method-name(InvocationContext) throws Exception { ... }
For example:
@AroundTimeout
protected void timeoutInterceptorMethod(InvocationContext ctx) { ... }
Timeout interceptor methods can have public, private, protected, or package-level
access, and must not be declared static or final.
Timeout interceptors can call any component or resource callable by the target timeout
method, and are invoked in the same transaction and security context as the target
method.
Timeout interceptors may access the timer object associated with the target timeout
method through the InvocationContext instance's getTimer method.
54.2.3.1 Using Multiple Timeout Interceptors
You can define multiple timeout interceptors for a given target class by specifying the
interceptor classes containing @AroundTimeout interceptor methods in an
@Interceptors annotation at the class level.
If a target class specifies timeout interceptors in an interceptor class, and also has an
@AroundTimeout interceptor method within the target class itself, the timeout
interceptors in the interceptor classes are called first, followed by the timeout
interceptors defined in the target class. For example, in the following example, assume
that both the PrimaryInterceptor and SecondaryInterceptor classes have timeout
interceptor methods:
@Interceptors({PrimaryInterceptor.class, SecondaryInterceptor.class})
@Stateful
public class OrderBean {
...
@AroundTimeout
private void last(InvocationContext ctx) { ... }
...
}
The timeout interceptor in PrimaryInterceptor will be called first, followed by the
timeout interceptor in SecondaryInterceptor, and finally the last method defined in
the target class.
54.2.4 Binding Interceptors to Components
Interceptor binding types are annotations that may be applied to components to
associate them with a particular interceptor. Interceptor binding types are typically
custom runtime annotation types that specify the interceptor target. Use the
54-6 The Java EE 7 Tutorial
Using Interceptors
javax.interceptor.InterceptorBinding annotation on the custom annotation
definition and specify the target by using @Target, setting one or more of TYPE
(class-level interceptors), METHOD (method-level interceptors), CONSTRUCTOR
(around-construct interceptors), or any other valid target:
@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Inherited
pubic @interface Logged { ... }
Interceptor binding types may also be applied to other interceptor binding types:
@Logged
@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Inherited
public @interface Secured { ... }
54.2.4.1 Declaring the Interceptor Bindings on an Interceptor Class
Annotate the interceptor class with the interceptor binding type and @Interceptor to
associate the interceptor binding with the interceptor class:
@Logged
@Interceptor
public class LoggingInterceptor {
@AroundInvoke
public Object logInvocation(InvocationContext ctx) throws Exception { ... }
...
}
An interceptor class may declare multiple interceptor binding types, and more than
one interceptor class may declare an interceptor binding type.
If the interceptor class intercepts lifecycle callbacks, it can only declare interceptor
binding types with Target(TYPE), or in the case of @AroundConstruct lifecycle
callbacks, Target(CONSTRUCTOR).
54.2.4.2 Binding a Component to an Interceptor
Add the interceptor binding type annotation to the target component's class, method,
or constructor. Interceptor binding types are applied using the same rules as
@Interceptor annotations:
@Logged
public class Message {
...
@Secured
public void getConfidentialMessage() { ... }
...
}
If the component has a class-level interceptor binding, it must not be final or have
any non-static, non-private final methods. If a non-static, non-private method
has an interceptor binding applied to it, it must not be final, and the component class
cannot be final.
Using Java EE Interceptors 54-7
Using Interceptors
54.2.5 Ordering Interceptors
The order in which multiple interceptors are invoked is determined by the following
rules.
■
■
■
■
■
■
Default interceptors are defined in a deployment descriptor, and are invoked first.
They may specify the invocation order or override the order specified using
annotations. Default interceptors are invoked in the order in which they are
defined in the deployment descriptor.
The order in which the interceptor classes are listed in the @Interceptors
annotation defines the order in which the interceptors are invoked. Any @Priority
settings for interceptors listed within an @Interceptors annotation are ignored.
If the interceptor class has superclasses, the interceptors defined on the
superclasses are invoked first, starting with the most general superclass.
Interceptor classes may set the priority of the interceptor methods by setting a
value within a javax.annotation.Priority annotation.
After the interceptors defined within interceptor classes have been invoked, the
target class's constructor, around-invoke, or around-timeout interceptors are
invoked in the same order as the interceptors within the @Interceptors
annotation.
If the target class has superclasses, any interceptors defined on the superclasses are
invoked first, starting with the most general superclass.
The @Priority annotation requires an int value as an element. The lower the number,
the higher the priority of the associated interceptor.
The invocation order of interceptors with the same priority
value is implementation-specific.
Note:
The javax.interceptor.Interceptor.Priority class defines the priority constants
listed in Table 54–2.
Table 54–2
Interceptor Priority Constants
Priority Constant
Value
Description
PLATFORM_BEFORE
0
Interceptors defined by the Java EE Platform and
intended to be invoked early in the invocation chain
should use the range between PLATFORM_BEFORE and
LIBRARY_BEFORE. These interceptors have the highest
priority.
LIBRARY_BEFORE
1000
Interceptors defined by extension libraries that should be
invoked early in the interceptor chain should use the
range between LIBRARY_BEFORE and APPLICATION.
APPLICATION
2000
Interceptors defined by applications should use the range
between APPLICATION and LIBRARY_AFTER.
LIBRARY_AFTER
3000
Low priority interceptors defined by extension libraries
should use the range between LIBRARY_AFTER and
PLATFORM_AFTER.
PLATFORM_AFTER
4000
Low priority interceptors defined by the Java EE Platform
should have values higher than PLATFORM_AFTER.
54-8 The Java EE 7 Tutorial
The interceptor Example Application
Negative priority values are reserved by the Interceptors
specification for future use, and should not be used.
Note:
The following code snippet shows how to use the priority constants in an
application-defined interceptor:
@Interceptor
@Priority(Interceptor.Priority.APPLICATION+200
public class MyInterceptor { ... }
54.3 The interceptor Example Application
The interceptor example demonstrates how to use an interceptor class, containing an
@AroundInvoke interceptor method, with a stateless session bean.
The HelloBean stateless session bean is a simple enterprise bean with two business
methods, getName and setName, to retrieve and modify a string. The setName business
method has an @Interceptors annotation that specifies an interceptor class,
HelloInterceptor, for that method:
@Interceptors(HelloInterceptor.class)
public void setName(String name) {
this.name = name;
}
The HelloInterceptor class defines an @AroundInvoke interceptor method,
modifyGreeting, that converts the string passed to HelloBean.setName to lowercase:
@AroundInvoke
public Object modifyGreeting(InvocationContext ctx) throws Exception {
Object[] parameters = ctx.getParameters();
String param = (String) parameters[0];
param = param.toLowerCase();
parameters[0] = param;
ctx.setParameters(parameters);
try {
return ctx.proceed();
} catch (Exception e) {
logger.warning("Error calling ctx.proceed in modifyGreeting()");
return null;
}
}
The parameters to HelloBean.setName are retrieved and stored in an Object array by
calling the InvocationContext.getParameters method. Because setName only has one
parameter, it is the first and only element in the array. The string is set to lowercase
and stored in the parameters array, then passed to
InvocationContext.setParameters. To return control to the session bean,
InvocationContext.proceed is called.
The user interface of interceptor is a JavaServer Faces web application that consists
of two Facelets views: index.xhtml, which contains a form for entering the name, and
response.xhtml, which displays the final name.
54.3.1 Running the interceptor Example
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
interceptor example.
Using Java EE Interceptors 54-9
The interceptor Example Application
54.3.1.1 To Run the interceptor Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/ejb
4.
Select the interceptor folder and click Open Project.
5.
In the Projects tab, right-click the interceptor project and select Run.
This will compile, deploy, and run the interceptor example, opening a web
browser to the following URL:
http://localhost:8080/interceptor/
6.
Enter a name into the form and click Submit.
The name will be converted to lowercase by the method interceptor defined in the
HelloInterceptor class.
54.3.1.2 To Run the interceptor Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
Go to the following directory:
tut-install/examples/ejb/interceptor/
3.
To compile the source files and package the application, use the following
command:
mvn install
This command builds and packages the application into a WAR file,
interceptor.war, located in the target directory. The WAR file is then deployed
to GlassFish Server.
4.
Open the following URL in a web browser:
http://localhost:8080/interceptor/
5.
Enter a name into the form and click Submit.
The name will be converted to lowercase by the method interceptor defined in the
HelloInterceptor class.
54-10 The Java EE 7 Tutorial
55
Batch Processing
55
This chapter describes Batch Applications for the Java Platform (JSR 352), which
provides support for defining, implementing, and running batch jobs. Batch jobs are
tasks that can be executed without user interaction. The batch framework is composed
of a job specification language based on XML, a Java API, and a batch runtime.
Some enterprise applications contain tasks that can be executed without user
interaction. These tasks are executed periodically or when resource usage is low, and
they often process large amounts of information such as log files, database records, or
images. Examples include billing, report generation, data format conversion, and
image processing. These tasks are called batch jobs.
Batch processing refers to running batch jobs on a computer system. Java EE includes
a batch processing framework that provides the batch execution infrastructure
common to all batch applications, enabling developers to concentrate on the business
logic of their batch applications. The batch framework consists of a job specification
language based on XML, a set of batch annotations and interfaces for application
classes that implement the business logic, a batch container that manages the
execution of batch jobs, and supporting classes and interfaces to interact with the batch
container.
The following topics are addressed here:
■
Introduction to Batch Processing
■
Batch Processing in Java EE
■
Simple Use Case
■
Using the Job Specification Language
■
Creating Batch Artifacts
■
Submitting Jobs to the Batch Runtime
■
Packaging Batch Applications
■
The webserverlog Example Application
■
The phonebilling Example Application
■
Further Information about Batch Processing
55.1 Introduction to Batch Processing
A batch job can be completed without user intervention. For example, consider a
telephone billing application that reads phone call records from the enterprise
information systems and generates a monthly bill for each account. Since this
application does not require any user interaction, it can run as a batch job.
Batch Processing
55-1
Introduction to Batch Processing
The phone billing application consists of two phases: The first phase associates each
call from the registry with a monthly bill, and the second phase calculates the tax and
total amount due for each bill. Each of these phases is a step of the batch job.
Batch applications specify a set of steps and their execution order. Different batch
frameworks may specify additional elements, like decision elements or groups of steps
that run in parallel. The following sections describe steps in more detail and provide
information about other common characteristics of batch frameworks.
55.1.1 Steps in Batch Jobs
A step is an independent and sequential phase of a batch job. Batch jobs contain
chunk-oriented steps and task-oriented steps.
Chunk-oriented steps (chunk steps) process data by reading items from a data
source, applying some business logic to each item, and storing the results. Chunk
steps read and process one item at a time and group the results into a chunk. The
results are stored when the chunk reaches a configurable size. Chunk-oriented
processing makes storing results more efficient and facilitates transaction
demarcation.
■
Chunk steps have three parts.
–
The input retrieval part reads one item at a time from a data source, such as
entries on a database, files in a directory, or entries in a log file.
–
The business processing part manipulates one item at a time using the
business logic defined by the application. Examples include filtering,
formatting, and accessing data from the item for computing a result.
–
The output writing part stores a chunk of processed items at a time.
Chunk steps are often long-running because they process large amounts of data.
Batch frameworks enable chunk steps to bookmark their progress using
checkpoints. A chunk step that is interrupted can be restarted from the last
checkpoint. The input retrieval and output writing parts of a chunk step save their
current position after the processing of each chunk, and can recover it when the
step is restarted.
Figure 55–1 shows the three parts of two steps in a batch job.
Figure 55–1 Chunk Steps in a Batch Job
Job
STEP A
Input Retrieval A
Business Processing A
Output Writing A
STEP B
Input Retrieval B
Business Processing B
Output Writing B
...
■
Task-oriented steps (task steps) execute tasks other than processing items from a
data source. Examples include creating or removing directories, moving files,
creating or dropping database tables, configuring resources, and so on. Task steps
are not usually long-running compared to chunk steps.
For example, the phone billing application consists of two chunk steps.
55-2 The Java EE 7 Tutorial
Introduction to Batch Processing
■
■
In the first step, the input retrieval part reads call records from the registry; the
business processing part associates each call with a bill and creates a bill if one
does not exist for an account; and the output writing part stores each bill in a
database.
In the second step, the input retrieval part reads bills from the database; the
business processing part calculates the tax and total amount due for each bill; and
the output writing part updates the database records and generates printable
versions of each bill.
This application could also contain a task step that cleaned up the files from the bills
generated for the previous month.
55.1.2 Parallel Processing
Batch jobs often process large amounts of data or perform computationally expensive
operations. Batch applications can benefit from parallel processing in two scenarios.
■
■
Steps that do not depend on each other can run on different threads.
Chunk-oriented steps where the processing of each item does not depend on the
results of processing previous items can run on more than one thread.
Batch frameworks provide mechanisms for developers to define groups of
independent steps and to split chunk-oriented steps in parts that can run in parallel.
55.1.3 Status and Decision Elements
Batch frameworks keep track of a status for every step in a job. The status indicates if a
step is running or if it has completed. If the step has completed, the status indicates
one of the following.
■
The execution of the step was successful.
■
The step was interrupted.
■
An error occurred in the execution of the step.
In addition to steps, batch jobs can also contain decision elements. Decision elements
use the exit status of the previous step to determine the next step or to terminate the
batch job. Decision elements set the status of the batch job when terminating it. Like a
step, a batch job can terminate successfully, be interrupted, or fail.
Figure 55–2 shows an example of a job that contains chunk steps, task steps and a
decision element.
Batch Processing
55-3
Batch Processing in Java EE
Figure 55–2 Steps and Decision Elements in a Job
Job
Start
STEP A (chunk)
Input Retrieval A
Business Processing A
Output Writing A
STEP B (task)
Task B
Decision D
condition 1
End
Job
condition 2
STEP C (chunk)
Input Retrieval C
Business Processing C
Output Writing C
End
Job
55.1.4 Batch Framework Functionality
Batch applications have the following common requirements.
■
Define jobs, steps, decision elements, and the relationships between them.
■
Execute some groups of steps or parts of a step in parallel.
■
Maintain state information for jobs and steps.
■
Launch jobs and resume interrupted jobs.
■
Handle errors.
Batch frameworks provide the batch execution infrastructure that addresses the
common requirements of all batch applications, enabling developers to concentrate on
the business logic of their applications. Batch frameworks consist of a format to specify
jobs and steps, an application programming interface (API), and a service available at
runtime that manages the execution of batch jobs.
55.2 Batch Processing in Java EE
This section lists the components of the batch processing framework in Java EE and
provides an overview of the steps you have to follow to create a batch application.
55.2.1 The Batch Processing Framework
Java EE includes a batch processing framework that consists of the following elements:
55-4 The Java EE 7 Tutorial
Batch Processing in Java EE
■
A batch runtime that manages the execution of jobs
■
A job specification language based on XML
■
A Java API to interact with the batch runtime
■
A Java API to implement steps, decision elements, and other batch artifacts
Batch applications in Java EE contain XML files and Java classes. The XML files define
the structure of a job in terms of batch artifacts and the relationships between them. (A
batch artifact is a part of a chunk-oriented step, a task-oriented step, a decision
element, or another component of a batch application). The Java classes implement the
application logic of the batch artifacts defined in the XML files. The batch runtime
parses the XML files and loads the batch artifacts as Java classes to run the jobs in a
batch application.
55.2.2 Creating Batch Applications
The process for creating a batch application in Java EE is the following.
1.
Design the batch application.
a.
Identify the input sources, the format of the input data, the desired final result,
and the required processing phases.
b.
Organize the application as a job with chunk-oriented steps, task-oriented
steps, and decision elements. Determine the dependencies between them.
c.
Determine the order of execution in terms of transitions between steps.
d.
Identify steps that can run in parallel and steps that can run in more than one
thread.
2.
Create the batch artifacts as Java classes by implementing the interfaces specified
by the framework for steps, decision elements, and so on. These Java classes
contain the code to read data from input sources, format items, process items, and
store results. Batch artifacts can access context objects from the batch runtime
using dependency injection.
3.
Define jobs, steps, and their execution flow in XML files using the Job Specification
Language. The elements in the XML files reference batch artifacts implemented as
Java classes. The batch artifacts can access properties declared in the XML files,
such as names of files and databases.
4.
Use the Java API provided by the batch runtime to launch the batch application.
The following sections describe in detail how to use the components of the batch
processing framework in Java EE to create batch applications.
55.2.3 Elements of a Batch Job
A batch job can contain one or more of the following elements:
■
Steps
■
Flows
■
Splits
■
Decision elements
Steps are described in Introduction to Batch Processing, and can be chunk-oriented or
task-oriented. Chunk-oriented steps can be partitioned steps. In a partitioned chunk
Batch Processing
55-5
Batch Processing in Java EE
step, the processing of one item does not depend on other items, so these steps can run
in more than one thread.
A flow is a sequence of steps that execute as a unit. A sequence of related steps can be
grouped together into a flow. The steps in a flow cannot transition to steps outside the
flow. The flow transitions to the next element when its last step completes.
A split is a set of flows that execute in parallel; each flow runs on a separate thread.
The split transitions to the next element when all its flows complete.
Decision elements use the exit status of the previous step to determine the next step or
to terminate the batch job.
55.2.4 Properties and Parameters
Jobs and steps can have a number of properties associated with them. You define
properties in the job definition file, and batch artifacts access these properties using
context objects from the batch runtime. Using properties in this manner enables you to
decouple static parameters of the job from the business logic and to reuse batch
artifacts in different job definition files.
Specifying properties is described in Using the Job Specification Language, and
accessing properties in batch artifacts is described in Creating Batch Artifacts.
Java EE applications can also pass parameters to a job when they submit it to the batch
runtime. This enables you to specify dynamic parameters that are only known at
runtime. Parameters are also necessary for partitioned steps, since each partition needs
to know, for example, what range of items to process.
Specifying parameters when submitting jobs is described in Submitting Jobs to the
Batch Runtime. Specifying parameters for partitioned steps and accessing them in
batch artifacts is demonstrated in The phonebilling Example Application.
55.2.5 Job Instances and Job Executions
A job definition can have multiple instances, each with different parameters. A job
execution is an attempt to run a job instance. The batch runtime maintains information
about job instances and job executions, as described in Checking the Status of a Job.
55.2.6 Batch and Exit Status
The state of jobs, steps, splits, and flows is represented in the batch runtime as a batch
status value. Batch status values are listed Table 55–1. They are represented as strings.
Table 55–1
Batch Status Values
Value
Description
STARTING
The job has been submitted to the batch runtime.
STARTED
The job is running.
STOPPING
The job has been requested to stop.
STOPPED
The job has stopped.
FAILED
The job finished executing because of an error.
COMPLETED
The job finished executing successfully.
ABANDONED
The job was marked abandoned.
55-6 The Java EE 7 Tutorial
Simple Use Case
Java EE applications can submit jobs and access the batch status of a job using the
JobOperator interface, as described in Submitting Jobs to the Batch Runtime. Job
definition files can refer to batch status values using the Job Specification Language
(JSL), as described in Using the Job Specification Language. Batch artifacts can access
batch status values using context objects, as described in Using the Context Objects
from the Batch Runtime.
For flows, the batch status is that of its last step. For splits, the batch status is the
following:
■
COMPLETED: If all its flows have a batch status of COMPLETED
■
FAILED: If any flow has a batch status of FAILED
■
STOPPED: If any flow has a batch status of STOPPED, and no flows have a batch
status of FAILED
The batch status for jobs, steps, splits, and flows is set by the batch runtime. Jobs,
steps, splits, and flows also have an exit status, which is a user-defined value based on
the batch status. You can set the exit status inside batch artifacts or in the job definition
file. You can access the exit status in the same manner as the batch status, described
above. The default value for the exit status is the same as the batch status.
55.3 Simple Use Case
This section demonstrates how to define a simple job using the Job Specification
Language (JSL) and how to implement the corresponding batch artifacts. Refer to the
rest of the sections in this chapter for detailed descriptions of the elements in the batch
framework.
The following job definition specifies a chunk step and a task step as follows:
<?xml version="1.0" encoding="UTF-8"?>
<job id="simplejob" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
version="1.0">
<properties>
<property name="input_file" value="input.txt"/>
<property name="output_file" value="output.txt"/>
</properties>
<step id="mychunk" next="mytask">
<chunk>
<reader ref="MyReader"></reader>
<processor ref="MyProcessor"></processor>
<writer ref="MyWriter"></writer>
</chunk>
</step>
<step id="mytask">
<batchlet ref="MyBatchlet"></batchlet>
<end on="COMPLETED"/>
</step>
</job>
55.3.1 Chunk Step
In most cases, you have to implement a checkpoint class for chunk-oriented steps. The
following class just keeps track of the line number in a text file:
public class MyCheckpoint implements Serializable {
private long lineNum = 0;
public void increase() { lineNum++; }
public long getLineNum() { return lineNum; }
Batch Processing
55-7
Simple Use Case
}
The following item reader implementation continues reading the input file from the
provided checkpoint if the job was restarted. The items consist of each line in the text
file (in more complex scenarios, the items are custom Java types and the input source
can be a database):
@Dependent
@Named("MyReader")
public class MyReader implements javax.batch.api.chunk.ItemReader {
private MyCheckpoint checkpoint;
private BufferedReader breader;
@Inject
JobContext jobCtx;
public MyReader() {}
@Override
public void open(Serializable ckpt) throws Exception {
if (ckpt == null)
checkpoint = new MyCheckpoint();
else
checkpoint = (MyCheckpoint) ckpt;
String fileName = jobCtx.getProperties()
.getProperty("input_file");
breader = new BufferedReader(new FileReader(fileName));
for (long i = 0; i < checkpoint.getLineNum(); i++)
breader.readLine();
}
@Override
public void close() throws Exception {
breader.close();
}
@Override
public Object readItem() throws Exception {
String line = breader.readLine();
return line;
}
}
In the following case, the item processor only converts the line to uppercase. More
complex examples can process items in different ways or transform them into custom
output Java types:
@Dependent
@Named("MyProcessor")
public class MyProcessor implements javax.batch.api.chunk.ItemProcessor {
public MyProcessor() {}
@Override
public Object processItem(Object obj) throws Exception {
String line = (String) obj;
return line.toUpperCase();
}
}
55-8 The Java EE 7 Tutorial
Simple Use Case
Note: The batch processing API does not support generics. In most
cases, you need to cast items to their specific type before processing
them.
The item writer writes the processed items to the output file. It overwrites the output
file if no checkpoint is provided; otherwise, it resumes writing at the end of the file.
Items are written in chunks:
@Dependent
@Named("MyWriter")
public class MyWriter implements javax.batch.api.chunk.ItemWriter {
private BufferedWriter bwriter;
@Inject
private JobContext jobCtx;
@Override
public void open(Serializable ckpt) throws Exception {
String fileName = jobCtx.getProperties()
.getProperty("output_file");
bwriter = new BufferedWriter(new FileWriter(fileName,
(ckpt != null)));
}
@Override
public void writeItems(List<Object> items) throws Exception {
for (int i = 0; i < items.size(); i++) {
String line = (String) items.get(i);
bwriter.write(line);
bwriter.newLine();
}
}
@Override
public Serializable checkpointInfo() throws Exception {
return new MyCheckpoint();
}
55.3.2 Task Step
The task step displays the length of the output file. In more complex scenarios, task
steps perform any task that does not fit the chunk processing programming model:
@Dependent
@Named("MyBatchlet")
public class MyBatchlet implements javax.batch.api.chunk.Batchlet {
@Inject
private JobContext jobCtx;
@Override
public String process() throws Exception {
String fileName = jobCtx.getProperties()
.getProperty("output_file");
System.out.println(""+(new File(fileName)).length());
return "COMPLETED";
}
}
Batch Processing
55-9
Using the Job Specification Language
55.4 Using the Job Specification Language
The Job Specification Language (JSL) enables you to define the steps in a job and their
execution order using an XML file. The following example shows how to define a
simple job that contains one chunk step and one task step:
<job id="loganalysis" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
version="1.0">
<properties>
<property name="input_file" value="input1.txt"/>
<property name="output_file" value="output2.txt"/>
</properties>
<step id="logprocessor" next="cleanup">
<chunk checkpoint-policy="item" item-count="10">
<reader ref="com.example.pkg.LogItemReader"></reader>
<processor ref="com.example.pkg.LogItemProcessor"></processor>
<writer ref="com.example.pkg.LogItemWriter"></writer>
</chunk>
</step>
<step id="cleanup">
<batchlet ref="com.example.pkg.CleanUp"></batchlet>
<end on="COMPLETED"/>
</step>
</job>
This example defines the loganalysis batch job, which consists of the logprocessor
chunk step and the cleanup task step. The logprocessor step transitions to the
cleanup step, which terminates the job when completed.
The job element defines two properties, input_file and output_file. Specifying
properties in this manner enables you to run a batch job with different configuration
parameters without having to recompile its Java batch artifacts. The batch artifacts can
access these properties using the context objects from the batch runtime.
The logprocessor step is a chunk step that specifies batch artifacts for the reader
(LogItemReader), the processor (LogItemProcessor), and the writer (LogItemWriter).
This step creates a checkpoint for every ten items processed.
The cleanup step is a task step that specifies the CleanUp class as its batch artifact. The
job terminates when this step completes.
The following sections describe the elements of the Job Specification Language (JSL) in
more detail and show the most common attributes and child elements.
55.4.1 The job Element
The job element is always the top-level element in a job definition file. Its main
attributes are id and restartable. The job element can contain one properties
element and zero or more of each of the following elements: listener, step, flow, and
split. For example:
<job id="jobname" restartable="true">
<listeners>
<listener ref="com.example.pkg.ListenerBatchArtifact"/>
</listeners>
<properties>
<property name="propertyName1" value="propertyValue1"/>
<property name="propertyName2" value="propertyValue2"/>
</properties>
55-10 The Java EE 7 Tutorial
Using the Job Specification Language
<step ...> ... </step>
<step ...> ... </step>
<decision ...> ... </decision>
<flow ...> ... </flow>
<split ...> ... </split>
</job>
The listener element specifies a batch artifact whose methods are invoked before and
after the execution of the job. The batch artifact is an implementation of the
javax.batch.api.listener.JobListener interface. See The Listener Batch Artifacts
for an example of a job listener implementation.
The first step, flow, or split element inside the job element executes first.
55.4.2 The step Element
The step element can be a child of the job and flow elements. Its main attributes are
id and next. The step element can contain the following elements.
■
■
One chunk element for chunk-oriented steps or one batchlet element for
task-oriented steps.
One properties element (optional).
This element specifies a set of properties that batch artifacts can access using batch
context objects.
■
One listener element (optional); one listeners element if more than one listener
is specified.
This element specifies listener artifacts that intercept various phases of step
execution.
For chunk steps, the batch artifacts for these listeners can be implementations of
the following interfaces: StepListener, ItemReadListener, ItemProcessListener,
ItemWriteListener, ChunkListener, RetryReadListener, RetryProcessListener,
RetryWriteListener, SkipReadListener, SkipProcessListener, and
SkipWriteListener.
For task steps, the batch artifact for these listeners must be an implementation of
the StepListener interface.
See The Listener Batch Artifacts for an example of an item processor listener
implementation.
■
One partition element (optional).
This element is used in partitioned steps which execute in more than one thread.
■
One end element if this is the last step in a job.
This element sets the batch status to COMPLETED.
■
One stop element (optional) to stop a job at this step.
This element sets the batch status to STOPPED.
■
One fail element (optional) to terminate a job at this step.
This element sets the batch status to FAILED.
■
One or more next elements if the next attribute is not specified.
This element is associated with an exit status and refers to another step, a flow, a
split, or a decision element.
Batch Processing 55-11
Using the Job Specification Language
The following is an example of a chunk step:
<step id="stepA" next="stepB">
<properties> ... </properties>
<listeners>
<listener ref="MyItemReadListenerImpl"/>
...
</listeners>
<chunk ...> ... </chunk>
<partition> ... </partition>
<end on="COMPLETED" exit-status="MY_COMPLETED_EXIT_STATUS"/>
<stop on="MY_TEMP_ISSUE_EXIST_STATUS" restart="step0"/>
<fail on="MY_ERROR_EXIT_STATUS" exit-status="MY_ERROR_EXIT_STATUS"/>
</step>
The following is an example of a task step:
<step id="stepB" next="stepC">
<batchlet ...> ... </batchlet>
<properties> ... </properties>
<listener ref="MyStepListenerImpl"/>
</step>
55.4.2.1 The chunk Element
The chunk element is a child of the step element for chunk-oriented steps. The
attributes of this element are listed in Table 55–2.
Table 55–2
Attributes of the chunk Element
Attribute Name
Description
Default Value
checkpoint-policy
Specifies how to commit the results of processing each chunk:
"item"
■
■
"item": the chunk is committed after processing item-count items
"custom": the chunk is committed according to a checkpoint
algorithm specified with the checkpoint-algorithm element
The checkpoint is updated when the results of a chunk are committed.
Every chunk is processed in a global Java EE transaction. If the processing of
one item in the chunk fails, the transaction is rolled back and no processed
items from this chunk are stored.
item-count
Specifies the number of items to process before committing the chunk and
taking a checkpoint.
10
time-limit
Specifies the number of seconds before committing the chunk and taking a 0 (no limit)
checkpoint when checkpoint-policy="item".
If item-count items have not been processed by time-limit seconds, the
chunk is committed and a checkpoint is taken.
buffer-items
Specifies if processed items are buffered until it is time to take a
true
checkpoint. If true, a single call to the item writer is made with a list of the
buffered items before committing the chunk and taking a checkpoint.
skip-limit
Specifies the number of skippable exceptions to skip in this step during
chunk processing. Skippable exception classes are specified with the
skippable-exception-classes element.
No limit
retry-limit
Specifies the number of attempts to execute this step if retryable
exceptions occur. Retryable exception classes are specified with the
retryable-exception-classes element.
No limit
The chunk element can contain the following elements.
55-12 The Java EE 7 Tutorial
Using the Job Specification Language
■
One reader element.
This element specifies a batch artifact that implements the ItemReader interface.
■
One processor element.
This element specifies a batch artifact that implements the ItemProcessor
interface.
■
One writer element.
This element specifies a batch artifact that implements the ItemWriter interface.
■
One checkpoint-algorithm element (optional).
This element specifies a batch artifact that implements the CheckpointAlgorithm
interface and provides a custom checkpoint policy.
■
One skippable-exception-classes element (optional).
This element specifies a set of exceptions thrown from the reader, writer, and
processor batch artifacts that chunk processing should skip. The skip-limit
attribute from the chunk element specifies the maximum number of skipped
exceptions.
■
One retryable-exception-classes element (optional).
This element specifies a set of exceptions thrown from the reader, writer, and
processor batch artifacts that chunk processing will retry. The retry-limit
attribute from the chunk element specifies the maximum number of attempts.
■
One no-rollback-exception-classes element (optional).
This element specifies a set of exceptions thrown from the reader, writer, and
processor batch artifacts that should not cause the batch runtime to roll back the
current chunk, but to retry the current operation without a rollback instead.
For exception types not specified in this element, the current chunk is rolled back
by default when an exception occurs.
The following is an example of a chunk-oriented step:
<step id="stepC" next="stepD">
<chunk checkpoint-policy="item" item-count="5" time-limit="180"
buffer-items="true" skip-limit="10" retry-limit="3">
<reader ref="pkg.MyItemReaderImpl"></reader>
<processor ref="pkg.MyItemProcessorImpl"></processor>
<writer ref="pkg.MyItemWriterImpl"></writer>
<skippable-exception-classes>
<include class="pkg.MyItemException"/>
<exclude class="pkg.MyItemSeriousSubException"/>
</skippable-exception-classes>
<retryable-exception-classes>
<include class="pkg.MyResourceTempUnavailable"/>
</retryable-exception-classes>
</chunk>
</step>
This example defines a chunk step and specifies its reader, processor, and writer
artifacts. The step updates a checkpoint and commits each chunk after processing five
items. It skips all MyItemException exceptions and all its subtypes, except for
MyItemSeriousSubException, up to a maximum of ten skipped exceptions. The step
retries a chunk when a MyResourceTempUnavailable exception occurs, up to a
maximum of three attempts.
Batch Processing 55-13
Using the Job Specification Language
55.4.2.2 The batchlet Element
The batchlet element is a child of the step element for task-oriented steps. This
element only has the ref attribute, which specifies a batch artifact that implements the
Batchlet interface. The batch element can contain a properties element.
The following is an example of a task-oriented step:
<step id="stepD" next="stepE">
<batchlet ref="pkg.MyBatchletImpl">
<properties>
<property name="pname" value="pvalue"/>
</properties>
</batchlet>
</step>
This example defines a batch step and specifies its batch artifact.
55.4.2.3 The partition Element
The partition element is a child of the step element. It indicates that a step is
partitioned. Most partitioned steps are chunk steps where the processing of each item
does not depend on the results of processing previous items. You specify the number
of partitions in a step and provide each partition with specific information on which
items to process, such as the following.
■
■
A range of items. For example, partition 1 processes items 1 through 500, and
partition 2 processes items 501 through 1000.
An input source. For example, partition 1 processes the items in input1.txt and
partition 2 processes the items in input2.txt.
When the number of partitions, the number of items, and the input sources for a
partitioned step are known at development or deployment time, you can use partition
properties in the job definition file to specify partition-specific information and access
these properties from the step batch artifacts. The runtime creates as many instances of
the step batch artifacts (reader, processor, and writer) as partitions, and each artifact
instance receives the properties specific to its partition.
In most cases, the number of partitions, the number of items, or the input sources for a
partitioned step can only be determined at runtime. Instead of specifying
partition-specific properties statically in the job definition file, you provide a batch
artifact that can access your data sources at runtime and determine how many
partitions are needed and what range of items each partition should process. This
batch artifact is an implementation of the PartitionMapper interface. The batch
runtime invokes this artifact and then uses the information it provides to instantiate
the step batch artifacts (reader, writer, and processor) for each partition and to pass
them partition-specific data as parameters.
The rest of this section describes the partition element in detail and shows two
examples of job definition files: one that uses partition properties to specify a range of
items for each partition, and one that relies on a PartitionMapper implementation to
determine partition-specific information.
See The Phone Billing Chunk Step in The phonebilling Example Application for a
complete example of a partitioned chunk step.
The partition element can contain the following elements.
■
One plan element, if the mapper element is not specified.
55-14 The Java EE 7 Tutorial
Using the Job Specification Language
This element defines the number of partitions, the number of threads, and the
properties for each partition in the job definition file. The plan element is useful
when this information is known at development or deployment time.
■
One mapper element, if the plan element is not specified.
This element specifies a batch artifact that provides the number of partitions, the
number of threads, and the properties for each partition. The batch artifact is an
implementation of the PartitionMapper interface. You use this option when the
information required for each partition is only known at runtime.
■
One reducer element (optional).
This element specifies a batch artifact that receives control when a partitioned step
begins, ends, or rolls back. The batch artifact enables you to merge results from
different partitions and perform other related operations. The batch artifact is an
implementation of the PartitionReducer interface.
■
One collector element (optional).
This element specifies a batch artifact that sends intermediary results from each
partition to a partition analyzer. The batch artifact sends the intermediary results
after each checkpoint for chunk steps and at the end of the step for task steps. The
batch artifact is an implementation of the PartitionCollector interface.
■
One analyzer element (optional).
This element specifies a batch artifact that analyzes the intermediary results from
the partition collector instances. The batch artifact is an implementation of the
PartitionAnalyzer interface.
The following is an example of a partitioned step using the plan element:
<step id="stepE" next="stepF">
<chunk>
<reader ...></reader>
<processor ...></processor>
<writer ...></writer>
</chunk>
<partition>
<plan partitions="2" threads="2">
<properties partition="0">
<property name="firstItem" value="0"/>
<property name="lastItem" value="500"/>
</properties>
<properties partition="1">
<property name="firstItem" value="501"/>
<property name="lastItem" value="999"/>
</properties>
</plan>
</partition>
<reducer ref="MyPartitionReducerImpl"/>
<collector ref="MyPartitionCollectorImpl"/>
<analyzer ref="MyPartitionAnalyzerImpl"/>
</step>
In this example, the plan element specifies the properties for each partition in the job
definition file.
The following example uses a mapper element instead of a plan element. The
PartitionMapper implementation dynamically provides the same information as the
plan element provides in the job definition file:
Batch Processing 55-15
Using the Job Specification Language
<step id="stepE" next="stepF">
<chunk>
<reader ...></reader>
<processor ...></processor>
<writer ...></writer>
</chunk>
<partition>
<mapper ref="MyPartitionMapperImpl"/>
<reducer ref="MyPartitionReducerImpl"/>
<collector ref="MyPartitionCollectorImpl"/>
<analyzer ref="MyPartitionAnalyzerImpl"/>
</partition>
</step>
Refer to The phonebilling Example Application for an example implementation of the
PartitionMapper interface.
55.4.3 The flow Element
The flow element can be a child of the job, flow, and split elements. Its attributes are
id and next. Flows can transition to flows, steps, splits, and decision elements. The
flow element can contain the following elements:
■
One or more step elements
■
One or more flow elements (optional)
■
One or more split elements (optional)
■
One or more decision elements (optional)
The last step in a flow is the one with no next attribute or next element. Steps and
other elements in a flow cannot transition to elements outside the flow.
The following is an example of the flow element:
<flow id="flowA" next="stepE">
<step id="flowAstepA" next="flowAstepB">...</step>
<step id="flowAstepB" next="flowAflowC">...</step>
<flow id="flowAflowC" next="flowAsplitD">...</flow>
<split id="flowAsplitD" next="flowAstepE">...</split>
<step id="flowAstepE">...</step>
</flow>
This example flow contains three steps, one flow, and one split. The last step does not
have the next attribute. The flow transitions to stepE when its last step completes.
55.4.4 The split Element
The split element can be a child of the job and flow elements. Its attributes are id
and next. Splits can transition to splits, steps, flows, and decision elements. The split
element can only contain one or more flow elements that can only transition to other
flow elements in the split.
The following is an example of a split with three flows that execute concurrently:
<split id="splitA" next="stepB">
<flow id="splitAflowA">...</flow>
<flow id="splitAflowB">...</flow>
<flow id="splitAflowC">...</flow>
</split>
55-16 The Java EE 7 Tutorial
Creating Batch Artifacts
55.4.5 The decision Element
The decision element can be a child of the job and flow elements. Its attributes are id
and next. Steps, flows, and splits can transition to a decision element. This element
specifies a batch artifact that decides the next step, flow, or split to execute based on
information from the execution of the previous step, flow, or split. The batch artifact
implements the Decider interface. The decision element can contain the following
elements.
■
One or more end elements (optional).
This element sets the batch status to COMPLETED.
■
One or more stop elements (optional).
This element sets the batch status to STOPPED.
■
One or more fail elements (optional).
This element sets the batch status to FAILED.
■
One or more next elements (optional).
■
One properties element (optional).
The following is an example of the decider element:
<decision id="decisionA" ref="MyDeciderImpl">
<fail on="FAILED" exit-status="FAILED_AT_DECIDER"/>
<end on="COMPLETED" exit-status="COMPLETED_AT_DECIDER"/>
<stop on="MY_TEMP_ISSUE_EXIST_STATUS" restart="step2"/>
</decision>
55.5 Creating Batch Artifacts
After you define a job in terms of its batch artifacts using the Job Specification
Language (JSL), you create these artifacts as Java classes that implement the interfaces
in the javax.batch.api package and its subpackages.
This section lists the main batch artifact interfaces, demonstrates how to access context
objects from the batch runtime, and provides some examples.
55.5.1 Batch Artifact Interfaces
The following tables list the interfaces that you implement to create batch artifacts. The
interface implementations are referenced from the elements described in Using the Job
Specification Language.
Table 55–3 lists the interfaces to implement batch artifacts for chunk steps, task steps,
and decision elements.
Table 55–4 lists the interfaces to implement batch artifacts for partitioned steps.
Table 55–5 lists the interfaces to implement batch artifacts for job and step listeners.
Table 55–3
Main Batch Artifact Interfaces
Package
Interface
Description
javax.batch.api
Batchlet
Implements the business logic of a
task-oriented step. It is referenced from
the batchlet element.
Batch Processing 55-17
Creating Batch Artifacts
Table 55–3 (Cont.) Main Batch Artifact Interfaces
Package
Interface
Description
javax.batch.api
Decider
Decides the next step, flow, or split to
execute based on information from the
execution of the previous step, flow, or
split. It is referenced from the decision
element.
javax.batch.api.chunk
CheckPointAlgorithm
Implements a custom checkpoint policy
for chunk steps. It is referenced from the
checkpoint-algorithm element inside
the chunk element.
javax.batch.api.chunk
ItemReader
Reads items from an input source in a
chunk step. It is referenced from the
reader element inside the chunk
element.
javax.batch.api.chunk
ItemProcessor
Processes input items to obtain output
items in chunk steps. It is referenced
from the processor element inside the
chunk element.
javax.batch.api.chunk
ItemWriter
Writes output items in chunk steps. It is
referenced from the writer element
inside the chunk element.
Table 55–4
Partition Batch Artifact Interfaces
Package
Interface
Description
javax.batch.api.partition
PartitionPlan
Provides details on how to execute a
partitioned step, such as the number
of partitions, the number of threads,
and the parameters for each partition.
This artifact is not referenced directly
from the job definition file.
javax.batch.api.partition
PartitionMapper
Provides a PartitionPlan object. It is
referenced from the mapper element
inside the partition element.
javax.batch.api.partition
PartitionReducer
Receives control when a partitioned
step begins, ends, or rolls back. It is
referenced from the reducer element
inside the partition element.
javax.batch.api.partition
PartitionCollector
Sends intermediary results from each
partition to a partition analyzer. It is
referenced from the collector
element inside the partition element.
javax.batch.api.partition
PartitionAnalyzer
Processes data and final results from
each partition. It is referenced from
the analyzer element inside the
partition element.
Table 55–5
Listener Batch Artifact Interfaces
Package
Interface
Description
javax.batch.api.listener
JobListener
Intercepts job execution before
and after running a job. It is
referenced from the listener
element inside the job element.
55-18 The Java EE 7 Tutorial
Creating Batch Artifacts
Table 55–5 (Cont.) Listener Batch Artifact Interfaces
Package
Interface
Description
javax.batch.api.listener
StepListener
Intercepts step execution before
and after running a step. It is
referenced from the listener
element inside the step
element
javax.batch.api.chunk.listener
ChunkListener
Intercepts chunk processing in
chunk steps before and after
processing each chunk, and on
errors. It is referenced from the
listener element inside the
step element.
javax.batch.api.chunk.listener
ItemReadListener
Intercepts item reading in
chunk steps before and after
reading each item, and on
errors. It is referenced from the
listener element inside the
step element.
javax.batch.api.chunk.listener
ItemProcessListener
Intercepts item processing in
chunk steps before and after
processing each item, and on
errors. It is referenced from the
listener element inside the
step element.
javax.batch.api.chunk.listener
ItemWriteListener
Intercepts item writing in
chunk steps before and after
writing each item, and on
errors. It is referenced from the
listener element inside the
step element.
javax.batch.api.chunk.listener
RetryReadListener
Intercepts retry item reading in
chunk steps when an exception
occurs. It is referenced from the
listener element inside the
step element.
javax.batch.api.chunk.listener
RetryProcessListener
Intercepts retry item processing
in chunk steps when an
exception occurs. It is
referenced from the listener
element inside the step
element.
javax.batch.api.chunk.listener
RetryWriteListener
Intercepts retry item writing in
chunk steps when an exception
occurs. It is referenced from the
listener element inside the
step element.
javax.batch.api.chunk.listener
SkipReadListener
Intercepts skippable exception
handling for item readers in
chunk steps. It is referenced
from the listener element
inside the step element.
javax.batch.api.chunk.listener
SkipProcessListener
Intercepts skippable exception
handling for item processors in
chunk steps. It is referenced
from the listener element
inside the step element.
Batch Processing 55-19
Creating Batch Artifacts
Table 55–5 (Cont.) Listener Batch Artifact Interfaces
Package
Interface
Description
javax.batch.api.chunk.listener
SkipWriteListener
Intercepts skippable exception
handling for item writers in
chunk steps. It is referenced
from the listener element
inside the step element.
55.5.2 Dependency Injection in Batch Artifacts
To ensure that Contexts and Dependency Injection (CDI) works in your batch artifacts,
follow these steps.
1.
Define your batch artifact implementations as CDI named beans using the Named
annotation.
For example, define an item reader implementation in a chunk step as follows:
@Named("MyItemReaderImpl")
public class MyItemReaderImpl implements ItemReader {
/* ... Override the ItemReader interface methods ... */
}
2.
Provide a public, empty, no-argument constructor for your batch artifacts.
For example, provide the following constructor for the artifact above:
public MyItemReaderImpl() {}
3.
Specify the CDI name for the batch artifacts in the job definition file, instead of
using the fully qualified name of the class.
For example, define the step for the artifact above as follows:
<step id="stepA" next="stepB">
<chunk>
<reader ref="MyItemReaderImpl"></reader>
...
</chunk>
</step>
This example uses the CDI name (MyItemReaderImpl) instead of the fully qualified
name of the class (com.example.pkg.MyItemReaderImpl) to specify a batch artifact.
4.
Ensure that your module is a CDI bean archive by annotating your batch artifacts
with the javax.enterprise.context.Dependent annotation or by including an
empty beans.xml deployment description with your application. For example, the
following batch artifact is annotated with @Dependent:
@Dependent
@Named("MyItemReaderImpl")
public class MyItemReaderImpl implements ItemReader { ... }
For more information on bean archives, see Packaging CDI Applications in
Chapter 25, "Contexts and Dependency Injection for Java EE: Advanced Topics".
Note: Contexts and Dependency Injection (CDI) is required in order
to access context objects from the batch runtime in batch artifacts.
You may encounter the following errors if you do not follow this procedure.
55-20 The Java EE 7 Tutorial
Submitting Jobs to the Batch Runtime
■
The batch runtime cannot locate some batch artifacts.
■
The batch artifacts throw null pointer exceptions when accessing injected objects.
55.5.3 Using the Context Objects from the Batch Runtime
The batch runtime provides context objects that implement the JobContext and
StepContext interfaces in the javax.batch.runtime.context package. These objects
are associated with the current job and step, respectively, and enable you to do the
following:
■
Get information from the current job or step, such as its name, instance ID,
execution ID, batch status, and exit status
■
Set the user-defined exit status
■
Store user data
■
Get property values from the job or step definition
You can inject context objects from the batch runtime inside batch artifact
implementations like item readers, item processors, item writers, batchlets, listeners,
and so on. The following example demonstrates how to access property values from
the job definition file in an item reader implementation:
@Dependent
@Named("MyItemReaderImpl")
public class MyItemReaderImpl implements ItemReader {
@Inject
JobContext jobCtx;
public MyItemReaderImpl() {}
@Override
public void open(Serializable checkpoint) throws Exception {
String fileName = jobCtx.getProperties()
.getProperty("log_file_name");
...
}
...
}
See Dependency Injection in Batch Artifacts for instructions on how to define your
batch artifacts to use dependency injection.
Note:
Do not access batch context objects inside artifact constructors.
Because the job does not run until you submit it to the batch runtime,
the batch context objects are not available when CDI instantiates your
artifacts upon loading your application. The instantiation of these
beans fails and the batch runtime cannot find your batch artifacts
when your application submits the job.
55.6 Submitting Jobs to the Batch Runtime
The JobOperator interface in the javax.batch.operations package enables you to
submit jobs to the batch runtime and obtain information about existing jobs. This
interface provides the following functionality.
Batch Processing 55-21
Packaging Batch Applications
■
Obtain the names of all known jobs.
■
Start, stop, restart, and abandon jobs.
■
Obtain job instances and job executions.
The BatchRuntime class in the javax.batch.runtime package provides the
getJobOperator factory method to obtain JobOperator objects.
55.6.1 Starting a Job
The following example code demonstrates how to obtain a JobOperator object and
submit a batch job:
JobOperator jobOperator = BatchRuntime.getJobOperator();
Properties props = new Properties();
props.setProperty("parameter1", "value1");
...
long execID = jobOperator.start("simplejob", props);
The first argument of the JobOperator.start method is the name of the job as
specified in its job definition file. The second parameter is a Properties object that
represents the parameters for this job execution. You can use job parameters to pass to
a job information that is only known at runtime.
55.6.2 Checking the Status of a Job
The JobExecution interface in the javax.batch.runtime package provides methods to
obtain information about submitted jobs. This interface provides the following
functionality.
■
Obtain the batch and exit status of a job execution.
■
Obtain the time the execution was started, updated, or ended.
■
Obtain the job name.
■
Obtain the execution ID.
The following example code demonstrates how to obtain the batch status of a job
using its execution ID:
JobExecution jobExec = jobOperator.getJobExecution(execID);
String status = jobExec.getBatchStatus().toString();
55.6.3 Invoking the Batch Runtime in Your Application
The component from which you invoke the batch runtime depends on the architecture
of your particular application. For example, you can invoke the batch runtime from an
enterprise bean, a servlet, a managed bean, and so on.
See The webserverlog Example Application and The phonebilling Example
Application for details on how to invoke the batch runtime from a managed bean
driven by a JavaServer Faces user interface.
55.7 Packaging Batch Applications
Job definition files and batch artifacts do not require separate packaging and can be
included in any Java EE application.
Package the batch artifact classes with the rest of the classes of your application, and
include the job definition files in one of the following directories:
55-22 The Java EE 7 Tutorial
The webserverlog Example Application
■
META-INF/batch-jobs/ for jar packages
■
WEB-INF/classes/META-INF/batch-jobs/ for war packages
The name of each job definition file must match its job ID. For example, if you define a
job as follows, and you are packaging your application as a WAR file, include the job
definition file in WEB-INF/classes/META-INF/batch-jobs/simplejob.xml:
<job id="simplejob" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
version="1.0">
...
</job>
55.8 The webserverlog Example Application
The webserverlog example application, located in the
tut-install/examples/batch/webserverlog/ directory, demonstrates how to use the
batch framework in Java EE to analyze the log file from a web server. This example
application reads a log file and finds what percentage of page views from tablet
devices are product sales.
55.8.1 Architecture of the webserverlog Example Application
The webserverlog example application consists of the following elements.
■
■
■
■
■
■
■
■
A job definition file (webserverlog.xml) that uses the Job Specification Language
(JSL) to define a batch job with a chunk step and a task step. The chunk step acts as
a filter, and the task step calculates statistics on the remaining entries.
A log file (log1.txt) that serves as input data to the batch job.
Two Java classes (LogLine and LogFilteredLine) that represent input items and
output items for the chunk step.
Three batch artifacts (LogLineReader, LogLineProcessor, and
LogFilteredLineWriter) that implement the chunk step of the application. This
step reads items from the web server log file, filters them by the web browser used
by the client, and writes the results to a text file.
Two batch artifacts (InfoJobListener and InfoItemProcessListener) that
implement two simple listeners.
A batch artifact (MobileBatchlet.java) that calculates statistics on the filtered
items.
Two Facelets pages (index.xhtml and jobstarted.xhtml) that provide the front
end of the batch application. The first page shows the log file that will be
processed by the batch job, and the second page enables the user to check on the
status of the job and shows the results.
A managed bean (JsfBean) that is accessed from the Facelets pages. The bean
submits the job to the batch runtime, checks on the status of the job, and reads the
results from a text file.
55.8.1.1 The Job Definition File
The webserverlog.xml job definition file is located in the
WEB-INF/classes/META-INF/batch-jobs/ directory. The file specifies seven job-level
properties and two steps:
<?xml version="1.0" encoding="UTF-8"?>
<job id="webserverlog" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
Batch Processing 55-23
The webserverlog Example Application
version="1.0">
<properties>
<property name="log_file_name" value="log1.txt"/>
<property name="filtered_file_name" value="filtered1.txt"/>
<property name="num_browsers" value="2"/>
<property name="browser_1" value="Tablet Browser D"/>
<property name="browser_2" value="Tablet Browser E"/>
<property name="buy_page" value="/auth/buy.html"/>
<property name="out_file_name" value="result1.txt"/>
</properties>
<listeners>
<listener ref="InfoJobListener"/>
</listeners>
<step id="mobilefilter" next="mobileanalyzer"> ... </step>
<step id="mobileanalyzer"> ... </step>
</job>
The first step is defined as follows:
<step id="mobilefilter" next="mobileanalyzer">
<listeners>
<listener ref="InfoItemProcessListeners"/>
</listeners>
<chunk checkpoint-policy="item" item-count="10">
<reader ref="LogLineReader"></reader>
<processor ref="LogLineProcessor"></processor>
<writer ref="LogFilteredLineWriter"></writer>
</chunk>
</step>
This step is a normal chunk step that specifies the batch artifacts that implement each
phase of the step. The batch artifact names are not fully qualified class names, so the
batch artifacts are CDI beans annotated with @Named.
The second step is defined as follows:
<step id="mobileanalyzer">
<batchlet ref="MobileBatchlet"></batchlet>
<end on="COMPLETED"/>
</step>
This step is a task step that specifies the batch artifact that implements it. This is the
last step of the job.
55.8.1.2 The LogLine and LogFilteredLine Items
The LogLine class represents entries in the web server log file and it is defined as
follows:
public class LogLine {
private final String
private final String
private final String
private final String
datetime;
ipaddr;
browser;
url;
/* ... Constructor, getters, and setters ... */
}
The LogFileteredLine class is similar to this class but only has two fields: the IP
address of the client and the URL.
55-24 The Java EE 7 Tutorial
The webserverlog Example Application
55.8.1.3 The Chunk Step Batch Artifacts
The first step is composed of the LogLineReader, LogLineProcessor, and
LogFilteredLineWriter batch artifacts.
The LogLineReader artifact reads records from the web server log file:
@Dependent
@Named("LogLineReader")
public class LogLineReader implements ItemReader {
private ItemNumberCheckpoint checkpoint;
private String fileName;
private BufferedReader breader;
@Inject
private JobContext jobCtx;
public LogLineReader() { }
/* ... Override the open, close, readItem, and
*
checkpointInfo methods ... */
}
The open method reads the log_file_name property and opens the log file with a
buffered reader. In this example, the log file has been included with the application
under webserverlog/WEB-INF/classes/log1.txt:
fileName = jobCtx.getProperties().getProperty("log_file_name");
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream iStream = classLoader.getResourceAsStream(fileName);
breader = new BufferedReader(new InputStreamReader(iStream));
If a checkpoint object is provided, the open method advances the reader up to the last
checkpoint. Otherwise, this method creates a new checkpoint object. The checkpoint
object keeps track of the line number from the last committed chunk.
The readItem method returns a new LogLine object or null at the end of the log file:
@Override
public Object readItem() throws Exception {
String entry = breader.readLine();
if (entry != null) {
checkpoint.nextLine();
return new LogLine(entry);
} else {
return null;
}
}
The LogLineProcessor artifact obtains a list of browsers from the job properties and
filters the log entries according to the list:
@Override
public Object processItem(Object item) {
/* Obtain a list of browsers we are interested in */
if (nbrowsers == 0) {
Properties props = jobCtx.getProperties();
nbrowsers = Integer.parseInt(props.getProperty("num_browsers"));
browsers = new String[nbrowsers];
for (int i = 1; i < nbrowsers + 1; i++)
browsers[i - 1] = props.getProperty("browser_" + i);
}
Batch Processing 55-25
The webserverlog Example Application
LogLine logline = (LogLine) item;
/* Filter for only the mobile/tablet browsers as specified */
for (int i = 0; i < nbrowsers; i++) {
if (logline.getBrowser().equals(browsers[i])) {
return new LogFilteredLine(logline);
}
}
return null;
}
The LogFilteredLineWriter artifact reads the name of the output file from the job
properties. The open method opens the file for writing. If a checkpoint object is
provided, the artifact continues writing at the end of the file; otherwise, it overwrites
the file if it exists. The writeItems method writes filtered items to the output file:
@Override
public void writeItems(List<Object> items) throws Exception {
/* Write the filtered lines to the output file */
for (int i = 0; i < items.size(); i++) {
LogFilteredLine filtLine = (LogFilteredLine) items.get(i);
bwriter.write(filtLine.toString());
bwriter.newLine();
}
}
55.8.1.4 The Listener Batch Artifacts
The InfoJobListener batch artifact implements a simple listener that writes log
messages when the job starts and when it ends:
@Dependent
@Named("InfoJobListener")
public class InfoJobListener implements JobListener {
...
@Override
public void beforeJob() throws Exception {
logger.log(Level.INFO, "The job is starting");
}
@Override
public void afterJob() throws Exception { ... }
}
The InfoItemProcessListener batch artifact implements the ItemProcessListener
interface for chunk steps:
@Dependent
@Named("InfoItemProcessListener")
public class InfoItemProcessListener implements ItemProcessListener {
...
@Override
public void beforeProcess(Object o) throws Exception {
LogLine logline = (LogLine) o;
llogger.log(Level.INFO, "Processing entry {0}", logline);
}
...
}
55-26 The Java EE 7 Tutorial
The webserverlog Example Application
55.8.1.5 The Task Step Batch Artifact
The task step is implemented by the MobileBatchlet artifact, which computes what
percentage of the filtered log entries are purchases:
@Override
public String process() throws Exception {
/* Get properties from the job definition file */
...
/* Count from the output of the previous chunk step */
breader = new BufferedReader(new FileReader(fileName));
String line = breader.readLine();
while (line != null) {
String[] lineSplit = line.split(", ");
if (buyPage.compareTo(lineSplit[1]) == 0)
pageVisits++;
totalVisits++;
line = breader.readLine();
}
breader.close();
/* Write the result */
...
}
55.8.1.6 The JavaServer Faces Pages
The index.xhtml page contains a text area that shows the web server log. The page
provides a button for the user to submit the batch job and navigate to the next page:
<body>
...
<textarea cols="90" rows="25"
readonly="true">#{jsfBean.getInputLog()}</textarea>
<p> </p>
<h:form>
<h:commandButton value="Start Batch Job"
action="#{jsfBean.startBatchJob()}" />
</h:form>
</body>
This page calls the methods of the managed bean to show the log file and submit the
batch job.
The jobstarted.xhtml page provides a button to check the current status of the batch
job and displays the results when the job finishes:
<p>Current Status of the Job: <b>#{jsfBean.jobStatus}</b></p>
<p>#{jsfBean.showResults()}</p>
<h:form>
<h:commandButton value="Check Status"
action="jobstarted"
rendered="#{jsfBean.completed==false}" />
</h:form>
55.8.1.7 The Managed Bean
The JsfBean managed bean submits the job to the batch runtime, checks on the status
of the job, and reads the results from a text file.
The startBatchJob method submits the job to the batch runtime:
/* Submit the batch job to the batch runtime.
* JSF Navigation method (return the name of the next page) */
Batch Processing 55-27
The webserverlog Example Application
public String startBatchJob() {
jobOperator = BatchRuntime.getJobOperator();
execID = jobOperator.start("webserverlog", null);
return "jobstarted";
}
The getJobStatus method checks the status of the job:
/* Get the status of the job from the batch runtime */
public String getJobStatus() {
return jobOperator.getJobExecution(execID).getBatchStatus().toString();
}
The showResults method reads the results from a text file.
55.8.2 Running the webserverlog Example Application
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
webserverlog example application.
55.8.2.1 To Run the webserverlog Example Application Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/batch
4.
Select the webserverlog folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the webserverlog project and select Run.
This command builds and packages the application into a WAR file,
webserverlog.war, located in the target/ directory; deploys it to the server; and
launches a web browser window at the following URL:
http://localhost:8080/webserverlog/
55.8.2.2 To Run the webserverlog Example Application Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/batch/webserverlog/
3.
Enter the following command to deploy the application:
mvn install
4.
Open a web browser window at the following URL:
http://localhost:8080/webserverlog/
55-28 The Java EE 7 Tutorial
The phonebilling Example Application
55.9 The phonebilling Example Application
The phonebilling example application, located in the
tut-install/examples/batch/phonebilling/ directory, demonstrates how to use the
batch framework in Java EE to implement a phone billing system. This example
application processes a log file of phone calls and creates a bill for each customer.
55.9.1 Architecture of the phonebilling Example Application
The phonebilling example application consists of the following elements.
■
■
■
■
■
■
■
A job definition file (phonebilling.xml) that uses the Job Specification Language
(JSL) to define a batch job with two chunk steps. The first step reads call records
from a log file and associates them with a bill. The second step computes the
amount due and writes each bill to a text file.
A Java class (CallRecordLogCreator) that creates the log file for the batch job. This
is an auxiliary component that does not demonstrate any key functionality in this
example.
Two Java Persistence API (JPA) entities (CallRecord and PhoneBill) that represent
call records and customer bills. The application uses a JPA entity manager to store
instances of these entities in a database.
Three batch artifacts (CallRecordReader, CallRecordProcessor, and
CallRecordWriter) that implement the first step of the application. This step reads
call records from the log file, associates them with a bill, and stores them in a
database.
Four batch artifacts (BillReader, BillProcessor, BillWriter, and
BillPartitionMapper) that implement the second step of the application. This
step is a partitioned step that gets each bill from the database, calculates the
amount due, and writes it to a text file.
Two Facelets pages (index.xhtml and jobstarted.xhtml) that provide the front
end of the batch application. The first page shows the log file that will be
processed by the batch job, and the second page enables the user to check on the
status of the job and shows the resulting bill for each customer.
A managed bean (JsfBean) that is accessed from the Facelets pages. The bean
submits the job to the batch runtime, checks on the status of the job, and reads the
text files for each bill.
55.9.1.1 The Job Definition File
The phonebilling.xml job definition file is located in the
WEB-INF/classes/META-INF/batch-jobs/ directory. The file specifies three job-level
properties and two steps:
<?xml version="1.0" encoding="UTF-8"?>
<job id="phonebilling" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
version="1.0">
<properties>
<property name="log_file_name" value="log1.txt"/>
<property name="airtime_price" value="0.08"/>
<property name="tax_rate" value="0.07"/>
</properties>
<step id="callrecords" next="bills"> ... </step>
<step id="bills"> ... </step>
</job>
Batch Processing 55-29
The phonebilling Example Application
The first step is defined as follows:
<step id="callrecords" next="bills">
<chunk checkpoint-policy="item" item-count="10">
<reader ref="CallRecordReader"></reader>
<processor ref="CallRecordProcessor"></processor>
<writer ref="CallRecordWriter"></writer>
</chunk>
</step>
This step is a normal chunk step that specifies the batch artifacts that implement each
phase of the step. The batch artifact names are not fully qualified class names, so the
batch artifacts are CDI beans annotated with @Named.
The second step is defined as follows:
<step id="bills">
<chunk checkpoint-policy="item" item-count="2">
<reader ref="BillReader">
<properties>
<property name="firstItem" value="#{partitionPlan['firstItem']}"/>
<property name="numItems" value="#{partitionPlan['numItems']}"/>
</properties>
</reader>
<processor ref="BillProcessor"></processor>
<writer ref="BillWriter"></writer>
</chunk>
<partition>
<mapper ref="BillPartitionMapper"/>
</partition>
<end on="COMPLETED"/>
</step>
This step is a partitioned chunk step. The partition plan is specified through the
BillPartitionMapper artifact instead of using the plan element.
55.9.1.2 The CallRecord and PhoneBill Entities
The CallRecord entity is defined as follows:
@Entity
public class CallRecord implements Serializable {
@Id @GeneratedValue
private Long id;
@Temporal(TemporalType.DATE)
private Date datetime;
private String fromNumber;
private String toNumber;
private int minutes;
private int seconds;
private BigDecimal price;
public CallRecord() { }
public CallRecord(String datetime, String from,
String to, int min, int sec)
throws ParseException { ... }
public CallRecord(String jsonData) throws ParseException { ... }
/* ... Getters and setters ... */
}
55-30 The Java EE 7 Tutorial
The phonebilling Example Application
The id field is generated automatically by the JPA implementation to store and
retrieve CallRecord objects to and from a database.
The second constructor creates a CallRecord object from an entry of JSON data in the
log file using the JSON Processing API. Log entries look as follows:
{"datetime":"03/01/2013 04:03","from":"555-0101",
"to":"555-0114","length":"03:39"}
The PhoneBill entity is defined as follows:
@Entity
public class PhoneBill implements Serializable {
@Id
private String phoneNumber;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@OrderBy("datetime ASC")
private List<CallRecord> calls;
private BigDecimal amountBase;
private BigDecimal taxRate;
private BigDecimal tax;
private BigDecimal amountTotal;
public PhoneBill() { }
public PhoneBill(String number) {
this.phoneNumber = number;
calls = new ArrayList<>();
}
public void addCall(CallRecord call) {
calls.add(call);
}
public void calculate(BigDecimal taxRate) { ... }
/* ... Getters and setters ... *
}
The OneToMany annotation defines the relationship between a bill and its call records.
The FetchType.EAGER attribute specifies that the collection should be retrieved eagerly.
The CascadeType.PERSIST attribute indicates that the elements in the call list should
be automatically persisted when the phone bill is persisted. The OrderBy annotation
defines an order for retrieving the elements of the call list from the database.
The batch artifacts use instances of these two entities as items to read, process, and
write.
For more information on the Java Persistence API, see Chapter 37, "Introduction to the
Java Persistence API". For more information on the JSON Processing API, see
Chapter 19, "JSON Processing".
55.9.1.3 The Call Records Chunk Step
The first step is composed of the CallRecordReader, CallRecordProcessor, and
CallRecordWriter batch artifacts.
The CallRecordReader artifact reads call records from the log file:
@Dependent
@Named("CallRecordReader")
Batch Processing 55-31
The phonebilling Example Application
public class CallRecordReader implements ItemReader {
private ItemNumberCheckpoint checkpoint;
private String fileName;
private BufferedReader breader;
@Inject
JobContext jobCtx;
/* ... Override the open, close, readItem,
*
and checkpointInfo methods ... */
}
The open method reads the log_filename property and opens the log file with a
buffered reader:
fileName = jobCtx.getProperties().getProperty("log_file_name");
breader = new BufferedReader(new FileReader(fileName));
If a checkpoint object is provided, the open method advances the reader up to the last
checkpoint. Otherwise, this method creates a new checkpoint object. The checkpoint
object keeps track of the line number from the last committed chunk.
The readItem method returns a new CallRecord object or null at the end of the log
file:
@Override
public Object readItem() throws Exception {
/* Read a line from the log file and
* create a CallRecord from JSON */
String callEntryJson = breader.readLine();
if (callEntryJson != null) {
checkpoint.nextItem();
return new CallRecord(callEntryJson);
} else
return null;
}
The CallRecordProcessor artifact obtains the airtime price from the job properties,
calculates the price of each call, and returns the call object. This artifact overrides only
the processItem method.
The CallRecordWriter artifact associates each call record with a bill and stores the bill
in the database. This artifact overrides the open, close, writeItems, and
checkpointInfo methods. The writeItems method looks like this:
@Override
public void writeItems(List<Object> callList) throws Exception {
for (Object callObject : callList) {
CallRecord call = (CallRecord) callObject;
PhoneBill bill = em.find(PhoneBill.class, call.getFromNumber());
if (bill == null) {
/* No bill for this customer yet, create one */
bill = new PhoneBill(call.getFromNumber());
bill.addCall(call);
em.persist(bill);
} else {
/* Add call to existing bill */
bill.addCall(call);
}
}
}
55-32 The Java EE 7 Tutorial
The phonebilling Example Application
55.9.1.4 The Phone Billing Chunk Step
The second step is composed of the BillReader, BillProcessor, BillWriter, and
BillPartitionMapper batch artifacts. This step gets the phone bills from the database,
computes the tax and total amount due, and writes each bill to a text file. Since the
processing of each bill is independent of the others, this step can be partitioned and
run in more than one thread.
The BillPartitionMapper artifact specifies the number of partitions and the
parameters for each partition. In this example, the parameters represent the range of
items each partition should process. The artifact obtains the number of bills in the
database to calculate these ranges. It provides a partition plan object that overrides the
getPartitions and getPartitionProperties methods of the PartitionPlan interface.
The getPartitions method looks like this:
@Override
public Properties[] getPartitionProperties() {
/* Assign an (approximately) equal number of elements
* to each partition. */
long totalItems = getBillCount();
long partItems = (long) totalItems / getPartitions();
long remItems = totalItems % getPartitions();
/* Populate a Properties array. Each Properties element
* in the array corresponds to a partition. */
Properties[] props = new Properties[getPartitions()];
for (int i = 0; i < getPartitions(); i++) {
props[i] = new Properties();
props[i].setProperty("firstItem",
String.valueOf(i * partItems));
/* Last partition gets the remainder elements */
if (i == getPartitions() - 1) {
props[i].setProperty("numItems",
String.valueOf(partItems + remItems));
} else {
props[i].setProperty("numItems",
String.valueOf(partItems));
}
return props;
}
The BillReader artifact obtains the partition parameters as follows:
@Dependent
@Named("BillReader")
public class BillReader implements ItemReader {
@Inject
@BatchProperty(name = "firstItem")
private String firstItemValue;
@Inject
@BatchProperty(name = "numItems")
private String numItemsValue;
private ItemNumberCheckpoint checkpoint;
@PersistenceContext
private EntityManager em;
private Iterator iterator;
@Override
Batch Processing 55-33
The phonebilling Example Application
public void open(Serializable ckpt) throws Exception {
/* Get the range of items to work on in this partition */
long firstItem0 = Long.parseLong(firstItemValue);
long numItems0 = Long.parseLong(numItemsValue);
if (ckpt == null) {
/* Create a checkpoint object for this partition */
checkpoint = new ItemNumberCheckpoint();
checkpoint.setItemNumber(firstItem0);
checkpoint.setNumItems(numItems0);
} else {
checkpoint = (ItemNumberCheckpoint) ckpt;
}
/* Adjust range for this partition from the checkpoint */
long firstItem = checkpoint.getItemNumber();
long numItems = numItems0 - (firstItem - firstItem0);
...
}
...
}
This artifact also obtains an iterator to read items from the JPA entity manager:
/* Obtain an iterator for the bills in this partition */
String query = "SELECT b FROM PhoneBill b ORDER BY b.phoneNumber";
Query q = em.createQuery(query).setFirstResult((int) firstItem)
.setMaxResults((int) numItems);
iterator = q.getResultList().iterator();
The BillProcessor artifact iterates over the list of call records in a bill and calculates
the tax and total amount due for each bill.
The BillWriter artifact writes each bill to a plain text file.
55.9.1.5 The JavaServer Faces Pages
The index.xhtml page contains a text area that shows the log file of call records. The
page provides a button for the user to submit the batch job and navigate to the next
page:
<body>
<h1>The Phone Billing Example Application</h1>
<h2>Log file</h2>
<p>The batch job analyzes the following log file:</p>
<textarea cols="90" rows="25"
readonly="true">#{jsfBean.createAndShowLog()}</textarea>
<p> </p>
<h:form>
<h:commandButton value="Start Batch Job"
action="#{jsfBean.startBatchJob()}" />
</h:form>
</body>
This page calls the methods of the managed bean to show the log file and submit the
batch job.
The jobstarted.xhtml page provides a button to check the current status of the batch
job and displays the bills when the job finishes:
<p>Current Status of the Job: <b>#{jsfBean.jobStatus}</b></p>
<h:dataTable var="_row" value="#{jsfBean.rowList}"
55-34 The Java EE 7 Tutorial
The phonebilling Example Application
border="1" rendered="#{jsfBean.completed}">
<!-- ... show results from jsfBean.rowList ... -->
</h:dataTable>
<!-- Render the check status button if the job has not finished -->
<h:form>
<h:commandButton value="Check Status"
rendered="#{jsfBean.completed==false}"
action="jobstarted" />
</h:form>
55.9.1.6 The Managed Bean
The JsfBean managed bean submits the job to the batch runtime, checks on the status
of the job, and reads the text files for each bill.
The startBatchJob method of the bean submits the job to the batch runtime:
/* Submit the batch job to the batch runtime.
* JSF Navigation method (return the name of the next page) */
public String startBatchJob() {
jobOperator = BatchRuntime.getJobOperator();
execID = jobOperator.start("phonebilling", null);
return "jobstarted";
}
The getJobStatus method of the bean checks the status of the job:
/* Get the status of the job from the batch runtime */
public String getJobStatus() {
return jobOperator.getJobExecution(execID).getBatchStatus().toString();
}
The getRowList method of the bean creates a list of bills to be displayed on the
jobstarted.xhtml JSF page using a table.
55.9.2 Running the phonebilling Example Application
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
phonebilling example application.
55.9.2.1 To Run the phonebilling Example Application Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/batch
4.
Select the phonebilling folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the phonebilling project and select Run.
This command builds and packages the application into a WAR file,
phonebilling.war, located in the target/ directory; deploys it to the server; and
launches a web browser window at the following URL:
http://localhost:8080/phonebilling/
Batch Processing 55-35
Further Information about Batch Processing
55.9.2.2 To Run the phonebilling Example Application Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/batch/phonebilling/
3.
Enter the following command to deploy the application:
mvn install
4.
Open a web browser window at the following URL:
http://localhost:8080/phonebilling/
55.10 Further Information about Batch Processing
For more information on batch processing in Java EE, see the Batch Applications for
the Java Platform specification:
http://www.jcp.org/en/jsr/detail?id=352
55-36 The Java EE 7 Tutorial
56
Concurrency Utilities for Java EE
56
This chapter describes Concurrency Utilities for Java EE, which are specified by JSR
236.
This chapter covers the following topics:
■
Concurrency Basics
■
Main Components of the Concurrency Utilities
■
Concurrency and Transactions
■
Concurrency and Security
■
The jobs Concurrency Example
■
The taskcreator Concurrency Example
■
Further Information about the Concurrency Utilities
56.1 Concurrency Basics
Concurrency is the concept of executing two or more tasks at the same time (in
parallel). Tasks may include methods (functions), parts of a program, or even other
programs. With current computer architectures, support for multiple cores and
multiple processors in a single CPU is very common.
The Java Platform has always offered support for concurrent programming, which was
the basis for implementing many of the services offered by Java EE containers. At Java
SE 5, additional high-level API support for concurrency was provided by the
java.util.concurrent package.
Prior to Java EE 7, there were no specific APIs that allowed enterprise developers to
use concurrency utilities in a safely standard manner. The Java EE web and EJB
containers instantiate objects using container-managed thread pools. Therefore, using
Java SE concurrent APIs to instantiate Thread objects was strongly discouraged. If a
developer creates a new (non-managed) Thread object, the container could not
guarantee that other Java EE platform services (for example, transactions and security)
would be part of this Thread.
56.1.1 Threads and Processes
The two main concurrency concepts are processes and threads.
Processes are primarily associated with applications running on the operating system
(OS). A process has specific runtime resources to interact with the underlying OS and
allocate other resources, such as its own memory, just as the JVM process does. A JVM
is in fact a process.
Concurrency Utilities for Java EE 56-1
Main Components of the Concurrency Utilities
The Java programming language and platform are primarily concerned with threads.
Threads share some features with processes, since both consume resources from the
OS or the execution environment. But threads are easier to create and consume many
fewer resources than a process.
Because threads are so lightweight, any modern CPU that has a couple of cores and a
few gigabytes of RAM can handle thousands of threads in a single JVM process. The
precise number of threads will depend on the combined output of the CPU, OS, and
RAM available, as well as on correct configuration (tuning) of the JVM.
Although concurrent programming solves many problems and can improve
performance for most applications, there are a number of situations where multiple
execution lines (threads or processes) can cause major problems. These situations
include the following:
■
Deadlocks
■
Thread starvation
■
Concurrent accessing of shared resources
■
Situations when the program generates incorrect data
56.2 Main Components of the Concurrency Utilities
Concurrent resources are managed objects that provide concurrency capabilities to
Java EE applications. In GlassFish Server, you configure concurrent resources and then
make them available for use by application components such as servlets and
enterprise beans. Concurrent resources are accessed through JNDI lookup or resource
injection.
The primary components of the concurrency utilities are as follows.
■
ManagedExecutorService: A managed executor service is used by applications to
execute submitted tasks asynchronously. Tasks are executed on threads that are
started and managed by the container. The context of the container is propagated
to the thread executing the task.
For example, by using an ManagedExecutorService.submit() call, a task, such as
the GenerateReportTask, could be submitted to execute at a later time and then, by
using the Future object callback, retrieve the result when it becomes available.
■
■
■
ManagedScheduledExecutorService: A managed scheduled executor service is
used by applications to execute submitted tasks asynchronously at specific times.
Tasks are executed on threads that are started and managed by the container. The
context of the container is propagated to the thread executing the task. The API
provides the scheduling functionality that allows users to set a specific date/time
for the Task execution programmatically in the application.
ContextService: A context service is used to create dynamic proxy objects that
capture the context of a container and enable applications to run within that
context at a later time or be submitted to a Managed Executor Service. The context
of the container is propagated to the thread executing the task.
ManagedThreadFactory: A managed thread factory is used by applications to
create managed threads. The threads are started and managed by the container.
The context of the container is propagated to the thread executing the task. This
object can also be used to provide custom factories for specific use cases (with
custom Threads) and, for example, set specific/proprietary properties to these
objects.
56-2 The Java EE 7 Tutorial
The jobs Concurrency Example
56.3 Concurrency and Transactions
The most basic operations for transactions are commit and rollback, but, in a
distributed environment with concurrent processing, it can be difficult to guarantee
that commit or rollback operations will be successfully processed, and the transaction
can be spread among different threads, CPU cores, physical machines, and networks.
Ensuring that a rollback operation will successfully execute in such a scenario is
crucial. Concurrency Utilities relies on the Java Transaction API (JTA) to implement
and support transactions on its components through
javax.transaction.UserTransaction, allowing application developers to explicitly
manage transaction boundaries. More information is available in the JTA specification.
Optionally, context objects can begin, commit, or roll back transactions, but these
objects cannot enlist in parent component transactions.
The following code snippet illustrates a Runnable task that obtains a UserTransaction
and then starts and commits a transaction while interacting with other transactional
components, such as an enterprise bean and a database:
public class MyTransactionalTask implements Runnable {
UserTransaction ut = ... // obtained through JNDI or injection
public void run() {
// Start a transaction
ut.begin();
// Invoke a Service or an EJB
myEJB.businessMethod();
// Update a database entity using an XA JDBC driver
myEJB.updateCustomer(customer);
// Commit the transaction
ut.commit();
}
}
56.4 Concurrency and Security
Concurrency Utilities for Java EE defers most security decisions to the application
server implementation. If, however, the container supports a security context, that
context can be propagated to the thread of execution. The ContextService can support
several runtime behaviors, and the security attribute, if enabled, will propagate the
container security principal.
56.5 The jobs Concurrency Example
This section describes a very basic example that shows how to use some of the basic
concurrency features in an enterprise application. Specifically, this example uses one of
the main components of Concurrency Utilities for Java EE, a Managed Executor
Service.
The example demonstrates a scenario where a RESTful web service, exposed as a
public API, is used to submit generic jobs for execution. These jobs are processed in the
background. Each job prints a "Starting" and a "Finished" message at the beginning
Concurrency Utilities for Java EE 56-3
The jobs Concurrency Example
and end of the execution. Also, to simulate background processing, each job takes 10
seconds to execute.
The RESTful service exposes two methods:
■
■
/token: Exposed as a GET method that registers and returns valid API tokens
/process: Exposed as a POST method that receives a jobID query parameter,
which is the identifier for the job to be executed, and a custom HTTP header
named X-REST-API-Key, which will be used internally to validate requests with
tokens
The token is used to differentiate the Quality of Service (QoS) offered by the API.
Users that provide a token in a service request can process multiple concurrent jobs.
However, users that do not provide a token can process only one job at a time. Since
every job takes 10 seconds to execute, users that provide no token will be able to
execute only one call to the service every 10 seconds. For users that provide a token,
processing will be much faster.
This differentiation is made possible by the use of two different Managed Executor
Services, one for each type of request.
56.5.1 Running the jobs Example
After configuring GlassFish Server by adding two Managed Executor Services, you
can use either NetBeans IDE or Maven to build, package, deploy, and run the jobs
example.
56.5.1.1 To Configure GlassFish Server for the Basic Concurrency Example
To configure GlassFish Server, follow these steps.
1.
Open the Administration Console at http://localhost:4848.
2.
Expand the Resources node.
3.
Expand the Concurrent Resources node.
4.
Click Managed Executor Services.
5.
On the Managed Executor Services page, click New to open the New Managed
Executor Services page.
6.
In the JNDI Name field, enter MES_High to create the high-priority Managed
Executor Service. Use the following settings (keep the default values for other
settings):
■
Thread Priority: 10
■
Core Size: 2
■
Maximum Pool Size: 5
■
Task Queue Capacity: 2
7.
Click OK.
8.
On the On the Managed Executor Services page, click New again.
9.
In the JNDI Name field, enter MES_Low to create the low-priority Managed
Executor Service. Use the following settings (keep the default values for other
settings):
■
Thread Priority: 1
■
Core Size: 1
56-4 The Java EE 7 Tutorial
The jobs Concurrency Example
■
Maximum Pool Size: 1
■
Task Queue Capacity: 0
10. Click OK.
56.5.1.2 To Build, Package, and Deploy the jobs Example Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/concurrency
4.
Select the jobs folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the jobs project and select Build.
This command builds and deploys the application.
56.5.1.3 To Build, Package, and Deploy the jobs Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/concurrency/jobs
3.
Enter the following command to build and deploy the application:
mvn install
56.5.1.4 To Run the jobs Example and Submit Jobs with Low Priority
To run the example as a user who submits jobs with low priority, follow these steps:
1.
In a web browser, enter the following URL:
http://localhost:8080/jobs
2.
In the Jobs Client page, enter the value 1 in the Enter a JobID field, enter nothing
in the Enter a Token field, then click Submit Job.
The following message should be displayed at the bottom of the page:
Job 1 successfully submitted
The server log includes the following messages:
INFO:
INFO:
INFO:
INFO:
Invalid or missing token!
Task started LOW-1
Job 1 successfully submitted
Task finished LOW-1
You submitted a job with low priority. This means that you cannot submit another
job for 10 seconds. If you try to do so, the RESTful API will return a service
unavailable (HTTP 503) response and the following message will be displayed at
the bottom of the page:
Job 2 was NOT submitted
Concurrency Utilities for Java EE 56-5
The jobs Concurrency Example
The server log will include the following messages:
INFO:
INFO:
INFO:
INFO:
INFO:
INFO:
Invalid or missing token!
Job 1 successfully submitted
Task started LOW-1
Invalid or missing token!
Job 2 was NOT submitted
Task finished LOW-1
56.5.1.5 To Run the jobs Example and Submit Jobs with High Priority
To run the example as a user who submits jobs with high priority, follow these steps:
1.
In a web browser, enter the following URL:
http://localhost:8080/jobs
2.
In the Jobs Client page, enter a value of one to ten digits in the Enter a JobID field.
3.
Click the here link on the line "Get a token here" to get a token. The page that
displays the token will open in a new tab.
4.
Copy the token and return to the Jobs Client page.
5.
Paste the token in the Enter a Token field, then click Submit Job.
A message like the following should be displayed at the bottom of the page:
Job 11 successfully submitted
The server log includes the following messages:
INFO:
INFO:
INFO:
INFO:
Token accepted. Execution with high priority.
Task started HIGH-11
Job 11 successfully submitted
Task finished HIGH-11
You submitted a job with high priority. This means that you can submit multiple
jobs, each with a token, and not face the 10 second per job restriction that the low
priority submitters face. If you submit 3 jobs with tokens in rapid succession,
messages like the following will be displayed at the bottom of the page:
Job 1 was submitted
Job 2 was submitted
Job 3 was submitted
The server log will include the following messages:
INFO:
INFO:
INFO:
INFO:
INFO:
INFO:
INFO:
INFO:
INFO:
INFO:
INFO:
INFO:
56-6 The Java EE 7 Tutorial
Token accepted. Execution with high priority.
Task started HIGH-1
Job 1 successfully submitted
Token accepted. Execution with high priority.
Task started HIGH-2
Job 2 successfully submitted
Task finished HIGH-1
Token accepted. Execution with high priority.
Task started HIGH-3
Job 3 successfully submitted
Task finished HIGH-2
Task finished HIGH-3
The taskcreator Concurrency Example
56.6 The taskcreator Concurrency Example
The taskcreator example demonstrates how to use Concurrency Utilities for Java EE
to run tasks immediately, periodically, or after a fixed delay. This example provides a
JavaServer Faces interface that enables users to submit tasks to be executed and
displays information messages for each task. The example uses the Managed Executor
Service to run tasks immediately and the Managed Scheduled Executor Service to run
tasks periodically or after a fixed delay. (See Main Components of the Concurrency
Utilities for information about these services.)
The taskcreator example consists of the following components.
■
■
■
■
■
A JavaServer Faces page (index.xhtml) that contains three elements: a form to
submit tasks, a task execution log, and a form to cancel periodic tasks. This page
submits Ajax requests to create and cancel tasks. This page also receives
WebSocket messages, using JavaScript code to update the task execution log.
A CDI managed bean (TaskCreatorBean) that processes the requests from the
JavaServer Faces page. This bean invokes the methods in TaskEJB to submit new
tasks and to cancel periodic tasks.
An enterprise bean (TaskEJB) that obtains executor service instances using
resource injection and submits tasks for execution. This bean is also a JAX-RS web
service endpoint. The tasks send information messages to this endpoint.
A WebSocket endpoint (InfoEndpoint) that the enterprise bean uses to send
information messages to the clients.
A task class (Task) that implements the Runnable interface. The run method in this
class sends information messages to the web service endpoint in TaskEJB and
sleeps for 1.5 seconds.
Figure 56–1 shows the architecture of the taskcreator example.
Figure 56–1 Architecture of the taskcreator Example
TaskCreatorBean
index.xhtml
Request new tasks
Get execution log
updates
Request AJAX page
updates using a
WebSocket
message
TaskEJB
Request updates for
parts of the page
InfoEndpoint
Schedule new tasks
Task
Send info messages
to web service
The TaskEJB class obtains the default executor service objects from the application
server as follows:
@Resource(name="java:comp/DefaultManagedExecutorService")
ManagedExecutorService mExecService;
Concurrency Utilities for Java EE 56-7
The taskcreator Concurrency Example
@Resource(name="java:comp/DefaultManagedScheduledExecutorService")
ManagedScheduledExecutorService sExecService;
The submitTask method in TaskEJB uses these objects to submit tasks for execution as
follows:
public void submitTask(Task task, String type) {
/* Use the managed executor objects from the app server */
switch (type) {
case "IMMEDIATE":
mExecService.submit(task);
break;
case "DELAYED":
sExecService.schedule(task, 3, TimeUnit.SECONDS);
break;
case "PERIODIC":
ScheduledFuture<?> fut;
fut = sExecService.scheduleAtFixedRate(task, 0, 8,
TimeUnit.SECONDS);
periodicTasks.put(task.getName(), fut);
break;
}
}
For periodic tasks, TaskEJB keeps a reference to the ScheduledFuture object, so that
the user can cancel the task at any time.
56.6.1 Running the taskcreator Example
This section describes how to build, package, deploy, and run the taskcreator
example using NetBeans IDE or Maven.
56.6.1.1 To Build, Package, and Deploy the taskcreator Example Using NetBeans
IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/concurrency
4.
Select the taskcreator folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the taskcreator project and select Build.
This command builds and deploys the application.
56.6.1.2 To Build, Package, and Deploy the taskcreator Example Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
In a terminal window, go to:
tut-install/examples/concurrency/taskcreator
3.
Enter the following command to build and deploy the application:
56-8 The Java EE 7 Tutorial
Further Information about the Concurrency Utilities
mvn install
56.6.1.3 To Run the taskcreator Example
1.
Open the following URL in a web browser:
http://localhost:8080/taskcreator/
The page contains a form to submit tasks, a task execution log, and a form to
cancel periodic tasks.
2.
Select the Immediate task type, enter a task name, and click the Submit button.
Messages like the following appear in the task execution log:
12:40:47 - IMMEDIATE Task TaskA finished
12:40:45 - IMMEDIATE Task TaskA started
3.
Select the Delayed (3 sec) task type, enter a task name, and click the Submit
button. Messages like the following appear in the task execution log:
12:43:26 - DELAYED Task TaskB finished
12:43:25 - DELAYED Task TaskB started
12:43:22 - DELAYED Task TaskB submitted
4.
Select the Periodic (8 sec) task type, enter a task name, and click the Submit
button. Messages like the following appear in the task execution log:
12:45:25
12:45:23
12:45:17
12:45:15
-
PERIODIC
PERIODIC
PERIODIC
PERIODIC
Task
Task
Task
Task
TaskC
TaskC
TaskC
TaskC
finished run #2
started run #2
finished run #1
started run #1
You can add more than one periodic task. To cancel a periodic task, select it from
the form and click Cancel Task.
56.7 Further Information about the Concurrency Utilities
For more information about concurrency, see
■
Concurrency Utilities for Java EE specification:
http://jcp.org/en/jsr/detail?id=236
■
Concurrency Utilities specification:
http://jcp.org/en/jsr/detail?id=166
■
Concurrency Lesson in The Java Tutorials:
http://docs.oracle.com/javase/tutorial/essential/concurrency/
Concurrency Utilities for Java EE 56-9
Further Information about the Concurrency Utilities
56-10 The Java EE 7 Tutorial
Part XII
Part XII
Case Studies
Part XII presents case studies that use a variety of Java EE technologies. This part
contains the following chapters:
■
Chapter 57, "Duke's Bookstore Case Study Example"
■
Chapter 58, "Duke's Tutoring Case Study Example"
■
Chapter 59, "Duke's Forest Case Study Example"
57
Duke's Bookstore Case Study Example
57
The Duke's Bookstore example is a simple e-commerce application that illustrates
some of the more advanced features of JavaServer Faces technology in combination
with Contexts and Dependency Injection for Java EE (CDI), enterprise beans, and the
Java Persistence API. Users can select books from an image map, view the bookstore
catalog, and purchase books. No security is used in this application.
The following topics are addressed here:
■
Design and Architecture of Duke's Bookstore
■
The Duke's Bookstore Interface
■
Running the Duke's Bookstore Case Study Application
57.1 Design and Architecture of Duke's Bookstore
Duke's Bookstore is a simple web application that uses many features of JavaServer
Faces technology, in addition to other Java EE 7 features:
■
■
JavaServer Faces technology, as well as Contexts and Dependency Injection for
Java EE (CDI)
–
A set of Facelets pages, along with a template, provides the user interface to
the application.
–
CDI managed beans are associated with each of the Facelets pages.
–
A custom image map component on the front page allows you to select a book
to enter the store. Each area of the map is represented by a JavaServer Faces
managed bean. Text hyperlinks are also provided for accessibility.
–
Action listeners are registered on the image map and the text links. These
listeners retrieve the ID value for the selected book and store it in the session
map so it can be retrieved by the managed bean for the next page.
–
The h:dataTable tag is used to render the book catalog and shopping cart
contents dynamically.
–
A custom converter is registered on the credit card field on the checkout page,
bookcashier.xhtml, which also uses an f:validateRegEx tag to ensure that
the input is correctly formatted.
–
A value-change listener is registered on the name field on bookcashier.xhtml.
This listener saves the name in a parameter so the following page,
bookreceipt.xhtml, can access it.
Enterprise beans: Local, no-interface-view stateless session bean and singleton
bean
Duke's Bookstore Case Study Example 57-1
The Duke's Bookstore Interface
■
A Java Persistence API entity
The packages of the Duke's Bookstore application, located in the
tut-install/examples/case-studies/dukes-bookstore/src/main/java/javaeetutoria
l/dukesbookstore/ directory, are as follows:
■
components: Includes the custom UI component classes, MapComponent and
AreaComponent
■
converters: Includes the custom converter class, CreditCardConverter
■
ejb: Includes two enterprise beans:
–
A singleton bean, ConfigBean, that initializes the data in the database
–
A stateless session bean, BookRequestBean, that contains the business logic to
manage the entity
■
entity: Includes the Book entity class
■
exceptions: Includes three exception classes
■
listeners: Includes the event handler and event listener classes
■
model: Includes a model JavaBeans class
■
renderers: Includes the custom renderers for the custom UI component classes
■
web.managedbeans: Includes the managed beans for the Facelets pages
■
web.messages: Includes the resource bundle files for localized messages
57.2 The Duke's Bookstore Interface
This section provides additional detail regarding the components of the Duke's
Bookstore example and how they interact.
57.2.1 The Book Java Persistence API Entity
The Book entity, located in the dukesbookstore.entity package, encapsulates the book
data stored by Duke's Bookstore.
The Book entity defines attributes used in the example:
■
A book ID
■
The author's first name
■
The author's surname
■
The title
■
The price
■
Whether the book is on sale
■
The publication year
■
A description of the book
■
The number of copies in the inventory
The Book entity also defines a simple named query, findBooks.
57-2 The Java EE 7 Tutorial
The Duke's Bookstore Interface
57.2.2 Enterprise Beans Used in Duke's Bookstore
Two enterprise beans located in the dukesbookstore.ejb package provide the business
logic for Duke's Bookstore.
■
■
BookRequestBean is a stateful session bean that contains the business methods for
the application. The methods create, retrieve, and purchase books, and update the
inventory for a book. To retrieve the books, the getBooks method calls the
findBooks named query defined in the Book entity.
ConfigBean is a singleton session bean used to create the books in the catalog
when the application is initially deployed. It calls the createBook method defined
in BookRequestBean.
57.2.3 Facelets Pages and Managed Beans Used in Duke's Bookstore
The Duke's Bookstore application uses Facelets and its templating features to display
the user interface. The Facelets pages interact with a set of CDI managed beans that act
as backing beans, providing the underlying properties and methods for the user
interface. The front page also interacts with the custom components used by the
application.
The application uses the following Facelets pages, which are located in the
tut-install/examples/case-studies/dukes-bookstore/src/main/webapp/ directory.
■
bookstoreTemplate.xhtml: The template file, which specifies a header used on
every page as well as the style sheet used by all the pages. The template also
retrieves the language set in the web browser.
Uses the LocaleBean managed bean.
■
■
index.xhtml: Landing page, which lays out the custom map and area components
using managed beans configured in the faces-config.xml file and allows the user
to select a book and advance to the bookstore.xhtml page.
bookstore.xhtml: Page that allows the user to obtain details on the selected book
or the featured book, to add either book to the shopping cart, and to advance to
the bookcatalog.xhtml page.
Uses the BookstoreBean managed bean.
■
bookdetails.xhtml: Page that shows details on a book selected from
bookstore.xhtml or other pages and allows the user to add the book to the cart
and/or advance to the bookcatalog.xhtml page.
Uses the BookDetailsBean managed bean.
■
bookcatalog.xhtml: Page that displays the books in the catalog and allows the
user to add books to the shopping cart, view the details for any book, view the
shopping cart, empty the shopping cart, or purchase the books in the shopping
cart.
Uses the BookstoreBean, CatalogBean, and ShoppingCart managed beans.
■
bookshowcart.xhtml: Page that displays the contents of the shopping cart and
allows the user to remove items, view the details for an item, empty the shopping
cart, purchase the books in the shopping cart, or return to the catalog.
Uses the ShowCartBean and ShoppingCart managed beans.
■
bookcashier.xhtml: Page that allows the user to purchase books, specify a
shipping option, subscribe to newsletters, or join the Duke Fan Club with a
purchase over a certain amount.
Duke's Bookstore Case Study Example 57-3
The Duke's Bookstore Interface
Uses the CashierBean and ShoppingCart managed beans.
■
bookreceipt.xhtml: Page that confirms the user's purchase and allows the user to
return to the catalog page to continue shopping.
Uses the CashierBean managed bean.
■
bookordererror.xhtml: Page rendered by CashierBean if the bookstore has no
more copies of a book that was ordered.
The application uses the following managed beans, which are located in the
tut-install/examples/case-studies/dukes-bookstore/src/main/java/javaeetutoria
l/dukesbookstore/web/managedbeans/ directory.
■
■
■
■
■
■
■
■
■
AbstractBean: Contains utility methods called by other managed beans.
BookDetailsBean: Backing bean for the bookdetails.xhtml page. Specifies the
name details.
BookstoreBean: Backing bean for the bookstore.xhtml page. Specifies the name
store.
CashierBean: Backing bean for the bookcashier.xhtml and bookreceipt.xhtml
pages.
CatalogBean: Backing bean for the bookcatalog.xhtml page. Specifies the name
catalog.
LocaleBean: Managed bean that retrieves the current locale; used on each page.
ShoppingCart: Backing bean used by the bookcashier.xhtml, bookcatalog.xhtml,
and bookshowcart.xhtml pages. Specifies the name cart.
ShoppingCartItem: Contains methods called by ShoppingCart, CatalogBean, and
ShowCartBean.
ShowCartBean: Backing bean for the bookshowcart.xhtml page. Specifies the name
showcart.
57.2.4 Custom Components and Other Custom Objects Used in Duke's Bookstore
The map and area custom components for Duke's Bookstore, along with associated
renderer, listener, and model classes, are defined in the following packages in the
tut-install/examples/case-studies/dukes-bookstore/src/main/java/javaeetutoria
l/dukesbookstore/ directory.
■
■
■
■
components: Contains the MapComponent and AreaComponent classes. See Creating
Custom Component Classes.
listeners: Contains the AreaSelectedEvent class, along with other listener
classes. See Handling Events for Custom Components.
model: Contains the ImageArea class. See Configuring Model Data for more
information.
renderers: Contains the MapRenderer and AreaRenderer classes. See Delegating
Rendering to a Renderer.
The
tut-install/examples/case-studies/dukes-bookstore/src/java/dukesbookstore/
directory also contains a custom converter and other custom listeners not specifically
tied to the custom components.
■
converters: Contains the CreditCardConverter class. See Creating and Using a
Custom Converter.
57-4 The Java EE 7 Tutorial
The Duke's Bookstore Interface
■
listeners: Contains the LinkBookChangeListener, MapBookChangeListener, and
NameChanged classes. See Implementing an Event Listener.
57.2.5 Properties Files Used in Duke's Bookstore
The strings used in the Duke's Bookstore application are encapsulated into resource
bundles to allow the display of localized strings in multiple locales. The properties
files, located in the
tut-install/examples/case-studies/dukes-bookstore/src/main/java/javaeetutoria
l/dukesbookstore/web/messages/ directory, consist of a default file containing
English strings and three additional files for other locales. The files are as follows:
■
Messages.properties: Default file, containing English strings
■
Messages_de.properties: File containing German strings
■
Messages_es.properties: File containing Spanish strings
■
Messages_fr.properties: File containing French strings
The language setting in the user's web browser determines which locale is used. The
html tag in bookstoreTemplate.xhtml retrieves the language setting from the
language property of LocaleBean:
<html lang="#{localeBean.language}"
...
For more information about resource bundles, see Chapter 20, "Internationalizing and
Localizing Web Applications."
The resource bundle is configured as follows in the faces-config.xml file:
<application>
<resource-bundle>
<base-name>
javaeetutorial.dukesbookstore.web.messages.Messages
</base-name>
<var>bundle</var>
</resource-bundle>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>de</supported-locale>
<supported-locale>es</supported-locale>
<supported-locale>fr</supported-locale>
</locale-config>
</application>
This configuration means that in the Facelets pages, messages are retrieved using the
prefix bundle with the key found in the Messages_locale.properties file, as in the
following example from the index.xhtml page:
<h:outputText style="font-weight:bold"
value="#{bundle.ChooseBook}" />
In Messages.properties, the key string is defined as follows:
ChooseBook=Choose a Book from our Catalog
57.2.6 Deployment Descriptors Used in Duke's Bookstore
The following deployment descriptors are used in Duke's Bookstore:
Duke's Bookstore Case Study Example 57-5
Running the Duke's Bookstore Case Study Application
■
■
■
■
src/main/resources/META-INF/persistence.xml: The Java Persistence API
configuration file
src/main/webapp/WEB-INF/bookstore.taglib.xml: The tag library descriptor file
for the custom components
src/main/webapp/WEB-INF/faces-config.xml: The JavaServer Faces
configuration file, which configures the managed beans for the map component as
well as the resource bundles for the application
src/main/webapp/WEB-INF/web.xml: The web application configuration file
57.3 Running the Duke's Bookstore Case Study Application
You can use either NetBeans IDE or Maven to build, package, deploy, and run the
Duke's Bookstore application.
57.3.1 To Build and Deploy Duke's Bookstore Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/case-studies
4.
Select the dukes-bookstore folder.
5.
Click Open Project.
6.
In the Projects tab, right-click the dukes-bookstore project and select Build.
This will build, package, and deploy Duke's Bookstore to GlassFish Server.
57.3.2 To Build and Deploy Duke's Bookstore Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server), as well as the database server (see Starting and Stopping the
Java DB Server).
2.
In a terminal window, go to:
tut-install/examples/case-studies/dukes-bookstore/
3.
Enter the following command:
mvn install
This command builds the application and packages it in a WAR file in the
tut-install/examples/case-studies/dukes-bookstore/target/ directory. It then
deploys the application to GlassFish Server.
57.3.3 To Run Duke's Bookstore
1.
In a web browser, enter the following URL:
http://localhost:8080/dukes-bookstore/
2.
On the Duke's Bookstore main page, click a book in the graphic, or click one of the
links at the bottom of the page.
57-6 The Java EE 7 Tutorial
Running the Duke's Bookstore Case Study Application
3.
Use the pages in the application to view and purchase books.
Duke's Bookstore Case Study Example 57-7
Running the Duke's Bookstore Case Study Application
57-8 The Java EE 7 Tutorial
58
Duke's Tutoring Case Study Example
58
The Duke's Tutoring example application is a tracking system for a tutoring center for
students. Students can be checked in and out and can visit the park. The tutoring
center can track attendance and status updates and can store contact information for
guardians and students. Administrators can maintain the tutoring center system.
The following topics are addressed here:
■
Design and Architecture of Duke's Tutoring
■
Main Interface
■
Administration Interface
■
Running the Duke's Tutoring Case Study Application
58.1 Design and Architecture of Duke's Tutoring
Duke's Tutoring is a web application that incorporates several Java EE technologies. It
exposes both a main interface (for students, guardians, and tutoring center staff) and
an administration interface (for staff to maintain the system). The business logic for
both interfaces is provided by enterprise beans. The enterprise beans use the Java
Persistence API to create and store the application's data in the database. Figure 58–1
illustrates the architecture of the application.
Duke's Tutoring Case Study Example 58-1
Design and Architecture of Duke's Tutoring
Figure 58–1 Architecture of the Duke's Tutoring Example Application
Java EE Server
Web Container
EJB Container
Database Server
ConfigBean
Main
Interface
(JSF)
Client
RequestBean
Admin
Interface
(JSF)
AdminBean
Database
Admin Client
The Duke's Tutoring application is organized into two main projects: the
dukes-tutoring-common library and the dukes-tutoring-war web application. The
dukes-tutoring-common library project contains the entity classes and helper classes
used by the dukes-tutoring-war web application, and dukes-tutoring-common is
packaged and deployed with dukes-tutoring-war. The library JAR file is useful for
allowing the entity classes and helper classes to be reused by other applications, such
as a JavaFX client application.
Duke's Tutoring uses the following Java EE 7 platform features:
■
■
■
Java Persistence API entities
–
A custom Bean Validation annotation, @Email, for validating email addresses
–
A standard jta-data-source definition that will create the JDBC resource on
deployment
–
A standard property in the persistence.xml deployment descriptor to
automatically and portably create and delete the tables in the
jta-data-source
Enterprise beans
–
Local, no-interface view session and singleton beans
–
JAX-RS resources in a session bean
–
Java EE security constraints on the administrative interface business methods
–
All enterprise beans packaged within the WAR
WebSocket
–
■
A WebSocket server endpoint that automatically publishes the status of
students to client endpoints
Contexts and Dependency Injection
–
A CDI event that is fired when the status of a student changes
58-2 The Java EE 7 Tutorial
Main Interface
■
–
Handler methods for updating the application once the status event is fired
–
CDI managed beans for Facelets pages
–
Bean Validation annotations in the CDI managed beans
JavaServer Faces technology, using Facelets for the web front end
–
Templating
–
Composite components
–
A custom formatter, PhoneNumberFormatter
–
Security constraints on the administrative interface
–
Ajax-enabled Facelets components
The Duke's Tutoring application has two main user interfaces, both packaged within a
single WAR file:
■
■
The main interface, for students, guardians, and staff
The administrative interface used by the staff to manage the students and
guardians, and to generate attendance reports
58.2 Main Interface
The main interface allows students and staff to check students in and out, and record
when students are outside at the playground.
58.2.1 Java Persistence API Entities Used in the Main Interface
The following entities used in the main interface encapsulate data stored and
manipulated by Duke's Tutoring, and are located in the dukestutoring.entity
package in the dukes-tutoring-common project.
■
■
■
■
■
■
Person: The Person entity defines attributes common to students and guardians
tracked by the application. These attributes are the person's name and contact
information, including phone numbers and email address. This entity has two
subclasses, Student and Guardian.
PersonDetails: The PersonDetails entity is used to store additional data common
to all people, such as attributes like pictures and the person's birthday, which
aren't included in the Person entity for performance reasons.
Student and Guardian: The Student entity stores attributes specific to the students
who come to tutoring. This includes information like the student's grade level and
school. The Guardian entity's attributes are specific to the parents or guardians of a
Student. Students and guardians have a many-to-many relationship. That is, a
student may have one or more guardians, and a guardian may have one or more
students.
Address: The Address entity represents a mailing address and is associated with
Person entities. Addresses and people have a many-to-one relationship. That is,
one person may have many addresses.
TutoringSession: The TutoringSession entity represents a particular day at the
tutoring center. A particular tutoring session tracks which students attended that
day, and which students went to the park.
StatusEntry: The StatusEntry entity, which logs when a student's status changes,
is associated with the TutoringSession entity. Students' statuses change when
Duke's Tutoring Case Study Example 58-3
Main Interface
they check in to a tutoring session, when they go to the park, and when they check
out. The status entry allows the tutoring center staff to track exactly which
students attended a tutoring session, when they checked in and out, which
students went to the park while they were at the tutoring center, and when they
went to and came back from the park.
For information on creating Java Persistence API entities, see Chapter 37, "Introduction
to the Java Persistence API." For information on validating entity data, see Validating
Persistent Fields and Properties and Chapter 22, "Bean Validation: Advanced Topics."
58.2.2 Enterprise Beans Used in the Main Interface
The following enterprise beans used in the main interface provide the business logic
for Duke's Tutoring, and are located in the dukestutoring.ejb package in the
dukes-tutoring-war project:
■
■
ConfigBean is a singleton session bean used to create the default students when
the application is initially deployed, and to create an automatic EJB timer that
creates tutoring session entities every weekday.
RequestBean is a stateless session bean containing the business methods for the
main interface. The bean also has business methods for retrieving lists of students.
These business methods use strongly typed Criteria API queries to retrieve data
from the database. RequestBean also injects a CDI event instance, StatusEvent.
This event is fired from the business methods when the status of a student
changes.
For information on creating and using enterprise beans, see Enterprise Beans. For
information on creating strongly typed Criteria API queries, see Chapter 40, "Using the
Criteria API to Create Queries." For information on CDI events, see Using Events in
CDI Applications.
58.2.3 WebSocket Endpoint Used in the Main Interface
The javaeetutorial.dukestutoring.web.websocket.StatusEndpoint class is a
WebSocket server endpoint that returns students and their status to client endpoints.
The StatusEndpoint.updateStatus method is a CDI observer method for the
StatusEvent event. When a student's status changes in the main interface, a
StatusEvent is fired. The updateStatus observer method is called by the container,
and pushes out the status change to all the client endpoints registered with
StatusEndpoint.
The index.xhtml JavaServer Faces page contains JavaScript code to connect to the
WebSocket endpoint. The onMessage method on this page clicks a JavaServer Faces
button, which makes an Ajax request to refresh the table that shows the current status
of the students.
For more information on WebSocket endpoints, see Chapter 18, "Java API for
WebSocket." For information on CDI events, see Using Events in CDI Applications.
58.2.4 Facelets Files Used in the Main Interface
The Duke's Tutoring application uses Facelets to display the user interface, making
extensive use of the templating features of Facelets. Facelets, the default display
technology for JavaServer Faces technology, consists of XHTML files located in the
tut-install/examples/case-studies/dukes-tutoring-war/src/main/webapp/
directory.
The following Facelets files are used in the main interface:
58-4 The Java EE 7 Tutorial
Main Interface
■
template.xhtml: Template file for the main interface
■
error.xhtml: Error file if something goes wrong
■
index.xhtml: Landing page for the main interface
■
park.xhtml: Page showing who is currently at the park
■
current.xhtml: Page showing who is currently in today's tutoring session
■
■
■
■
■
■
statusEntries.xhtml: Page showing the detailed status entry log for today's
session
resources/components/allStudentsTable.xhtml: A composite component for a
table displaying all active students
resources/components/allInactiveStudentsTable.xhtml: A composite
component for a table displaying all inactive students
resources/components/currentSessionTable.xhtml: A composite component for
a table displaying all students in today's session
resources/components/parkTable.xhtml: A composite component for a table
displaying all students currently at the park
WEB-INF/includes/mainNav.xhtml: XHTML fragment for the main interface's
navigation bar
For information on using Facelets, see Chapter 8, "Introduction to Facelets."
58.2.5 Helper Classes Used in the Main Interface
The following helper classes, found in the dukes-tutoring-common project's
dukestutoring.util package, are used in the main interface.
■
■
■
CalendarUtil: A class that provides a method to strip the unnecessary time data
from java.util.Calendar instances.
Email: A custom Bean Validation annotation class for validating email addresses in
the Person entity.
StatusType: An enumerated type defining the different statuses that a student can
have. Possible values are IN, OUT, and PARK. StatusType is used throughout the
application, including in the StatusEntry entity, and throughout the main
interface. StatusType also defines a toString method that returns a localized
translation of the status based on the locale.
58.2.6 Properties Files
The strings used in the main interface are encapsulated into resource bundles to allow
the display of localized strings in multiple locales. Each of the properties files has
locale-specific files appended with locale codes, containing the translated strings for
each locale. For example, Messages_es.properties contains the localized strings for
Spanish locales.
The dukes-tutoring-common project has the following resource bundle under
src/main/resources/.
■
javaeetutorial/dukestutoring/util/StatusMessages.properties: Strings for
each of the status types defined in the StatusType enumerated type for the default
locale. Each supported locale has a property file of the form StatusMessages_locale
prefix.properties containing the localized strings. For example, the strings for
Spanish-speaking locales are located in StatusMessages_es.properties.
Duke's Tutoring Case Study Example 58-5
Administration Interface
The dukes-tutoring-war project has the following resource bundles under
src/main/resources/.
■
■
ValidationMessages.properties: Strings for the default locale used by the Bean
Validation runtime to display validation messages. This file must be named
ValidationMessages.properties and located in the default package as required
by the Bean Validation specification. Each supported locale has a property file of
the form ValidationMessages_locale prefix.properties containing the localized
strings. For example, the strings for German-speaking locales are located in
ValidationMessages_de.properties.
javaeetutorial/dukestutoring/web/messages/Messages.properties: Strings for
the default locale for the main and administration Facelets interface. Each
supported locale has a property file of the form Messages_locale prefix.properties
containing the localized strings. For example, the strings for simplified
Chinese-speaking locales are located in Messages_zh.properties.
For information on localizing web applications, see Registering Application Messages.
58.2.7 Deployment Descriptors Used in Duke's Tutoring
Duke's Tutoring uses these deployment descriptors in the src/main/webapp/WEB-INF
directory of the dukes-tutoring-war project:
■
■
■
faces-config.xml: The JavaServer Faces configuration file
glassfish-web.xml: The configuration file specific to GlassFish Server, which
defines security role mapping
web.xml: The web application configuration file
Duke's Tutoring also uses the following deployment descriptor in the
src/main/resources/META-INF directory of the dukes-tutoring-common project:
■
persistence.xml: The Java Persistence API configuration file
No enterprise bean deployment descriptor is used in Duke's Tutoring. Annotations in
the enterprise bean class files are used for the configuration of enterprise beans in this
application.
58.3 Administration Interface
The administration interface of Duke's Tutoring is used by the tutoring center staff to
manage the data employed by the main interface: the students, the students'
guardians, and the addresses. The administration interface uses many of the same
components as the main interface. Additional components that are only used in the
administration interface are described here.
58.3.1 Enterprise Beans Used in the Administration Interface
The following enterprise bean, in the dukestutoring.ejb package of the
dukes-tutoring-war project, is used in the administration interface.
■
AdminBean: A stateless session bean for all the business logic used in the
administration interface. Calls security methods to allow invocation of the
business methods only by authorized users.
58-6 The Java EE 7 Tutorial
Administration Interface
58.3.2 Facelets Files Used in the Administration Interface
The following Facelets files, under src/main/webapp/, are used in the administration
interface:
■
admin/adminTemplate.xhtml: Template for the administration interface
■
admin/index.xhtml: Landing page for the administration interface
■
login.xhtml: Login page for the security-constrained administration interface
■
■
■
■
■
■
loginError.xhtml: Page displayed if there are errors authenticating the
administration user
admin/address directory: Pages that allow you to create, edit, and delete Address
entities
admin/guardian directory: Pages that allow you to create, edit, and delete
Guardian entities
admin/student directory: Pages that allow you to create, edit, and delete Student
entities
resources/components/formLogin.xhtml: Composite component for a login form
using Java EE security
WEB-INF/includes/adminNav.xhtml: XHTML fragment for the administration
interface's navigation bar
58.3.3 CDI Managed Beans Used in the Administration Interface
The CDI managed beans used in the administration interface are located in the
dukestutoring.web package in the dukes-tutoring-war project.
■
■
■
StudentBean.java: A managed bean for the Facelets pages used to create and edit
students. The first and last names have Bean Validation annotations that require
the fields to be filled in. The phone numbers have Bean Validation annotations to
ensure that the submitted data is well-formed.
GuardianBean.java: A managed bean for the Facelets pages used to create
guardians for and assign guardians to students. The first and last names have
Bean Validation annotations that require the fields to be filled in. The phone
numbers have Bean Validation annotations to ensure that the submitted data is
well-formed.
AddressBean.java: A managed bean for the Facelets pages used to create
addresses for students. The street, city, province, and postal code attributes have
Bean Validation annotations that require the fields to be filled in, and the postal
code attribute has an additional annotation to ensure that the data is properly
formed.
58.3.4 Helper Classes Used in the Administration Interface
The following helper classes, found in the dukes-tutoring-war project's
dukestutoring.web.util package, are used in the administration interface.
■
EntityConverter: A parent class to StudentConverter and GuardianConverter
that defines a cache to store the entity classes when converting the entities for use
in JavaServer Faces user interface components. The cache helps increase
performance. The cache is stored in the JavaServer Faces context.
Duke's Tutoring Case Study Example 58-7
Running the Duke's Tutoring Case Study Application
■
■
StudentConverter: A JavaServer Faces converter for the Student entity class. This
class contains methods to convert Student instances to strings and back again, so
they can be used in the user interface components of the application.
GuardianConverter: Similar to StudentConverter, this class is a converter for the
Guardian entity class.
58.4 Running the Duke's Tutoring Case Study Application
This section describes how to build, package, deploy, and run the Duke's Tutoring
application.
58.4.1 Running Duke's Tutoring
You can use either NetBeans IDE or Maven to build, package, deploy, and run Duke's
Tutoring.
58.4.1.1 To Build and Deploy Duke's Tutoring Using NetBeans IDE
Before You Begin
You must have already configured GlassFish Server as a Java EE server in NetBeans
IDE, as described in To Add GlassFish Server as a Server Using NetBeans IDE.
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server).
2.
If the database server is not already running, start it as described in Starting and
Stopping the Java DB Server.
3.
From the File menu, choose Open Project.
4.
In the Open Project dialog box, navigate to:
tut-install/examples/case-studies
5.
Select the dukes-tutoring folder.
6.
Select the Open Required Projects check box and click Open Project.
Note: The first time you open Duke's Tutoring in NetBeans, you
will see error glyphs in the Projects tab. This is expected, as the
metamodel files used by the enterprise beans for Criteria API
queries have not yet been generated.
7.
In the Projects tab, right-click the dukes-tutoring project and select Build.
This command creates a JDBC security realm named tutoringRealm, builds and
packages the dukes-tutoring-common and dukes-tutoring-war projects, and
deploys dukes-tutoring-war to GlassFish Server, starting the Java DB database
and GlassFish Server if they have not already been started.
58.4.1.2 To Build and Deploy Duke's Tutoring Using Maven
1.
Make sure that GlassFish Server has started (see Starting and Stopping GlassFish
Server).
2.
If the database server is not already running, start it as described in Starting and
Stopping the Java DB Server.
58-8 The Java EE 7 Tutorial
Running the Duke's Tutoring Case Study Application
3.
In a terminal window, go to:
tut-install/examples/case-studies/dukes-tutoring/
4.
Enter the following command:
mvn install
This command creates a JDBC security realm named tutoringRealm, builds and
packages the dukes-tutoring-common and dukes-tutoring-war projects, and
deploys dukes-tutoring-war to GlassFish Server.
58.4.1.3 Using Duke's Tutoring
Once Duke's Tutoring is running on GlassFish Server, use the main interface to
experiment with checking students in and out or sending them to the park.
To Use the Main Interface of Duke's Tutoring
1.
In a web browser, open the main interface at the following URL:
http://localhost:8080/dukes-tutoring-war/
2.
Use the main interface to check students in and out, and to log when the students
go to the park.
To Use the Administration Interface of Duke's Tutoring
Follow these instructions to log in to the administration interface of Duke's Tutoring
and add new students, guardians, and addresses.
1.
From the main interface, open the administration interface by clicking
Administration main page in the left menu.
This redirects you to the login page at the following URL:
http://localhost:8080/dukes-tutoring-war/admin/index.xhtml
2.
On the login page, enter admin@example.com in the User name field, and enter
javaee in the Password field.
3.
Use the administration interface to add or modify students, add guardians, or add
addresses.
■
■
■
■
To add a new student, click Create new student in the left menu, fill in the
fields (two are required) in the form that opens, and click Submit. The Email,
Home phone, and Mobile phone fields have formatting requirements
enforced by HTML5 pass-through or by Bean Validation constraints.
To modify a student, click Edit next to the student's name, modify the fields in
the form that opens, and click Submit. To edit another student, choose the
student from the drop-down menu at the top of the page and click Change
student.
To remove a student, click Remove next to the student's name, then click
Confirm in the page that appears. This action removes the student from the
tutoring session but does not remove the student from the database. To add
the student to the tutoring session again, click Activate student in the left
menu, then click Activate next to the student's name in the page that appears.
To add a guardian for a student, click Add guardian next to the student's
name. The page that appears shows the student's name, the available
guardians, and the current guardians for the student, if any. To add an existing
guardian for that student, select the guardian from the list and click Add
Duke's Tutoring Case Study Example 58-9
Running the Duke's Tutoring Case Study Application
guardian. To create a new guardian for the student, fill in the fields and click
Submit. To remove a guardian from a student, select one of the student's
current guardians from the list and click Remove guardian.
■
To add an address for a student, click Add address next to the student's name.
In the page that appears, fill in the appropriate fields in the form that appears,
and click Submit. Four fields are required.
The administration interface is not fully implemented. It is not possible to edit a
guardian or to view or edit an address, although Facelets pages exist for these features.
The application also makes no use of the properties in the PersonDetails entity. Feel
free to modify the application to add these features.
58-10 The Java EE 7 Tutorial
59
Duke's Forest Case Study Example
59
Duke's Forest is a simple e-commerce application that contains several web
applications and illustrates the use of multiple Java EE 7 APIs:
■
JavaServer Faces technology, including Ajax
■
Contexts and Dependency Injection for Java EE (CDI)
■
Java API for RESTful Web Services (JAX-RS)
■
Java Persistence API (JPA)
■
Java API for JavaBeans Validation (Bean Validation)
■
Enterprise JavaBeans (EJB) technology
■
Java Message Service (JMS)
The application consists of the following projects.
■
■
■
■
■
■
Duke's Store: A web application that has a product catalog, customer
self-registration, and a shopping cart. It also has an administration interface for
product, category, and user management. The project name is dukes-store.
Duke's Shipment: A web application that provides an interface for order shipment
management. The project name is dukes-shipment.
Duke's Payment: A web service application that has a RESTful web service for
order payment. The project name is dukes-payment.
Duke's Resources: A simple Java archive project that contains all resources used by
the web projects. It includes messages, CSS style sheets, images, JavaScript files,
and JavaServer Faces composite components. The project name is
dukes-resources.
Entities: A simple Java archive project that contains all JPA entities. This project is
shared among other projects that use the entities. The project name is entities.
Events: A simple Java archive project that contains a POJO class that is used as a
CDI event. The project name is events.
The following topics are addressed here:
■
Design and Architecture of Duke's Forest
■
Building and Deploying the Duke's Forest Case Study Application
■
Running the Duke's Forest Application
Duke's Forest Case Study Example 59-1
Design and Architecture of Duke's Forest
59.1 Design and Architecture of Duke's Forest
Duke's Forest is a complex application consisting of three main projects and three
subprojects. Figure 59–1 shows the architecture of the three main projects that you will
deploy: Duke's Store, Duke's Shipment, and Duke's Payment. It also shows how
Duke's Store makes use of the Events and Entities projects.
Figure 59–1 Architecture of the Duke's Forest Example Application
Duke’s Shipment
Duke’s Payment
EJB Container
Web Services
ShipmentBean
OrderBrowser
Main Interface (Web Pages)
PaymentService
Duke’s Store
Main Interface (Web Pages)
Web Services / REST
Events
OrderBean
OrderEvent
Admin Interface (Web Pages)
EJB Container
AdministratorBean
CategoryBean
OrderBean
OrderJMSManager
UserBean
ProductBean
ShoppingCart
GroupsBean
EventDispatchBean
OrderStatusBean
OrderDetailBean
Entities.jar
Person
Customer
Category
CustomerOrder
OrderDetailPK
Administrator
Groups
Product
OrderDetail
OrderStatus
Duke's Forest uses the following Java EE 7 platform features:
■
■
■
■
Java Persistence API entities
–
Bean Validation annotations on the entities for verifying data
–
XML annotations for Java API for XML binding (JAXB) serialization
Web services
–
A JAX-RS web service for payment, with security constraints
–
A JAX-RS web service that is EJB based
Enterprise beans
–
Local session beans
–
All enterprise beans packaged within the WAR
Contexts and Dependency Injection (CDI)
–
CDI annotations for JavaServer Faces components
–
A CDI managed bean used as a shopping cart, with conversation scoping
–
Qualifiers
59-2 The Java EE 7 Tutorial
Design and Architecture of Duke's Forest
–
■
Servlets
–
■
■
Events and event handlers
A servlet for dynamic image presentation
JavaServer Faces 2.2 technology, using Facelets for the web front end
–
Templating
–
Composite components
–
File upload
–
Resources packaged in a JAR file so they can be found in the classpath
Security
–
Java EE security constraints on the administrative interface business methods
(enterprise beans)
–
Security constraints for customers and administrators (web components)
–
Single Sign-On (SSO) to propagate an authenticated user identity from Duke's
Store to Duke's Shipment
The Duke's Forest application has two main user interfaces, both packaged within the
Duke's Store WAR file:
■
■
The main interface, for customers and guests
The administrative interface used to perform back office operations, such as
adding new items to the catalog
The Duke's Shipment application also has a user interface, accessible to administrators.
Figure 59–2 shows how the web applications and the web service interact.
Duke's Forest Case Study Example 59-3
Design and Architecture of Duke's Forest
Figure 59–2 Interactions between Duke's Forest Components
Duke’s
Shipment
JMS Client
HTTP
Duke’s
Payment
Customer
Orders
Main Interface
(Web Pages)
Payment
Service
HTTP
OrderQueue
Administrator
json
json
REST/
HTTP
Customer
Orders
REST/
HTTP
Duke’s Store
HTTP
Admin Interface
(Web Pages)
Web Services
API
JMS
Client
Main Interface
(Web Pages)
Facade
Entities
JDBC
Customer
Database
As illustrated in Figure 59–2, the customer interacts with the main interface of Duke's
Store, while the administrator interacts with the administration interface. Both
interfaces access a façade consisting of managed beans and stateless session beans,
which in turn interact with the entities that represent database tables. The façade also
interacts with web services APIs that access the Duke's Payment web service. When
the payment for an order is approved, Duke's Store sends the order to a JMS queue.
The administrator also interacts with the interface of Duke's Shipment, which can be
accessed either directly through Duke's Shipment or from the administration interface
of Duke's Store by means of a web service. When the administrator approves an order
for shipping, Duke's Shipment consumes the order from the JMS queue.
The most fundamental building blocks of the application are the Events and Entities
projects, which are bundled into Duke's Store and Duke's Shipment along with the
Duke's Resources project.
59.1.1 The events Project
Events are one of the core components of Duke's Forest. The events project, included
in all three of the main projects, is the most simple project of the application. It has
only one class, OrderEvent, but this class is responsible for most of the messages
between objects in the application.
59-4 The Java EE 7 Tutorial
Design and Architecture of Duke's Forest
The application can send messages based on events to different components and react
to them based on the qualification of the event. The application supports the following
qualifiers:
■
@LoggedIn: For authenticated users
■
@New: When a new order is created by the shopping cart
■
@Paid: When an order is paid for and ready for shipment
The following code snippet from the PaymentHandler class of Duke's Store shows how
the @Paid event is handled:
@Inject @Paid Event<OrderEvent> eventManager;
...
public void onNewOrder(@Observes @New OrderEvent event) {
if (processPayment(event)) {
orderBean.setOrderStatus(event.getOrderID(),
String.valueOf(OrderBean.Status.PENDING_PAYMENT.getStatus()));
logger.info("Payment Approved");
eventManager.fire(event);
} else {
orderBean.setOrderStatus(event.getOrderID(),
String.valueOf(OrderBean.Status.CANCELLED_PAYMENT.getStatus()));
logger.info("Payment Denied");
}
}
To enable users to add more events to the project easily or update an event class with
more fields for a new client, this component is a separate project within the
application.
59.1.2 The entities Project
The entities project is a Java Persistence API (JPA) project used by both Duke's Store
and Duke's Shipment. It is generated from the database schema shown in Figure 59–3
and is also used as a base for the entities consumed and produced by the web services
through JAXB. Each entity has validation rules based on business requirements,
specified using Bean Validation.
Duke's Forest Case Study Example 59-5
Design and Architecture of Duke's Forest
Figure 59–3 Duke's Forest Database Tables and Their Relationships
CATEGORY
PRODUCT
ID INT
ID INT
NAME VARCHAR(45)
NAME VARCHAR(45)
TAGS VARCHAR(45)
PRICE DECIMAL(10,2)
DESCRIPTION VARCHAR(45)
GROUPS
IMG VARCHAR(45)
ID INT
CATEGORY_ID INT
NAME VARCHAR(50)
IMG_SRC BLOB(1073741823)
DESCRIPTION VARCHAR(300)
ORDER_DETAIL
PERSON_GROUPS
ORDER_ID INT
GROUPS_ID INT
PRODUCT_ID INT
EMAIL VARCHAR(45)
QTY INT
PERSON
CUSTOMER_ORDER
ID INT
ID INT
FIRSTNAME VARCHAR(50)
AMOUNT FLOAT(52)
LASTNAME VARCHAR(100)
DATE_CREATED TIMESTAMP
EMAIL VARCHAR(45)
CUSTOMER_ID INT
ADDRESS VARCHAR(45)
STATUS_ID INT
CITY VARCHAR(45)
PASSWORD VARCHAR(100)
DTYPE VARCHAR(31)
ORDER_STATUS
Primary key
Required field
Foreign key
Field
ID INT
STATUS VARCHAR(45)
DESCRIPTION VARCHAR(200)
The database schema contains eight tables:
■
■
■
■
■
■
■
PERSON, which has a one-to-many relationship with PERSON_GROUPS and CUSTOMER_
ORDER
GROUPS, which has a one-to-many relationship with PERSON_GROUPS
PERSON_GROUPS, which has a many-to-one relationship with PERSON and GROUPS (it
is the join table between those two tables)
PRODUCT, which has a many-to-one relationship with CATEGORY and a one-to-many
relationship with ORDER_DETAIL
CATEGORY, which has a one-to-many relationship with PRODUCT
CUSTOMER_ORDER, which has a one-to-many relationship with ORDER_DETAIL and a
many-to-one relationship with PERSON and ORDER_STATUS
ORDER_DETAIL, which has a many-to-one relationship with PRODUCT and CUSTOMER_
ORDER (it is the join table between those two tables)
59-6 The Java EE 7 Tutorial
Design and Architecture of Duke's Forest
■
ORDER_STATUS, which has a one-to-many relationship with CUSTOMER_ORDER
The entity classes that correspond to these tables are as follows.
■
■
■
■
■
■
■
■
■
Person, which defines attributes common to customers and administrators. These
attributes are the person's name and contact information, including street and
email addresses. The email address has a Bean Validation annotation to ensure
that the submitted data is well-formed. The generated table for the Person entity
also has a DTYPE field that represents the discriminator column. Its value identifies
the subclass (Customer or Administrator) to which the person belongs.
Customer, a specialization of Person with a specific field for CustomerOrder
objects.
Administrator, a specialization of Person with fields for administration
privileges.
Groups, which represents the group (USERS or ADMINS) to which the user belongs.
Product, which defines attributes for products. These attributes include name,
price, description, associated image, and category.
Category, which defines attributes for product categories. These attributes include
a name and a set of tags.
CustomerOrder, which defines attributes for orders placed by customers. These
attributes include an amount and a date, along with id values for the customer
and the order detail.
OrderDetail, which defines attributes for the order detail. These attributes include
a quantity and id values for the product and the customer.
OrderStatus, which defines a status attribute for each order.
59.1.3 The dukes-payment Project
The dukes-payment project is a web project that holds a simple Payment web service.
Since this is an example application, it does not obtain any real credit information or
even customer status to validate the payment. For now, the only rule imposed by the
payment system is to deny all orders above $1,000. This application illustrates a
common scenario where a third-party payment service is used to validate credit cards
or bank payments.
The project uses HTTP Basic Authentication and JAAS (Java Authentication and
Authorization Service) to authenticate a customer to a JAX-RS web service. The
implementation itself exposes a simple method, processPayment, which receives an
OrderEvent to evaluate and approve or deny the order payment. The method is called
from the checkout process of Duke's Store.
59.1.4 The dukes-resources Project
The dukes-resources project contains a number of files used by both Duke's Store and
Duke's Shipment, bundled into a JAR file placed in the classpath. The resources are in
the src/main/resources directory:
■
META-INF/resources/css: Two style sheets, default.css and jsfcrud.css
■
META-INF/resources/img: Images used by the projects
■
META-INF/resources/js: A JavaScript file, util.js
■
META-INF/resources/util: Composite components used by the projects
Duke's Forest Case Study Example 59-7
Design and Architecture of Duke's Forest
■
bundles/Bundle.properties: Application messages in English
■
bundles/Bundle_es.properties: Application messages in Spanish
■
ValidationMessages.properties: Bean Validation messages in English
■
ValidationMessages_es.properties: Bean Validation messages in Spanish
59.1.5 The Duke's Store Project
Duke's Store, a web application, is the core application of Duke's Forest. It is
responsible for the main store interface for customers as well as the administration
interface.
The main interface of Duke's Store allows the user to perform the following tasks:
■
Browsing the product catalog
■
Signing up as a new customer
■
Adding products to the shopping cart
■
Checking out
■
Viewing order status
The administration interface of Duke's Store allows administrators to perform the
following tasks:
■
Product maintenance (create, edit, update, delete)
■
Category maintenance (create, edit, update, delete)
■
Customer maintenance (create, edit, update, delete)
■
Group maintenance (create, edit, update, delete)
The project also uses stateless session beans as façades for interactions with the JPA
entities described in The entities Project, and CDI managed beans as controllers for
interactions with Facelets pages. The project thus follows the MVC
(Model-View-Controller) pattern and applies the same pattern to all entities and pages,
as in the following example.
■
■
■
AbstractFacade is an abstract class that receives a Type<T> and implements the
common operations (CRUD) for this type, where <T> is a JPA entity.
ProductBean is a stateless session bean that extends AbstractFacade, applying
Product as Type<T>, and injects the PersistenceContext for the EntityManager.
This bean implements any custom methods needed to interact with the Product
entity or to call a custom query.
ProductController is a CDI managed bean that interacts with the necessary
enterprise beans and Facelets pages to control the way the data will be displayed.
ProductBean begins as follows:
@Stateless
public class ProductBean extends AbstractFacade<Product> {
private static final Logger logger =
Logger.getLogger(ProductBean.class.getCanonicalName());
@PersistenceContext(unitName="forestPU")
private EntityManager em;
@Override
protected EntityManager getEntityManager() {
59-8 The Java EE 7 Tutorial
Design and Architecture of Duke's Forest
return em;
}
...
59.1.5.1 Enterprise Beans Used in Duke's Store
The enterprise beans used in Duke's Store provide the business logic for the
application and are located in the com.forest.ejb package. All are stateless session
beans.
AbstractFacade is not an enterprise bean but an abstract class that implements
common operations for Type<T>, where <T> is a JPA entity.
Most of the other beans extend AbstractFacade, inject the PersistenceContext, and
implement any needed custom methods:
■
AdministratorBean
■
CategoryBean
■
EventDispatcherBean
■
GroupsBean
■
OrderBean
■
OrderDetailBean
■
OrderJMSManager
■
OrderStatusBean
■
ProductBean
■
ShoppingCart
■
UserBean
The ShoppingCart class, although it is in the ejb package, is a CDI managed bean with
conversation scope, which means that the request information will persist across
multiple requests. Also, ShoppingCart is responsible for starting the event chain for
customer orders, which invokes the RESTful web service in dukes-payment and
publishes an order to the JMS queue for shipping approval if the payment is
successful.
59.1.5.2 Facelets Files Used in the Main Interface of Duke's Store
Like the other case study examples, Duke's Store uses Facelets to display the user
interface. The main interface uses a large number of Facelets pages to display different
areas. The pages are grouped into directories based on which module they handle.
■
template.xhtml: Template file, used for both main and administration interfaces.
It first performs a browser check to verify that the user's browser supports HTML
5, which is required for Duke's Forest. It divides the screen into several areas and
specifies the client page for each area.
■
topbar.xhtml: Page for the login area at the top of the screen.
■
top.xhtml: Page for the title area.
■
left.xhtml: Page for the left sidebar.
■
index.xhtml: Page for the main screen content.
■
login.xhtml: Login page specified in web.xml. The main login interface is
provided in topbar.xhtml, but this page appears if there is a login error.
Duke's Forest Case Study Example 59-9
Design and Architecture of Duke's Forest
■
■
■
■
■
admin directory: Pages related to the administration interface, described in Facelets
Files Used in the Administration Interface of Duke's Store.
customer directory: Pages related to customers (Create.xhtml, Edit.xhtml,
List.xhtml, Profile.xhtml, View.xhtml).
order directory: Pages related to orders (Create.xhtml, List.xhtml,
MyOrders.xhtml, View.xhtml).
orderDetail directory: Popup page allowing users to view details of an order
(View_popup.xhtml).
product directory: Pages related to products (List.xhtml, ListCategory.xhtml,
View.xhtml).
59.1.5.3 Facelets Files Used in the Administration Interface of Duke's Store
The Facelets pages for the administration interface of Duke's Store are found in the
web/admin directory:
■
■
■
■
■
■
■
administrator directory: Pages related to administrator management
(Create.xhtml, Edit.xhtml, List.xhtml, View.xhtml)
category directory: Pages related to product category management
(Create.xhtml, Edit.xhtml, List.xhtml, View.xhtml)
customer directory: Pages related to customer management (Create.xhtml,
Edit.xhtml, List.xhtml, Profile.xhtml, View.xhtml)
groups directory: Pages related to group management (Create.xhtml, Edit.xhtml,
List.xhtml, View.xhtml)
order directory: Pages related to order management (Create.xhtml, Edit.xhtml,
List.xhtml, View.xhtml)
orderDetail directory: Popup page allowing the administrator to view details of
an order (View_popup.xhtml)
product directory: Pages related to product management (Confirm.xhtml,
Create.xhtml, Edit.xhtml, List.xhtml, View.xhtml)
59.1.5.4 Managed Beans Used in Duke's Store
Duke's Store uses the following CDI managed beans, which correspond to the
enterprise beans. The beans are in the com.forest.web package:
■
AdministratorController
■
CategoryController
■
CustomerController
■
CustomerOrderController
■
GroupsController
■
OrderDetailController
■
OrderStatusController
■
ProductController
■
UserController
59-10 The Java EE 7 Tutorial
Design and Architecture of Duke's Forest
59.1.5.5 Helper Classes Used in Duke's Store
The CDI managed beans in the main interface of Duke's Store use the following helper
classes, found in the com.forest.web.util package:
■
■
■
■
AbstractPaginationHelper: An abstract class with methods used by the managed
beans
ImageServlet: A servlet class that retrieves the image content from the database
and displays it
JsfUtil: Class used for JavaServer Faces operations, such as queuing messages on
a FacesContext instance
MD5Util: Class used by the CustomerController managed bean to generate an
encrypted password for a user
59.1.5.6 Qualifiers Used in Duke's Store
Duke's Store defines the following qualifiers in the com.forest.qualifiers package:
■
@LoggedIn: Qualifies a user as having logged in
■
@New: Qualifies an order as new
■
@Paid: Qualifies an order as paid
59.1.5.7 Event Handlers Used in Duke's Store
Duke's Store defines event handlers related to the OrderEvent class packaged in the
events project (see The events Project). The event handlers are in the
com.forest.handlers package.
■
■
■
IOrderHandler: The IOrderHandler interface defines a method, onNewOrder,
implemented by the two handler classes.
PaymentHandler: The ShoppingCart bean fires an OrderEvent qualified as @New.
The onNewOrder method of PaymentHandler observes these events and, when it
intercepts them, processes the payment using the Duke's Payment web service.
After a successful response from the web service, PaymentHandler fires the
OrderEvent again, this time qualified as @Paid.
DeliveryHandler: The onNewOrder method of DeliveryHandler observes
OrderEvent objects qualified as @Paid (orders paid and ready for delivery) and
modifies the order status to PENDING_SHIPMENT. When an administrator accesses
Duke's Shipment, it will call the Order Service, a RESTful web service, and ask for
all orders in the database that are ready for delivery.
59.1.5.8 Deployment Descriptors Used in Duke's Store
Duke's Store uses the following deployment descriptors, located in the web/WEB-INF
directory:
■
faces-config.xml: The JavaServer Faces configuration file
■
glassfish-web.xml: The configuration file specific to GlassFish Server
■
web.xml: The web application configuration file
59.1.6 The Duke's Shipment Project
Duke's Shipment is a web application with a login page, a main Facelets page, and
some other objects. This application, which is accessible only to administrators,
consumes orders from a JMS queue and calls the RESTful web service exposed by
Duke's Forest Case Study Example 59-11
Design and Architecture of Duke's Forest
Duke's Store to update the order status. The main page of Duke's Shipment shows a
list of orders pending shipping approval and a list of shipped orders. The
administrator can approve or deny orders for shipping. If approved, the order is
shipped, and it appears under the Shipped heading. If denied, the order disappears
from the page, and on the customer's Orders list it appears as cancelled.
There is also a gear icon on the Pending list that makes an Ajax call to the Order
Service to refresh the list without refreshing the page. The code looks like this:
<h:commandLink>
<h:graphicImage library="img" title="Check for new orders"
style="border:0px" name="refresh.png"/>
<f:ajax execute="@form" render="@form" />
</h:commandLink>
59.1.6.1 Enterprise Beans Used in Duke's Shipment
The UserBean stateless session bean used in Duke's Shipment provides the business
logic for the application and is located in the com.forest.shipment.session package.
Like Duke's Store, Duke's Shipment uses the AbstractFacade class. This class is not an
enterprise bean but an abstract class that implements common operations for Type<T>,
where <T> is a JPA entity.
The OrderBrowser stateless session bean, located in the com.forest.shipment.ejb
package, has one method that browses the JMS order queue and another that
consumes an order message after the administrator approves or denies the order for
shipment.
59.1.6.2 Facelets Files Used in Duke's Shipment
Duke's Shipment has only one page, so it has many fewer Facelets files than Duke's
Store.
■
template.xhtml: The template file, like the one in Duke's Store, first performs a
browser check to verify that the user's browser supports HTML 5, which is
required for Duke's Forest. It divides the screen into areas and specifies the client
page for each area.
■
topbar.xhtml: Page for the login area at the top of the screen.
■
top.xhtml: Page for the title area.
■
index.xhtml: Page for the initial main screen content.
■
■
login.xhtml: Login page specified in web.xml. The main login interface is
provided in topbar.xhtml, but this page appears if there is a login error.
admin/index.xhtml: Page for the main screen content after authentication.
59.1.6.3 Managed Beans Used in Duke's Shipment
Duke's Shipment uses the following CDI managed beans, in the com.forest.shipment
package:
■
■
web.ShippingBean: Managed bean that acts as a client to the Order Service
web.UserController: Managed bean that corresponds to the UserBean session
bean
59-12 The Java EE 7 Tutorial
Building and Deploying the Duke's Forest Case Study Application
59.1.6.4 Helper Class Used in Duke's Shipment
The Duke's Shipment managed beans use only one helper class, found in the
com.forest.shipment.web.util package:
■
JsfUtil: Class used for JavaServer Faces operations, such as queuing messages on
a FacesContext instance
59.1.6.5 Qualifier Used in Duke's Shipment
Duke's Shipment includes the @LoggedIn qualifier described in Qualifiers Used in
Duke's Store.
59.1.6.6 Deployment Descriptors Used in Duke's Shipment
Duke's Shipment uses the following deployment descriptors:
■
faces-config.xml: The JavaServer Faces configuration file
■
glassfish-web.xml: The configuration file specific to GlassFish Server
■
web.xml: The web application configuration file
59.2 Building and Deploying the Duke's Forest Case Study Application
You can use NetBeans IDE or Maven to build and deploy Duke's Forest.
59.2.1 To Build and Deploy the Duke's Forest Application Using NetBeans IDE
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server), as well as the database server (see Starting and Stopping the
Java DB Server).
2.
From the File menu, choose Open Project.
3.
In the Open Project dialog box, navigate to:
tut-install/examples/case-studies
4.
Select the dukes-forest folder.
5.
Select the Open Required Projects check box and click Open Project.
6.
Right-click the dukes-forest folder and select Build.
This task configures the server, creates and populates the database, builds all the
subprojects, assembles them into JAR and WAR files, and deploys the
dukes-payment, dukes-store, and dukes-shipment applications.
To configure the server, this task creates a JDBC security realm named jdbcRealm,
enables default principal-to-role mapping, and enables single sign-on (SSO) for the
HTTP Service.
59.2.2 To Build and Deploy the Duke's Forest Application Using Maven
1.
Make sure that GlassFish Server has been started (see Starting and Stopping
GlassFish Server), as well as the database server (see Starting and Stopping the
Java DB Server).
2.
In a terminal window, go to:
tut-install/examples/case-studies/dukes-forest/
Duke's Forest Case Study Example 59-13
Running the Duke's Forest Application
3.
Enter the following command to configure the server, create and populate the
database, build all the subprojects, assemble them into JAR and WAR files, and
deploy the dukes-payment, dukes-store, and dukes-shipment applications:
mvn install
To configure the server, this task creates a JDBC security realm named jdbcRealm,
enables default principal-to-role mapping, and enables single sign-on (SSO) for the
HTTP Service.
59.3 Running the Duke's Forest Application
Running the Duke's Forest application involves several tasks:
■
Registering as a customer of Duke's Store
■
As a customer, purchasing products
■
As an administrator, approving or denying shipment of a product
■
As an administrator, creating a new product, customer, group, or category
59.3.1 To Register as a Duke's Store Customer
1.
In a web browser, enter the following URL:
http://localhost:8080/dukes-store
The Duke's Forest - Store page opens.
2.
Click Sign Up at the top of the page.
3.
Fill in the form fields, then click Save.
All fields are required, and the Password value must be at least 7 characters in
length.
59.3.2 To Purchase Products
1.
To log in as the user you created, or as one of two users already in the database,
enter the user name and password and click Log In.
The preexisting users have the user names jack@example.com and
robert@example.com, and they both have the same password, 1234.
2.
Click Products in the left sidebar.
3.
On the page that appears, click one of the categories (Plants, Food, Services, or
Tools).
4.
Choose a product and click Add to Cart.
You can order only one of any one product, but you can order multiple different
products in multiple categories. The products and a running total appear in the
Shopping Cart in the left sidebar.
5.
When you have finished choosing products, click Checkout.
A message appears: "Your order is being processed. Check the Orders page to see
the status of your order."
6.
Click Orders in the left sidebar to verify your order.
59-14 The Java EE 7 Tutorial
Running the Duke's Forest Application
If the total of the order exceeds $1,000, the status of the order is "Order cancelled,"
because the Payment web service denies orders over that limit. Otherwise, the
status is "Ready to ship."
7.
When you have finished placing orders, click Logout at the top of the page.
59.3.3 To Approve Shipment of a Product
1.
Log in to Duke's Store as an administrator.
Your user name is admin@example.com, and your password is 1234.
The main administration page allows you to view categories, customers,
administrators, groups, products, and orders, and to create new objects of all types
except orders.
2.
At the bottom of the page, click Approve Shipment.
This action takes you to Duke's Shipment, retaining your administrator login.
3.
On the Pending list, click Approve to approve an order and move it to the
Shipped area of the page.
If you click Deny, the order disappears from the page. If you log in to Duke's Store
again as the customer, it will appear in the Orders list as "Order cancelled."
To return to Duke's Store from Duke's Shipment, click Return to Duke's Store.
59.3.4 To Create a New Product
You can create other kinds of objects as well as products. Creating products is more
complex than the other creation processes, so it is described here.
1.
Log in to Duke's Store as an administrator.
2.
On the main administration page, click Create New Product.
3.
Enter values in the Name, Price, and Description fields.
4.
Select a category, then click Next.
5.
On the Upload the Product Image page, click Browse to locate an image on your
file system using a file chooser.
6.
Click Next.
7.
On the next page, view the product fields, then click Done.
8.
Click Products in the left sidebar, then click the category to verify that the product
has been added.
9.
Click Administration at the top of the page to return to the main administration
page, or click Logout to log out.
Duke's Forest Case Study Example 59-15
Running the Duke's Forest Application
59-16 The Java EE 7 Tutorial
Index
Symbols
@AccessTimeout annotation, 34-10
@Alternative annotation, 25-2
@ApplicationScoped annotation, 6-6, 16-2, 23-7
@AroundInvoke annotation, 54-2
@AroundTimeout annotation, 54-2
@Asynchronous annotation, 36-1
@ConcurrencyManagement annotation, 34-8
@Consumes annotation, 29-3, 29-10
@Context annotation, 31-1
@ConversationScoped annotation, 23-7
@CookieParam annotation, 31-1
@DeclareRoles annotation, 49-3, 49-4, 49-10
@Decorator annotation, 25-10
@Delegate annotation, 25-10
@DELETE annotation, 29-3, 29-7
@DenyAll annotation, 49-5
@Dependent annotation, 16-2, 23-7
@DependsOn annotation, 34-7
@DiscriminatorColumn annotation, 37-12
@DiscriminatorValue annotation, 37-12
@Disposes annotation, 25-5
@Embeddable annotation, 37-10
@EmbeddedId annotation, 37-6
@Entity annotation, 37-1
@FlowScoped annotation, 16-2
@FormParam annotation, 31-1, 31-3
@GET annotation, 29-3, 29-7
@GroupSequence annotation, 22-3
@HEAD annotation, 29-3
@HeaderParam annotation, 31-1
@HttpConstraint annotation, 48-2, 48-16
@HttpMethodConstraint annotation, 48-2, 48-16
@Id annotation, 37-6
@IdClass annotation, 37-6
@Inject annotation, 23-6, 25-6
@Interceptor annotation, 54-2
@Interceptors annotation, 54-2
@Local annotation, 32-7, 34-2
@Lock annotation, 34-8
@ManagedBean annotation, 8-4, 16-1
@ManyToMany annotation, 37-8
@ManyToOne annotation, 37-8
@MatrixParam annotation, 31-1
@MessageDriven annotation, 46-34
@MultipartConfig annotation, 17-15
@Named annotation, 23-8
@NamedQuery annotation, 39-2
@Observes annotation, 25-7
@OnClose annotation, 18-5
@OnError annotation, 18-4
@OneToMany annotation, 37-8, 37-9
@OneToOne annotation, 37-7, 37-8, 37-9
@OnMessage annotation, 18-4
@OnOpen annotation, 18-4
@Path annotation, 29-2, 29-5
@PathParam annotation, 29-3, 29-11, 31-1, 31-2
@PermitAll annotation, 49-4
@PersistenceContext annotation, 37-14
@PersistenceUnit annotation, 37-15
@POST annotation, 29-3, 29-7
@PostActivate annotation, 34-2, 34-4
@PostConstruct annotation, 32-11, 34-2, 34-4, 54-2
@PreDestroy annotation, 32-11, 34-2, 34-4, 54-2
@PrePassivate annotation, 34-2, 34-4
@Produces annotation, 23-10, 25-4, 29-3, 29-9
@Provider annotation, 29-3
@PUT annotation, 29-3, 29-7
@Qualifier annotation, 23-5
@QueryParam annotation, 29-3, 29-11, 31-1, 31-2
@Remote annotation, 32-7, 34-2
@Remove annotation, 32-12, 34-2, 34-5
@RequestScoped annotation, 6-6, 16-2, 23-7
@Resource annotation, 3-1, 4-2, 6-14, 25-6
JMS resources, 45-8, 46-30
@ResourceDependency annotation, 10-27, 13-10
@RolesAllowed annotation, 49-4, 49-10
@RunAs annotation, 49-8
@Schedule and @Schedules annotations, 34-20
@ServletSecurity annotation, 48-2, 48-16
@SessionScoped annotation, 6-6, 16-2, 23-7
@Singleton annotation, 34-7
@Startup annotation, 34-7
@Stateful annotation, 34-2
@Timeout annotation, 34-18
@Timeout method, 34-18, 34-20
@Transient annotation, 37-3
@WebFilter annotation, 17-7
@WebInitParam annotation, 17-5, 17-8
@WebListener annotation, 17-3
@WebMethod annotation, 34-5
Index-1
@WebService annotation, 28-2
@WebServiceRef annotation, 6-15
@WebServlet annotation, 6-9, 17-4
A
abstract schemas, 39-1
access control, 47-5
acknowledge method, 45-20
acknowledging messages. See message
acknowledgment
action events, 7-8, 7-11, 10-13, 15-18
ActionEvent class, 15-18, 15-20
actionListener attribute, 10-12, 11-10, 11-11,
15-7
ActionListener implementation, 15-19, 15-20
ActionListener interface, 11-7
actionListener tag, 10-27, 11-7, 15-3
processAction(ActionEvent) method, 15-20
referencing methods that handle action
events, 11-11, 12-12
writing a managed bean method to handle action
events, 12-12
action method, 7-11
administered objects, 45-7
creating and removing, 46-3
definition, 45-4
See also connection factories, destinations
Administration Console, 1-23
starting, 2-4
afterBegin method, 51-6
afterCompletion method, 51-6
Ajax
error handling, 13-6
event attribute of f:ajax tag, 13-5
example, 13-10
execute attribute of f:ajax tag, 13-5
grouping components, 13-8
immediate attribute of f:ajax tag, 13-5
listener attribute of f:ajax tag, 13-6
loading JavaScript resource library, 13-9
monitoring events, 13-6
onerror attribute of f:ajax tag, 13-6
onevent attribute of f:ajax tag, 13-6
overview, 13-1
receiving responses, 13-7
render attribute of f:ajax tag, 13-7
request lifecycle, 13-7
sending requests, 13-4
using JavaScript API directly, 13-9
using with Facelets, 13-2
using with JavaServer Faces technology, 13-1
alternatives
CDI, 25-2
example, 26-1
annotations, 1-1
interceptor metadata, 54-1
JAX-RS, 29-2, 31-1
security, 47-8, 48-16, 49-1, 49-3
appclient tool, 1-23
Index-2
applet container, 1-10
applets, 1-5, 1-6
application client container, 1-10
application clients, 1-5
examples, 46-30
securing, 50-13
application clients, JMS
building, 46-4
examples, 46-2
running, 46-10
applications
dynamic reloading, 6-8
JavaServer Faces, 7-2
packaging, 5-1
security, 47-6
undeploying, 6-8
asadmin tool, 1-23
asynchronous message consumption, 45-6
JMS client example, 46-9
See also message-driven beans
asynchronous method invocation
calling asynchronous business methods, 36-2
cancelling, 36-3
checking status, 36-3
creating asynchronous business methods, 36-1
example, 36-3
java.util.concurrent.Future<V> interface, 36-1
retrieving results, 36-2
session beans, 36-1
asynchronous send mechanism, 45-25
attributes referencing managed bean methods, 11-10
action attribute, 11-10, 11-11
actionListener attribute, 11-10, 11-11
validator attribute, 11-10, 11-11
valueChangeListener attribute, 11-10, 11-12
audit modules, pluggable, 47-10
auditing, 47-5
auth-constraint element, 48-4
authenticate method, 48-10
authenticating users, 48-6, 48-8
authentication, 47-4, 47-16
basic, 48-6
basic with EJB, 49-6
certificate-based mutual, 50-5
client, 50-5, 50-7
digest, 48-8
form-based, 48-7, 48-18
mutual, 50-5, 50-7
server, 50-5
user name/password-based mutual, 50-6
authorization, 47-4
authorization constraints, 48-3, 48-4
authorization providers, pluggable, 47-9
auto commit, 1-17
AUTO_ACKNOWLEDGE mode, 45-20
B
basic authentication, 48-6
EJB, 49-6
example, 48-15
Batch Applications for the Java Platform, 1-20, 55-1
batch jobs
checking status, 55-22
defining, 55-7
definition, 55-1
elements, 55-5
instances and executions, 55-6
properties and parameters, 55-6
starting, 55-22
status, 55-6
steps, 55-2
submitting to batch runtime, 55-21
batch processing
context objects, 55-21
creating applications, 55-5
creating batch artifacts, 55-17
definition, 55-1
dependency injection, 55-20
examples, 55-23, 55-29
implementing chunk steps, 55-7
implementing task steps, 55-9
introduction, 55-1
Java EE framework, 55-4
Java EE platform, 55-4
Job Specification Language, 55-7, 55-10
packaging applications, 55-22
status and decision elements, 55-3
Bean Validation, 1-18, 21-1
advanced, 22-1
constraint violations, 21-6
constraints, 38-18
constructors, 21-5
custom constraints, 22-1, 58-2
empty strings, 21-4
examples, 38-18
exceptions, 21-6
inheritance, 22-4
Java Persistence API, 37-4
JavaServer Faces applications, 21-1, 38-20
localization, 22-3
messages, 22-2
methods, 21-5, 21-6, 22-4
null strings, 21-4
ordering, 22-3
parameters, 21-5, 21-6
resource bundles, 22-2
using f:validateBean tag, 11-8
bean-managed transactions. See transactions,
bean-managed
beans, in CDI, 23-4
beans.xml file, 23-10
beforeCompletion method, 51-6
BLOBs. See persistence, BLOBs
bookmarkable URLs
component tags, 10-23
example, 10-24
view parameters, 10-23
BufferedReader class, 17-6
bundles. See resource bundles
business logic, 32-1
business methods, 32-9
client calls, 34-4
exceptions, 34-5
locating, 33-2
requirements, 34-5
transactions, 51-4, 51-6, 51-7, 51-8
BytesMessage interface, 45-17
C
CallbackHandler interface, 50-13
capture-schema tool, 1-23
CDI. See Contexts and Dependency Injection for Java
EE (CDI)
certificate authorities, 50-1
certificates, 47-6
client, 50-7
digital, 47-7, 50-1, 50-2
server, 50-2, 50-4
using for authentication, 50-4
character encodings, 20-5
character sets, 20-4
client certificates, generating, 50-7
client ID, for durable subscriptions, 45-13
CLIENT_ACKNOWLEDGE mode, 45-20
clients
authenticating, 50-5, 50-7
securing, 50-13
CLOBs. See persistence, CLOBs
collections, persistence, 37-3, 40-9
commit method, 51-6
commit method (JMS), 45-24
commits. See transactions, commits
Common Client Interface, Connector
architecture, 52-5
component binding, 12-3, 12-4, 15-31, 15-34
binding attribute, 12-3, 15-31, 15-34
component properties. See managed bean properties
component rendering model, 7-5, 7-7
decode method, 7-15, 15-14, 15-20, 15-24
decoding, 15-4, 15-10
delegated implementation, 15-4
direct implementation, 15-4
encode method, 15-25
encodeBegin method, 15-12
encodeChildren method, 15-12
encodeEnd method, 15-12, 15-17
encoding, 15-4, 15-10
HTML render kit, 15-21, 16-27
render kit, 7-7
Renderer class, 7-7
Renderer implementation, 16-27
RenderKit class, 7-7
RenderKit implementation, 16-27
component tag attributes
action attribute, 10-12, 12-11, 15-7
actionListener attribute, 10-12, 11-10, 12-12,
15-7
alt attribute, 15-7
Index-3
binding attribute, 10-4, 10-6, 12-3, 15-31, 15-34
columns attribute, 10-15
converter attribute, 10-9, 11-2, 15-26
for attribute, 10-11, 10-22
id attribute, 10-4, 10-5
immediate attribute, 10-4, 10-5, 15-7
redisplay attribute, 10-10
rendered attribute, 10-4, 10-6, 15-34
style attribute, 10-4, 10-6, 10-22
styleClass attribute, 10-4, 10-6
validator attribute, 10-9, 12-12
value attribute, 10-4, 10-6, 12-4, 15-7, 15-31, 15-32
valueChangeListener attribute, 10-9, 11-12, 12-13
var attribute, 20-4
component tags, 7-8, 7-9, 12-4
attributes. See component tag attributes
body tag, 10-7
bookmarkable URLs, 10-23
button tag, 10-23
column tag, 10-2
commandButton tag, 10-2, 10-12
commandLink tag, 10-2, 10-13
dataTable tag, 10-2, 10-19, 12-5
form tag, 10-2, 10-7
graphicImage tag, 10-2, 10-13, 15-7
head tag, 10-7
inputHidden tag, 10-3, 10-8
inputSecret tag, 10-3, 10-8, 10-10
inputText tag, 10-3, 10-8, 10-10
inputTextarea tag, 10-3, 10-8
link tag, 10-23
message tag, 10-3, 10-22
messages tag, 10-3, 10-22
outputFormat tag, 10-3, 10-9, 10-11
outputLabel tag, 10-3, 10-9, 10-10
outputLink tag, 10-3, 10-9, 10-11
outputScript tag, 10-25
outputStylesheet tag, 10-25
outputText tag, 10-3, 10-9, 10-10, 10-13, 12-6
panelGrid tag, 10-3, 10-14
panelGroup tag, 10-3, 10-14
resource relocation, 10-25
selectBooleanCheckbox tag, 10-3, 10-16, 12-6
selectItems tag, 12-8
selectManyCheckbox tag, 10-3, 10-17, 12-7
selectManyListbox tag, 10-3, 10-17
selectManyMenu tag, 10-3, 10-17
selectOneListbox tag, 10-4, 10-16
selectOneMenu tag, 10-4, 10-16, 12-7, 12-8
selectOneRadio tag, 10-4, 10-16
component-managed sign-on, 50-14, 50-15
components
boxes, 10-3, 10-4
buttons, 10-2, 10-12
check boxes, 10-3, 10-16
data grids, 10-2
fields, 10-3
hidden fields, 10-3
hyperlinks, 10-13
images, 10-13
Index-4
Java EE, 1-4
labels, 10-3
links, 10-2
menus, 10-3, 10-4, 10-16, 10-17
options, 10-4
password fields, 10-3
radio buttons, 10-4
table columns, 10-2
tables, 10-3, 10-14, 10-19
text areas, 10-3
composite components
advanced features, 14-1
attributes, 14-1
default attribute, 14-1
example, 14-3
f:validateBean tag, 14-2
f:validateRegex tag, 14-2
f:validateRequired tag, 14-2
Facelets, 8-10
invoking managed beans, 14-2
method-signature attribute, 14-1
name attribute, 14-1
required attribute, 14-1
type attribute, 14-2
validating values, 14-2
concurrency
definition, 56-1
examples, 56-3, 56-7
security and, 56-3
threads and processes, 56-1
transactions and, 56-3
Concurrency Utilities for Java EE, 1-20, 56-1
concurrent access, 51-1
concurrent access to entity data, 42-1
conditional HTTP requests in JAX-RS, 31-9
confidentiality, 47-16
configuring JavaServer Faces applications
Application class, 16-3
application configuration resource files, 16-3
configuring managed beans, 16-1, 16-14
error message registration, 15-27
faces-config.xml files, 16-26
including the classes, pages, and other
resources, 16-33
javax.faces.application.CONFIG_FILES context
parameter, 16-3
registering custom converters, 16-25
registering custom renderers, 16-27
registering custom UI components, 16-29
registering custom validators, 16-24
registering messages, 16-21
specifying a path to an application configuration
resource file, 16-32
specifying where UI component state is
saved, 15-16, 16-32
value binding, 15-32
configuring JavaServer Faces applications. See
configuring navigation rules
configuring managed beans, 15-7, 16-14
configuring navigation rules, 7-10, 16-25
from-action element, 16-26
from-view-id element, 16-26
navigation-case element, 16-26, 16-27
navigation-rule element, 16-26
to-view-id element, 16-26
connection factories, 45-8
creating, 46-31, 46-42
injecting resources, 45-8, 46-30
Connection interface, 51-6, 51-9
Connection interface (JMS), 45-9
connection pooling, 3-2
ConnectionFactory interface (JMS), 45-8
connections, JMS
introduction, 45-9
managing in enterprise bean applications, 45-29
connections, securing, 47-15
connectors. See Java EE Connector architecture
constructors, 54-4
static, 21-5
container-managed sign-on, 50-14
container-managed transactions. See transactions,
container-managed
containers, 1-8
application client, 1-10
configurable services, 1-9
nonconfigurable services, 1-9
security, 47-1, 47-8
services, 1-9
trust between, 49-9
See also EJB container, embedded enterprise bean
container, web container
context parameters, 6-5
specifying, 6-12
Contexts and Dependency Injection for Java EE
(CDI), 1-18
advanced topics, 25-1
alternatives, 25-2
basic concepts, 23-1
beans, 23-4
configuring applications, 23-10
converting managed beans to JAX-RS root resource
classes, 31-8
decorators, 25-10
disposer methods, 25-5
EL, 23-8
events, 25-7, 58-2, 58-4
examples, 24-1, 26-1
Facelets pages, 23-9
injectable objects, 23-5
injecting beans, 23-6
integrating with JAX-RS, 31-8
interceptors, 25-9
managed beans, 23-4
observer methods, 25-7, 58-4
overview, 23-3
producer fields, 25-4
producer methods, 23-10, 25-4
qualifiers, 23-5
scopes, 23-7
setter and getter methods, 23-9
specialization, 25-3
stereotypes, 25-12
contexts, JMS, 45-9
ContextService interface, 56-2
conversational state, 32-2
conversion model, 7-5, 7-8
converter attribute, 10-9, 11-2, 15-26
Converter implementations, 7-8, 11-1, 15-26
Converter interface, 15-24
converterId attribute, 11-2
converting data between model and
presentation, 7-8
javax.faces.convert package, 11-1
model view, 15-24
presentation view, 15-24
See also converters, converter tags
Converter implementation classes
BigDecimalConverter class, 11-1
BigIntegerConverter class, 11-2
BooleanConverter class, 11-2
ByteConverter class, 11-2
CharacterConverter class, 11-2
DateTimeConverter class, 11-2, 11-3
DoubleConverter class, 11-2
EnumConverter class, 11-2
FloatConverter class, 11-2
IntegerConverter class, 11-2
LongConverter class, 11-2
NumberConverter class, 11-2, 11-3, 11-4
ShortConverter class, 11-2
converter tags
convertDateTime tag, 11-3
convertDateTime tag attributes, 11-4
converter tag, 11-3, 15-26
convertNumber tag, 11-3, 11-4
convertNumber tag attributes, 11-5
converters, 7-5, 7-15
custom converters, 7-8, 15-26
See also standard converters
converting data. See conversion model
cookie parameters, JAX-RS, 29-13
createBrowser method, 46-11
createTimer method, 34-19
credential, 47-12
Criteria API, 40-1
creating queries, 40-4
examples, 38-15
expressions, 40-6, 40-7
path navigation, 40-6
query execution, 40-9
query results, 40-6, 40-8
criteria queries, string-based, 41-1
cryptography, public-key, 50-2
custom converters
binding to managed bean properties, 15-35
creating, 15-23
getAsObject method, 15-24
getAsObject(FacesContext, UIComponent,
String) method, 15-24
getAsString method, 15-25
Index-5
getAsString(FacesContext, UIComponent,
Object) method, 15-24
registering. See registering custom converters
using, 15-26
custom objects
custom converters, 15-26
using, 15-22
using custom components, renderers and tags
together, 15-4
See also custom tags, custom UI components,
custom validators
custom renderers
creating the Renderer class, 15-17
determining necessity of, 15-4
performing decoding, 15-14
performing encoding, 15-12
registering with a render kit, 16-27
custom tags, 7-10, 15-4
getRendererType method, 15-18
identifying the renderer type, 15-17
specifying, 15-29
tag library descriptor, 15-9
custom UI components
creating, 15-1
creating component classes, 15-9
custom objects, 15-22
delegating rendering, 15-16
determining necessity of, 15-2
handling events emitted by, 15-20
queueEvent method, 15-14
registering. See registering custom UI components
restoreState(FacesContext, Object)
method, 15-16
saveState(FacesContext) method, 15-16
saving state, 15-15
specifying where state is saved, 16-32
steps for creating, 15-9
custom validators, 15-27
binding to managed bean properties, 15-35
custom validator tags, 15-29
implementing the Validator interface, 15-28
registering, 16-24
using, 15-30
validate method, 12-12, 15-28
Validator implementation, 12-11, 15-28, 15-30
Validator interface, 15-27
validator tag, 15-27, 15-30
loading data, 37-21
message-driven beans and, 32-4
multiple, 51-7, 51-8
See also transactions
DataSource interface, 3-2
DDL scripts, 37-20
loading data, 37-21
debugging Java EE applications, 2-7
declarative security, 47-1, 48-1, 49-1
example, 49-9
decorators
CDI, 25-10
example, 26-19
delivery delay for messages, 45-23
delivery modes, 45-21
JMSDeliveryMode message header field, 45-16
DeliveryMode interface, 45-21
Dependency Injection for Java (JSR 330), 1-18, 23-1
deployment, 33-3
deployment descriptors, 5-1, 47-1, 47-8
enterprise bean, 5-3, 47-9, 49-1, 49-3
Java EE, 5-2
runtime, 5-2, 5-5
security-role-mapping element, 47-14
security-role-ref element, 48-13
web application, 5-4, 6-2, 16-30, 47-9
Destination interface, 45-8
destinations, 45-8
creating, 46-31, 46-42
injecting resources, 45-8, 46-30
JMSDestination message header field, 45-16
temporary, 45-23, 46-38
See also queues, temporary JMS destinations, topics
destroy method, 17-13
digest authentication, 48-8
digital signatures, 50-2
disposer methods, CDI, 25-5
document roots, 5-4
doFilter method, 17-7, 17-8, 17-9
doGet method, 17-5
domains, 2-3
doPost method, 17-5
downloading GlassFish Server, 2-1
DUPS_OK_ACKNOWLEDGE mode, 45-21
durable subscriptions, 45-13
examples, 46-16, 46-24, 46-32
shared, 45-15
D
E
data encryption, 50-5
data integrity, 47-5, 51-1, 51-2
data sources, 3-2
databases
clients, 32-1
connections, 34-5, 51-7
creating tables, 37-20
data recovery, 51-1
dropping tables, 37-20
EIS tier, 1-3
eager attribute, managed beans, 16-4
EAR files, 5-1
EIS tier, 1-8
security, 50-14
EJB container, 1-10
container-managed transactions, 51-2
message-driven beans, 45-29
onMessage method, invoking, 46-30
services, 32-1, 49-1
See also embedded enterprise bean container
Index-6
EJB JAR files, 32-11
EJBContext interface, 51-6, 51-8
ejb-jar.xml file, 5-3, 47-9, 49-3
EL, 6-4, 9-1
CDI managed beans, 23-8
composite expressions, 9-6
deferred evaluation expressions, 9-2
expression examples, 9-11
immediate evaluation expressions, 9-2
literals, 9-5
lvalue expressions, 9-3
managed beans, 12-2
method expressions, 9-7
method-binding expressions, 7-11
operators, 9-9
overview, 9-1
parameterized method calls, 9-5
reserved words, 9-10
rvalue expressions, 9-3
type conversion during expression
evaluation, 9-6
value expressions, 9-3
See also method binding
embeddable classes, persistence, 37-10
embedded enterprise bean container
creating, 35-2
developing applications, 35-1
examples, 35-4
initializing enterprise bean modules, 35-3
overview, 35-1
running applications, 35-2
session bean references, 35-3
shutting down, 35-3
See also EJB container, enterprise beans
end-to-end security, 47-7
enterprise applications, 1-1
securing, 49-1
enterprise beans, 1-7, 1-15
accessing, 32-5
classes, 32-11
compiling, 33-3
contents, 32-10
converting to JAX-RS root resource classes, 31-8
defined, 32-1
dependency injection, 32-6
deployment, 32-11
distribution, 32-7
exceptions, 34-24
finding, 35-3
getCallerPrincipal method, 49-6
implementor of business logic, 1-7
integrating with JAX-RS, 31-8
interceptors, 54-1
interfaces, 32-5, 32-11
isCallerInRole method, 49-6
JAX-RS resources, 29-16
JNDI lookup, 32-6
lifecycles, 32-11
local access, 32-7
local interfaces, 32-8
packaging, 5-3, 33-3
performance, 32-7
programmatic security, 49-6
remote access, 32-9
remote interfaces, 32-9
securing, 49-1
singletons, 29-16
testing, 35-4
timer service, 34-16
types, 32-2
web services, 32-2, 32-10, 34-13
See also business methods, embedded enterprise
bean container, message-driven beans, session
beans
Enterprise Information Systems. See EIS tier
entities
abstract, 37-11
abstract schema names, 39-3
application-managed entity managers, 37-15
cascading operations, 37-9
collections, 39-15
container-managed entity managers, 37-14
controlling caching, 44-2
creating, 38-9
discriminator columns, 37-12
entity manager, 37-14
finding, 37-16, 38-10
inheritance, 37-11, 38-13
inheritance mapping, 37-12
lifecycle, 37-16
managing, 37-14, 38-9
mapping to multiple tables, 38-7
non-entity superclasses, 37-12
overview, 37-1
persistent fields, 37-2
persistent properties, 37-2
persisting, 37-16
primary keys, 37-6
querying, 37-18
relationships, 38-10
removing, 37-17, 38-11
requirements, 37-1
superclasses, 37-11
synchronizing, 37-17
validating, 37-4
entity data
lock modes, 42-2
optimistic locking, 42-1, 42-2
pessimistic locking, 42-1, 42-4
entity graphs, 43-1
named, 43-3
entity providers, JAX-RS, 29-8
entity relationships
bidirectional, 37-8
many-to-many, 37-8, 38-13
many-to-one, 37-8
multiplicity, 37-7
one-to-many, 37-8
one-to-one, 37-7
query language, 37-9
Index-7
unidirectional, 37-8
EntityManager interface, 37-14
equals method, 37-6
event and listener model, 7-5, 7-8
binding listeners to managed bean
properties, 15-35
Event class, 7-8
event handlers, 7-15, 15-9
event listeners, 7-15, 7-16, 7-17
handling events of custom UI components, 15-20
implementing event listeners, 15-18
Listener class, 7-8
listener class, 12-11
queueEvent method, 15-14
ValueChangeEvent class, 11-12
See also action events, value-change events
events
CDI, 25-7
example, 26-13
examples, 2-1
Ajax, 13-10
asynchronous method invocation, session
beans, 36-3
basic authentication, 48-15
batch processing, 55-23, 55-29
Bean Validation, 38-18
bookmarkable URLs, 10-24
building, 2-5
CDI, 24-1, 26-1
composite components, 14-3
concurrency, 56-3, 56-7
connectors, 53-1
Criteria API, 38-15
directory structure, 2-5
Duke's Bookstore case study, 57-1
Duke’s Forest case study, 59-1
Duke’s Tutoring case study, 58-1
embedded enterprise bean container, 35-4
file upload using servlets, 17-25
HTML5-friendly markup, 8-20
interceptors, 54-9
Java API for WebSocket, 18-11, 18-14
JAX-RS, 29-15, 31-16
JAX-WS, 28-2
JMS asynchronous message consumption, 46-9
JMS durable subscriptions, 46-16
JMS in a web application, 46-26
JMS local transactions, 46-18
JMS message acknowledgment, 46-14
JMS queue browsing, 46-11
JMS shared durable subscriptions, 46-24
JMS synchronous message consumption, 46-7
JMS with entities, 46-36
JMS with session beans, 46-32
message-driven beans, 46-29, 46-32, 46-36
persistence, 38-1
primary keys, 37-7
query language, 38-10, 39-4
required software, 2-1
resource adapters, 53-1
Index-8
resource library contracts, 8-15
security, 48-18, 49-9, 49-13
sending JMS messages, 46-5
servlets, 6-8, 17-23, 33-2
session beans, 33-1, 34-1
singleton session beans, 34-7
timer service, 34-21
web clients, 33-2
web services, 34-13
exceptions
business methods, 34-5
enterprise beans, 34-24
JMS, 45-19
mapping to error screens, 6-13
rolling back transactions, 34-25, 51-6
transactions, 51-4
expiration of JMS messages, 45-22
JMSExpiration message header field, 45-16
Expression Language. See EL
F
Facelets, 8-1
composite components, 8-10
configuring applications, 8-7
f:ajax tag, 13-3
features, 8-1
resources, 8-12
templating, 8-8
using Ajax with, 13-2
XHTML pages, 8-5
See also EL
Facelets applications
developing, 8-3
lifecycle, 8-3
using JavaScript in, 13-9
Faces Flows, using, 16-5
faces-config.xml file, 16-3
FacesContext class, 7-14, 15-23
Apply Request Values phase, 7-15
custom converters, 15-24
performing encoding, 15-13
Process Validations phase, 7-16
Update Model Values phase, 7-17
validation methods, 12-12
Validator interface, 15-28
FacesServlet class, 16-31
fetch graphs
See persistence
fetch graphs
fetch plans, 43-1
filter chains, 17-7, 17-9
Filter interface, 17-7
filters, 17-7
defining, 17-7
mapping to web components, 17-9
mapping to web resources, 17-9
overriding request methods, 17-9
overriding response methods, 17-9
response wrappers, 17-9
foreign keys, 38-3
form parameters, JAX-RS, 29-13, 31-3
form-based authentication, 48-7
forward method, 17-11
G
garbage collection, 32-13
GenericServlet interface, 17-1
getBody method, 45-17
getCallerPrincipal method, 49-6, 49-13
getConnection method, 3-2
getPart method, 17-16
getParts method, 17-16
getRemoteUser method, 48-12
getRequestDispatcher method, 17-10
getRollbackOnly method, 45-33, 51-8
getServletContext method, 17-11
getSession method, 17-12
getStatus method, 51-8
getUserPrincipal method, 48-12
GlassFish Server
adding users to, 47-13
downloading, 2-1
enabling debugging, 2-7
installation tips, 2-1
securing, 47-9
server log, 2-7
SSL connectors, 47-16
starting, 2-3
stopping, 2-4
tools, 1-22
groups, 47-12
managing, 47-12
H
handling events. See event and listener model
hashCode method, 37-6
header parameters, JAX-RS, 29-13
helper classes, 32-11
session bean example, 34-5
HTML5-friendly markup, 8-17
example, 8-20
pass-through attributes, 8-18
pass-through elements, 8-17
HTTP, 28-1
basic authentication, 48-6
over SSL, 50-5
HTTP cookies, 30-7
HTTP methods, 29-6
HTTP request and response entity bodies, 29-8
supported types, 29-8
HTTP request URLs, 17-6
query strings, 17-6
request paths, 17-6
HTTP requests, 17-6, 29-6
See also requests
HTTP responses, 17-7
status codes, 6-13
See also responses
HTTPS, 47-7, 47-17, 48-4, 50-2
HttpServlet interface, 17-1
HttpServletRequest interface, 17-6, 48-12
HttpServletResponse interface, 17-7
HttpSession interface, 17-12
I
identification, 47-4
implicit navigation, 7-3, 7-10
implicit objects, 15-34
binding component values to, 15-33
include method, 17-11
init method, 17-5
InitialContext interface, 1-21
initialization parameters, 17-5
initializing properties with the managed-property
element
initializing Array and List properties, 16-19
initializing managed-bean properties, 16-19
initializing Map properties, 16-18
initializing maps and lists, 16-21
referencing a context initialization
parameter, 16-17
initParams attribute, 17-5
injectable objects, CDI, 23-5
integrity, 47-16
of data, 47-5
Interceptors
around-construct, 54-4
invoking, 54-8
lifecycle callback events, 54-4
methods, 54-3
ordering, 54-8
interceptors, 54-1
CDI, 25-9
example, 54-9
example (CDI), 26-13
internationalization, 20-1
internationalizing JavaServer Faces applications
FacesContext.getLocale method, 11-4
loadBundle tag, 20-4
using the FacesMessage class to create a
message, 16-22
invalidate method, 17-12
isCallerInRole method, 49-6, 49-13
ISO 8859 character encoding, 20-5
isUserInRole method, 48-12
J
JAAS, 1-22, 47-5, 50-13
login modules, 50-14
JACC, 1-19, 47-9
JAF, 1-21
JAR files, 5-1
JAR signatures, 47-6
JASPIC, 1-19
Java API for JavaBean Validation
Index-9
See Bean Validation
Java API for JavaBean Validation. See Bean Validation
Java API for JSON Processing, 1-20
Java API for RESTful Web Services. See JAX-RS
Java API for WebSocket, 1-19, 18-1
annotated endpoints, 18-4
configuring endpoints, 18-10
creating applications, 18-2
endpoints, 18-1, 58-2, 58-4
error handling, 18-10
examples, 18-11, 18-14
introduction, 18-1
maintaining client state, 18-6
path parameters, 18-9
programmatic endpoints, 18-3
receiving messages, 18-6
sending messages, 18-5
using decoders, 18-8
using encoders, 18-7
Java API for XML Binding (JAXB), 1-21
using with JAX-RS, 31-11
Java API for XML Processing (JAXP), 1-21
Java API for XML Web Services. See JAX-WS
Java Authentication and Authorization Service. See
JAAS
Java Authentication Service Provider Interface for
Containers (JASPIC), 1-19
Java Authorization Contract for Containers. See JACC
Java BluePrints, 2-5
Java Cryptography Extension (JCE), 47-6
Java Database Connectivity API. See JDBC API
Java DB, 1-23
starting, 2-4
stopping, 2-4
Java EE applications, 1-3
debugging, 2-7
deploying, 33-3
iterative development, 33-4
tiers, 1-3
Java EE clients, 1-5
See also application clients, web clients
Java EE components, 1-4
Java EE Connector architecture, 1-18, 52-1
example, 53-1
Java EE modules, 5-1, 5-2
application client modules, 5-2
EJB modules, 5-2, 32-11
resource adapter modules, 5-2
See also web modules
Java EE platform, 1-3
APIs, 1-12
JMS and, 45-3
overview, 1-1
Java EE security model, 1-9
Java EE servers, 1-10
Java EE transaction model, 1-9
Java Generic Security Services, 47-5
Java GSS-API, 47-5
Java Message Service (JMS) API, 1-18, 45-1
See also JMS, message-driven beans
Index-10
Java Naming and Directory Interface API. See JNDI
Java Persistence API, 1-17, 37-1
See also persistence
Java Persistence API query language. See query
language
Java Persistence Criteria API. See Criteria API
Java Secure Sockets Extension (JSSE), 47-6
Java Servlet technology, 1-15, 17-1
See also servlets
Java Transaction API, 1-17, 51-7
JavaBeans Activation Framework (JAF), 1-21
JavaBeans components, 1-6
JavaMail API, 1-19
example, 53-1
JavaServer Faces application development
bean property, 12-5
Bean Validation, 21-1
managed beans, 12-1
web pages, 10-1
JavaServer Faces applications
configuring. See configuring JavaServer Faces
applications
HTML tags, 10-2
queueing messages, 12-13
JavaServer Faces core tag library, 10-1, 10-27
actionListener tag, 10-27, 11-7, 15-3
ajax tag, 13-3
attribute tag, 10-28
convertDateTime tag, 10-27, 11-3
convertDateTime tag attributes, 11-4
converter tag, 10-27, 11-3, 15-26
converterId attribute, 11-2
convertNumber tag, 10-27, 11-3, 11-4
convertNumber tag attributes, 11-5
facet tag, 10-20, 10-28
loadBundle tag, 10-28
metadata tag, 10-23, 10-28
param tag, 10-11, 10-28
selectItem tag, 10-17, 10-18, 10-28
selectItems tag, 10-17, 10-18, 10-28
type attribute, 11-6
validateBean tag, 11-8
validateDoubleRange tag, 10-28, 11-8
validateLength tag, 10-28, 11-8
validateLongRange tag, 10-28, 11-8, 11-9
validateRegEx tag, 11-8
validateRegex tag, 11-10
validateRequired tag, 11-8
validator tag, 7-10, 10-28, 15-27
custom validator tags, 15-30
valueChangeListener tag, 10-27, 11-6
viewparam tag, 10-23
JavaServer Faces standard HTML render kit
library, 7-8, 16-27
html_basic TLD, 15-21
See also component tags
JavaServer Faces standard UI components, 7-5, 15-1
UIComponent component, 15-25
JavaServer Faces tag libraries, 8-2
JavaServer Faces core tag library, 10-1, 10-27
JavaServer Faces HTML render kit tag
library, 10-1
namespace directives, 10-2
JavaServer Faces Technology
Faces Flows, 16-5
resource library contracts, 8-14
JavaServer Faces technology, 1-6, 1-16, 7-1
advantages, 7-3
bookmarkable URLs, 10-23
component tags. See component tags
composite components, 14-1
FacesContext class. See FacesContext class
FacesServlet class, 16-31
features, 7-2
HTML5-friendly markup, 8-17
partial processing, 7-17
partial rendering, 7-17
relocatable resources, 8-13
using Ajax with, 13-1, 58-3
Validator interface, 12-12
See also component rendering model
See also component tags
See also conversion model
See also event and listener model
See also Facelets
See also JavaServer Faces standard UI components
See also lifecycle of a JavaServer Faces application
See also UI component behavioral interfaces
See also UI component classes
See also validation model
JavaServer Pages Standard Tag Library (JSTL), 1-17
JavaServer Pages technology, 1-16
javax.servlet package, 17-1
javax.servlet.http package, 17-1
JAXB, 1-21
using with JAX-RS, 31-11
JAXP, 1-21
JAX-RS, 1-17, 29-1
accessing XML documents, 31-11
advanced features, 31-1
annotations, 31-1
application overview, 29-4
asynchronous invocations, 30-8
clients, 30-1
conditional HTTP requests, 31-9
configuring, 29-14
converting CDI managed beans to root resource
classes, 31-8
converting enterprise beans to root resource
classes, 31-8
cookies, 30-7
entity providers, 29-8
examples, 29-15, 31-16
extracting Java type of request or response, 31-3
filters, 30-7
form parameters, 31-3
HTTP headers, 30-6
integrating with CDI, 31-8
integrating with EJB technology, 31-8
introduction, 27-2
invocations, 30-3
JSON, 31-15
path parameters, 30-2, 31-2
path templates, 29-5
query parameters, 31-2
reference implementation, 29-1
request headers, 31-1
request method designators, 29-2, 29-7
resource class methods, 31-6
resource classes, 29-2
resource methods, 29-2
runtime content negotiation, 31-9
runtime resource resolution, 31-6
static content negotiation, 31-9
subresource locators, 31-7
subresource methods, 31-7
subresources, 31-6
URI, 31-1
using with JAXB, 31-11
JAX-RS Client API, 29-17, 30-1
JAX-RS clients, 29-17
JAX-WS, 1-22
defined, 28-1
endpoints, 28-2
examples, 28-2
introduction, 27-1
service endpoint interfaces, 28-2
specification, 28-10
JCE, 47-6
JDBC API, 1-20, 3-2
resources, 58-2
JMS, 1-18
achieving reliability and performance, 45-19
administered objects, 45-7
application client examples, 46-2
architecture, 45-4
basic concepts, 45-3
definition, 45-2
examples, 46-1, 46-26, 46-29
introduction, 45-1
Java EE platform, 45-3, 45-26
messaging domains, 45-4
programming model, 45-6
JMSConsumer interface, 45-10
JMSContext interface, 45-9
JMSCorrelationID message header field, 45-16
JMSDeliveryMode message header field, 45-16
JMSDeliveryTime message header field, 45-16
JMSDestination message header field, 45-16
JMSException class, 45-19
JMSExpiration message header field, 45-16
JMSMessageID message header field, 45-16
JMSPriority message header field, 45-16
JMSProducer interface, 45-10
JMSRedelivered message header field, 45-17
JMSReplyTo message header field, 45-16
JMSTimestamp message header field, 45-16
JMSType message header field, 45-16
JNDI, 1-21, 3-1
data source naming subcontexts, 1-21
Index-11
enterprise bean lookup, 32-6
enterprise bean naming subcontexts, 1-21
environment naming contexts, 1-21
jms naming subcontext, 45-8
namespace for JMS administered objects, 45-7
naming contexts, 1-21
naming environments, 1-21
naming subcontexts, 1-21
Job Specification Language, 55-10
batchlet element, 55-14
chunk element, 55-12
decision element, 55-17
flow element, 55-16
job element, 55-10
partition element, 55-14
split element, 55-16
step element, 55-11
jsf.js file, 13-9
JSON
JAX-RS, 31-15
JSR 339. See JAX-RS
JSR 346. See Contexts and Dependency Injection for
Java EE (CDI)
JSSE, 47-6
JSTL, 1-17
JTA, 1-17, 51-7
JTS API, 51-7
JUnit, 35-4
K
Kerberos, 47-5, 47-6
key pairs, 50-2
keystores, 47-6, 50-1, 50-2
managing, 50-2
keytool utility, 50-2
L
lifecycle of a JavaServer Faces application, 7-4, 7-13
action and value-change event processing, 7-9
Apply Request Values phase, 7-15, 15-14
custom converters, 15-24, 15-25
getRendererType method (Render Response
phase), 15-18
immediate attribute, 15-7
Invoke Application phase, 7-17
performing encoding (Render Response
phase), 15-12
Process Validations phase, 7-16
Render Response phase, 7-17
renderResponse method, 7-14, 7-15, 7-16, 7-17
responseComplete method, 7-14, 7-16, 7-17
Restore View phase, 7-15
saving state, 15-16
Update Model Values phase, 7-16
updateModels method, 7-17
Validator interface, 15-29
views, 7-15
listener classes, 17-2
Index-12
defining, 17-2
listener interfaces, 17-2
listeners
HTTP, 47-9
IIOP, 47-9
load graphs
See persistence
load graphs
local interfaces, 32-8
local transactions, 45-24
localization, 20-1
Bean Validation, 22-3
log, server, 2-7
login configuration, 48-6, 48-8
login method, 48-10
login modules, 50-13
logout method, 48-10
M
managed bean creation facility, 16-14
managed bean declarations, 15-7
key-class element, 16-18
list-entries element, 16-17
managed-bean element, 16-15, 16-20
managed-bean-name element, 16-15
managed-property element, 16-17
map-entries element, 16-17, 16-18
map-entry element, 16-18
null-value elements, 16-17
value element, 16-17
managed bean methods
attributes. See attributes referencing managed bean
methods
referencing. See referencing managed bean
methods
writing. See writing managed bean methods
managed bean properties, 11-2, 12-1, 12-3, 15-31
bound to component instances, 12-9
UIData properties, 12-5
UIInput and UIOutput properties, 12-5
UISelectBoolean properties, 12-6
UISelectItem properties, 12-8
UISelectItems properties, 12-8
UISelectMany properties, 12-7
UISelectOne properties, 12-7
writing, 12-3
managed beans, 7-2
composite components, 14-2
configuring in JavaServer Faces technology, 16-1
conversion model, 7-8
custom component alternative, 15-3
defined for CDI, 23-4
developing, 8-4
event and listener model, 7-9
JavaServer Faces technology, 12-1
loading JavaScript, 13-10
method binding, 10-9
properties. See managed bean properties
See also value binding
Managed Beans specification, 1-17, 23-1
ManagedExecutorService interface, 56-2
ManagedScheduledExecutorService interface,
ManagedThreadFactory interface, 56-2
MapMessage interface, 45-17
mapping URLs, 29-14
matrix parameters, JAX-RS, 29-13
Maven tool, 2-3
message acknowledgment, 45-20
bean-managed transactions, 45-33
example, 46-14
message bodies, 45-17
message consumers, 45-10
shared, 45-15
message consumption, 45-6
asynchronous, 45-6, 46-9
synchronous, 45-6, 46-7
message headers, 45-16
message IDs, JMS, 45-16
Message interface, 45-17
message listeners, 32-4, 45-11
examples, 46-9, 46-38
message producers, 45-10
message properties, 45-17
message security, 48-2
message selectors, 45-12
message subscriptions
durable, 45-13
MessageBodyReader interface, 29-8
MessageBodyWriter interface, 29-8
message-driven beans, 1-15, 32-4
accessing, 32-4
coding, 46-30, 46-34, 46-38
defined, 32-4
examples, 46-29, 46-32, 46-36
garbage collection, 32-13
introduction, 45-29
onMessage method, 32-5, 46-30
requirements, 46-30
transactions, 32-5, 51-2, 51-7
MessageListener interface, 45-11
messages
integrity, 50-5
MessageFormat pattern, 10-11, 10-28
outputFormat tag, 10-11
param tag, 10-11, 10-28
parameter substitution tags, 10-28
queueing messages, 12-13, 16-21
securing, 47-7
using the FacesMessage class to create a
message, 16-22
messages, JMS
body formats, 45-17
browsing, 45-18
definition, 45-4
delivery delay, 45-23
delivery modes, 45-21
expiration, 45-22
headers, 45-16
introduction, 45-16
56-2
persistence, 45-21
priority levels, 45-22
properties, 45-17
messaging domains, 45-4
point-to-point, 45-5
publish/subscribe, 45-5
messaging, definition, 45-1
metadata annotations
resource adapters, 52-4
security, 47-8
Metamodel API, 40-1
using, 38-15, 40-2
method binding
method expressions, 15-14
method-binding expressions, 7-11, 16-27
method expressions, 7-9, 11-10
method permissions, 49-3
annotations, 49-3
methods, static, 21-5
mutual authentication, 50-5, 50-7
N
naming contexts, 1-21
naming environments, 1-21
navigation
configuring, 7-10, 16-25
implicit, 7-10
navigation model, 7-10
action attribute, 10-12, 11-10, 11-11, 15-7
action methods, 12-11, 16-25
ActionEvent class, 11-11
configuring navigation rules, 16-25
logical outcome, 12-11, 16-25
NavigationHandler class, 7-12
referencing methods that perform
navigation, 11-11, 12-11
writing a managed bean method to perform
navigation processing, 12-11
NetBeans IDE, 2-2
NON_PERSISTENT delivery mode, 45-22
non-repudiation, 47-5
O
ObjectMessage interface, 45-17
objects, administered, 45-7
creating and removing, 46-3
observer methods, CDI, 25-7
onMessage method
introduction, 45-11
message-driven beans, 32-5, 45-30, 46-30
P
package-appclient tool, 1-23
packaging applications, 5-1
path parameters, JAX-RS, 29-13, 31-2
path templates, JAX-RS, 29-5
permissions, security policy, 47-10
Persistence
Index-13
schema creation, 58-2
persistence
BLOBs, 38-8
cascade operations, 38-8
CLOBs, 38-8
collections, 37-3
concurrent access to entity data, 42-1
configuration, 37-17
context, 37-14
creating database tables, 37-20
criteria queries, 43-1, 43-4
DDL scripts, 37-20
dropping database tables, 37-20
eager fetching, 43-1
embeddable classes, 37-10
entities, 37-1
entity graph properties, 43-4
examples, 38-1
fetch graphs, 43-2
JMS example, 46-36
JMS messages, 45-21
JPQL, 43-1
lazy fetching, 43-1
load graphs, 43-2
loading data, 37-21
locking strategies, 42-1
many-to-many, 38-13
maps, 37-4
named entity graphs, 43-3
one-to-many, 38-3
one-to-one, 38-3
overview, 37-1
persistence units, 37-17
persistent fields, 37-2
primary keys, 37-6, 38-4, 38-5
properties, 37-3
queries, 37-1, 37-18, 38-10, 39-2, 43-1
creating, 40-4
Criteria, 40-1
dynamic, 39-2
executing, 40-9
expressions, 40-6, 40-7
joins, 40-5
parameters, 39-2, 39-3
path navigation, 40-6
results, 40-6, 40-8
static, 39-2
typesafe, 40-1
See also query language
query hints, 43-4
query language, 37-9
relationships, 38-2
schema creation, 37-19
scope, 37-17
second-level cache, 44-1
self-referential relationships, 38-2
string-based criteria queries, 41-1
temporal types, 38-9
persistence units, query language, 39-1, 39-14
PERSISTENT delivery mode, 45-22
Index-14
pluggable audit modules, 47-10
pluggable authorization providers, 47-9
point-to-point messaging domain, 45-5
point-to-point messaging style
See also queues
POJOs, 1-2
policy files, 47-6
primary keys, 38-3
compound, 38-5
defined, 37-6
examples, 37-7
generated, 38-4
principal, 47-12
PrintWriter class, 17-6
priority levels, for messages, 45-22
JMSPriority message header field, 45-16
producer fields
CDI, 25-4
example, 26-8
producer methods
CDI, 23-10, 25-4
example, 26-5
programmatic security, 47-2, 47-9, 48-2, 49-2
example, 49-13
programming model, JMS, 45-6
providers, JMS, 45-4
proxies, 28-1
public key certificates, 50-5
public-key cryptography, 50-2
publish/subscribe messaging domain
durable subscriptions, 45-13
introduction, 45-5
publish/subscribe messaging style
See also topics
Q
qualifiers, using in CDI, 23-5
Quality of Service, 47-5
queries
criteria, 43-1
JPQL, 43-1
persistence, 43-1
query language
ABS function, 39-23
abstract schemas, 39-1, 39-3, 39-15
ALL expression, 39-21
ANY expression, 39-21
arithmetic functions, 39-22
ASC keyword, 39-27
AVG function, 39-25
BETWEEN expression, 39-7, 39-19
Boolean literals, 39-18
Boolean logic, 39-24
case expressions, 39-23
collection member expressions, 39-15, 39-21
collections, 39-15, 39-20, 39-21
compared to SQL, 39-5, 39-14, 39-16
comparison operators, 39-7, 39-19
CONCAT function, 39-22
conditional expressions, 39-6, 39-17, 39-18, 39-24
constructors, 39-26
COUNT function, 39-25
DELETE expression, 39-8
DELETE statement, 39-4
DESC keyword, 39-27
DISTINCT keyword, 39-4
domain of query, 39-1, 39-12, 39-14
duplicate values, 39-4
enum literals, 39-18
equality, 39-24
ESCAPE clause, 39-20
examples, 38-10, 39-4
EXISTS expression, 39-21
FETCH JOIN operator, 39-16
FROM clause, 39-3, 39-12
grammar, 39-8
GROUP BY clause, 39-3, 39-27
HAVING clause, 39-4, 39-27
identification variables, 39-3, 39-12, 39-14
identifiers, 39-12
IN operator, 39-16, 39-19
INNER JOIN operator, 39-16
input parameters, 39-6, 39-18
IS EMPTY expression, 39-7
IS FALSE operator, 39-24
IS NULL expression, 39-7
IS TRUE operator, 39-24
JOIN statement, 39-5, 39-15
LEFT JOIN operator, 39-16
LEFT OUTER JOIN operator, 39-16
LENGTH function, 39-22
LIKE expression, 39-6, 39-20
literals, 39-17
LOCATE function, 39-22
LOWER function, 39-22
MAX function, 39-25
MEMBER expression, 39-21
MIN function, 39-25
MOD function, 39-23
multiple declarations, 39-14
multiple relationships, 39-6
named parameters, 39-5, 39-18
navigation, 39-5, 39-6, 39-15, 39-17
negation, 39-24
NOT operator, 39-24
null values, 39-20, 39-24
numeric comparisons, 39-24
numeric literals, 39-18
operator precedence, 39-18
operators, 39-18
ORDER BY clause, 39-4, 39-27
parameters, 39-4
parentheses, 39-18
path expressions, 39-2, 39-16
positional parameters, 39-18
range variables, 39-15
relationship fields, 39-2
relationships, 39-1, 39-5, 39-6
return types, 39-25
root, 39-15
scope, 39-1
SELECT clause, 39-3, 39-25
setNamedParameter method, 39-5
SIZE function, 39-23
SQRT function, 39-23
state fields, 39-2
string comparison, 39-24
string functions, 39-22
string literals, 39-18
subqueries, 39-21
SUBSTRING function, 39-22
SUM function, 39-26
syntax, 39-3, 39-8
TRIM function, 39-22
types, 39-17, 39-24
UPDATE expression, 39-4, 39-8
UPPER function, 39-22
WHERE clause, 39-3, 39-17
wildcards, 39-20
query parameters, JAX-RS, 29-11, 31-2
query roots, 40-5
Queue interface, 45-8
QueueBrowser interface, 45-18
JMS client example, 46-11
queues, 45-8
browsing, 45-18, 46-11
creating, 45-8, 46-42
injecting resources, 46-30
temporary, 45-23, 46-38
R
RAR files, packaging, 5-5
realms, 47-10, 47-11
admin-realm, 47-11
certificate, 47-11, 50-4
configuring, 47-9
file, 47-11
receiveBody method, 45-18
recover method, 45-21
redelivery of messages, 45-20, 45-21
JMSRedelivered message header field, 45-17
referencing managed bean methods, 11-10
for handling action events, 11-11, 12-12
for handling value-change events, 11-12
for performing navigation, 11-11, 12-11
for performing validation, 11-11, 12-12
registering custom converters, 16-25
converter element, 16-25
registering custom renderers, 16-27
renderer element, 16-27
render-kit element, 16-27
registering custom UI components, 15-9, 16-29
component element, 16-29
registering custom validators, 16-24
validator element, 16-24
registering messages, 16-21
resource-bundle element, 16-21
relationship fields, query language, 39-2
Index-15
relationships
direction, 37-8
unidirectional, 38-4
reliability, JMS
basic mechanisms, 45-21
durable subscriptions, 45-13
local transactions, 45-24
message acknowledgment, 45-20
message delivery delay, 45-23
message expiration, 45-22
message persistence, 45-21
message priority levels, 45-22
temporary destinations, 45-23
relocatable resources, 8-13
remote interfaces, 32-9
Remote Method Invocation (RMI), and
messaging, 45-1
request headers, JAX-RS, 31-1
request method designators, JAX-RS, 29-2, 29-7
Request objects, JAX-RS, 31-10
request parameters, JAX-RS, 29-11
RequestDispatcher interface, 17-10
request/reply mechanism
JMSCorrelationID message header field, 45-16
JMSReplyTo message header field, 45-16
temporary destinations and, 45-23
requests, 17-5
customizing, 17-8
getting information from, 17-5
retrieving a locale, 20-2
See also HTTP requests
Required transaction attribute, 45-33
resource adapters, 1-18, 52-1
example, 53-1
metadata annotations, 52-4
packaging, 5-5
security, 50-15
resource bundles, 20-1
Bean Validation, 22-2
resource classes, JAX-RS, 29-2
resource library contracts, 8-14
example, 8-15
resource methods, JAX-RS, 29-2
resources, 52-1
JMS, 45-29
relocatable, 8-13
See also data sources
ResponseBuilder class, 29-8
responses, 17-6
buffering output, 17-6
customizing, 17-8
setting headers, 17-5
See also HTTP responses
RESTful web services, 1-17, 29-1
defined, 29-1
roles, 47-12
application, 47-14
declaring, 48-9
mapping to groups, 47-14
mapping to users, 47-14
Index-16
referencing, 49-3
security, 47-13, 48-9, 49-3
rollback method, 51-6, 51-7, 51-8
rollback method (JMS), 45-24
rollbacks. See transactions, rollbacks
root resource classes, 29-2
run-as identity, 49-8
S
SAAJ, 1-22
SASL, 47-6
schemagen tool, 1-23
schemas
creating, 37-19
deployment descriptors, 47-8
scopes
CDI, 23-7
introduction, 6-6
JavaServer Faces technology, 16-2
servlets, 17-4
secure connections, 47-15
Secure Sockets Layer (SSL), 47-15
security
annotations, 47-8, 48-16, 49-1
application, 47-4, 47-6
application clients, 50-13
callback handlers, 50-13
component-managed sign-on, 50-15
concurrency and, 56-3
constraints, 48-2
container trust, 49-9
container-managed sign-on, 50-14
containers, 47-1, 47-8
context for enterprise beans, 49-6
declarative, 47-1, 47-8, 48-1, 49-1
deploying enterprise beans, 49-9
EIS applications, 50-14
end-to-end, 47-7
enterprise applications, 49-1
enterprise beans, 49-1
examples, 48-18, 49-9, 49-13
groups, 47-12
introduction, 47-1
JAAS login modules, 50-14
Java SE, 47-5
login forms, 50-13
login modules, 50-13
mechanism features, 47-4
mechanisms, 47-5, 47-6
message, 48-2
message-layer, 47-7
method permissions, 49-3
overview, 47-1
policy domain, 47-12
programmatic, 47-2, 47-9, 48-2, 48-10, 49-2
programmatic login, 50-14
propagating identity, 49-8
realms, 47-11
resource adapters, 50-15
role names, 48-9, 49-3
roles, 47-12, 47-13, 48-9, 49-3
run-as identity, 49-8
simple walkthrough, 47-2
transport-layer, 47-7, 47-15
users, 47-11
web applications, 48-1
web components, 48-1
security constraints, 48-2
multiple, 48-5
security domain, 47-12
security identity
propagating, 49-8
specific identity, 49-8
security role references, 48-13
security roles, 47-13, 49-3
security-role-mapping element, 47-14
security-role-ref element, 48-13
send method, 45-10
sending messages
Java EE components, 45-28
JMS client example, 46-5
sending messages asynchronously, 45-25
server authentication, 50-5
server certificates, 50-1
server log, 2-7
service methods, servlets, 17-5
Servlet interface, 17-1
ServletContext interface, 17-11
ServletInputStream class, 17-6
ServletOutputStream class, 17-6
ServletRequest interface, 17-5
ServletResponse interface, 17-6
servlets, 1-6, 17-1
asynchronous processing, 17-16
binary data, 17-6
character data, 17-6
compiling, 33-3
creating, 17-4
examples, 6-8, 17-23, 33-2
finalizing, 17-13
initializing, 17-5
lifecycle, 17-2
lifecycle events, 17-2
nonblocking I/O, 17-19
packaging, 33-3
scope objects, 17-4
service methods, 17-5, 17-14, 17-15
specifying initialization parameters, 17-5
tracking service requests, 17-14
uploading files with, 17-15, 19-1
session beans, 1-15, 32-2
activation, 32-12
bean-managed concurrency, 34-8, 34-10
business interfaces, 32-5
clients, 32-2
concurrent access, 34-8
container-managed concurrency, 34-8
databases, 51-6
eager initialization, 34-7
examples, 33-1, 34-1, 34-7, 34-13, 46-32
handling errors, 34-11
no-interface views, 32-5
passivation, 32-12
requirements, 34-2
singleton, 32-3, 34-7
stateful, 32-2, 32-3
stateless, 32-3, 32-4
transactions, 51-2, 51-6, 51-7
web services, 32-10, 34-14
See also asynchronous method invocation
Session interface, 45-9
sessions, 17-12
associating attributes, 17-12
associating with user, 17-13
invalidating, 17-12
notifying objects associated with, 17-12
sessions, JMS, 45-9
managing in enterprise bean applications, 45-29
SessionSynchronization interface, 51-6
setRollbackOnly method, 45-33, 51-6, 51-8
shared durable subscriptions, 45-15
shared message consumers, 45-15
sign-on
component-managed, 50-14, 50-15
container-managed, 50-14
Simple Authentication and Security Layer
(SASL), 47-6
SingleThreadModel interface, 17-4
SOAP, 27-1, 28-1, 28-10
SOAP messages, 1-11, 1-22
securing, 47-7
SOAP with Attachments API for Java (SAAJ), 1-22
specialization, CDI, 25-3
SQL, 1-20, 39-5, 39-14, 39-16
loading data, 37-21
SQL92, 39-24
SSL, 47-7, 47-15, 48-4, 50-5
connectors, GlassFish Server, 47-16
handshake, 47-16
verifying support, 47-17
standard converters, 7-8
converter tags, 11-3
NumberConverter class, 11-2
using, 11-1
standard validators, 7-10
using, 11-8
state fields, query language, 39-2
stereotypes, CDI, 25-12
StreamMessage interface, 45-17
string-based criteria queries, 41-1
subresources, JAX-RS, 31-6
subscription names, for durable subscribers, 45-13
substitution parameters, defining. See messages,
param tag
synchronous message consumption, 45-6
Java EE components, 45-28
JMS client example, 46-7
Index-17
T
templating
Facelets, 8-8
temporary JMS destinations, 45-23
examples, 46-38
testing
enterprise beans, 35-4
unit, 35-4
TextMessage interface, 45-17
timer service, 34-16
automatic timers, 34-16, 34-20
calendar-based timer expressions, 34-16
cancelling timers, 34-20
creating timers, 34-19
examples, 34-21
exceptions, 34-21
getInfo method, 34-21
getNextTimeout method, 34-21
getTimeRemaining method, 34-21
getting information, 34-21
programmatic timers, 34-16, 34-18
saving timers, 34-20
transactions, 34-21
timestamps for JMS messages, 45-16
Topic interface, 45-8
topics, 45-8
creating, 45-8, 46-42
durable subscriptions, 45-13
temporary, 45-23
transactions, 51-1
application-managed, 37-15
attributes, 51-3, 51-5
bean-managed, 45-32, 51-7, 51-8
boundaries, 51-2, 51-6, 51-7
business methods. See business methods,
transactions
commits, 51-2, 51-6
concurrency and, 56-3
container-managed, 45-32, 51-2
container-managed transaction demarcation, 51-2
defined, 51-2
distributed, 45-32
examples, 46-18
exceptions. See exceptions, transactions
JDBC, 51-8
JMS and enterprise bean applications, 45-29
JTA, 51-7
local, 45-24
managers, 51-4, 51-7, 51-8
message-driven beans. See message-driven beans,
transactions
nested, 51-2, 51-7
Required attribute, 45-33
rollbacks, 51-2, 51-6, 51-7
scope, 51-3
session beans. See session beans, transactions
timeouts, 51-8
timer service, 34-21
web components, 51-9
transport guarantees, 48-4
Index-18
transport-guarantee element, 48-4
transport-layer security, 47-7, 47-15
truststores, 50-1, 50-2
managing, 50-2
U
UI component behavioral interfaces, 7-6
ActionSource interface, 7-6, 7-9, 15-10, 15-18
ActionSource2 interface, 7-6, 15-10
ClientBehaviorHolder interface, 7-7
ConvertibleValueHolder interface, 7-6
EditableValueHolder interface, 7-6, 15-10
NamingContainer interface, 7-6, 15-10
StateHolder interface, 7-6, 15-10, 15-16
SystemEventListenerHolder interface, 7-7
ValueHolder interface, 7-7, 15-10
UI component classes, 7-5, 7-7, 15-2
javax.faces.component package, 15-10
UIColumn class, 7-6
UICommand class, 7-6, 7-7
UIComponent class, 7-5, 7-7
UIComponentBase class, 7-5, 15-10, 15-12
UIData class, 7-6, 12-5
UIForm class, 7-6
UIGraphic class, 7-6
UIInput and UIOutput classes, 12-5
UIInput class, 7-6, 7-9
UIMessage class, 7-6
UIMessages class, 7-6
UIOutcomeTarget class, 7-6
UIOutput class, 7-6, 7-8
UIPanel class, 7-6
UIParameter class, 7-6
UISelectBoolean class, 7-6, 12-6
UISelectItem class, 7-6, 12-8
UISelectItems class, 7-6, 12-8
UISelectMany class, 7-6, 12-7
UISelectOne class, 7-6, 7-7, 12-7
UIViewRoot class, 7-6
See also custom UI components
UnavailableException class, 17-5
undeploying modules and applications, 6-8
Unicode character set, 20-4
unified expression language. See EL
Uniform Resource Identifiers (URIs), 29-1
URI path parameters, JAX-RS, 29-13
URI path templates, JAX-RS, 29-4, 29-5
URL paths, 6-9
URLs, mapping, 29-14
US-ASCII character set, 20-4
user data constraints, 48-3, 48-4
user-data-constraint element, 48-4
users, 47-11
adding to GlassFish Server, 47-13
managing, 47-12
UserTransaction interface, 37-15, 51-6, 51-7, 51-8,
51-9
message-driven beans, 45-32
using pages, 8-12
UTF-8 character encoding, 20-5
utility classes, 32-11
V
validating input. See Bean Validation, validation
model
validation, 21-1
customizing, 22-1
entities, 37-4
groups, 22-3
localization, 22-3
messages, 22-2
ordering, 22-3
validation model, 7-5, 7-9
referencing a method that performs
validation, 11-11
validator attribute, 10-9, 11-10, 11-11, 12-12
Validator implementation, 7-10, 15-30
Validator interface, 7-10, 12-11, 12-12
custom validator tags, 15-29
implementing, 15-28
writing a managed bean method to perform
validation, 12-12
See also validators
Validator implementation classes, 7-10, 11-8
BeanValidator class, 11-8
DoubleRangeValidator class, 10-28, 11-8
LengthValidator class, 10-28, 11-8
LongRangeValidator class, 10-28, 11-8, 11-9
RegexValidator class, 11-8, 11-10
RequiredValidator class, 11-8
validator tags
composite components, 14-2
validateBean tag, 11-8
validateDoubleRange tag, 11-8
validateLength tag, 11-8
validateLongRange tag, 11-8, 11-9
validateRegex tag, 11-8, 11-10
validateRequired tag, 11-8
validator tag, 7-10, 15-30
validators, 7-5, 7-15
custom validators, 10-28, 15-30
default, 16-24
registering, 11-9
standard, 11-8
value binding
acceptable types of component values, 12-4
component instances to bean properties. See
component binding
component values and instances to managed bean
properties, 15-31
component values to implicit objects, 15-33
component values to managed bean
properties, 15-32
properties, 12-4
value attribute, 12-4, 15-7, 15-31, 15-32
value expressions, 12-6, 15-14, 15-34
value-binding expressions, 15-32
value expressions, 12-3
ValueExpression class, 12-3
value-change events, 7-9, 15-19
processValueChange(ValueChangeEvent)
method, 15-19
processValueChangeEvent method, 12-13
referencing methods that handle value-change
events, 11-12
type attribute, 11-6
ValueChangeEvent class, 11-6, 15-19
valueChangeListener attribute, 10-9, 11-10, 12-13
ValueChangeListener class, 11-6, 12-13, 15-19
ValueChangeListener implementation, 15-19
valueChangeListener tag, 10-27, 11-6, 15-3
writing a managed bean method to handle
value-change events, 12-13
Variant class, JAX-RS, 31-10
W
W3C, 1-21, 28-1, 28-10
WAR files, 5-1
web applications, 5-4, 6-1
configuring, 6-2
deployment descriptors, 6-2
document roots, 5-4
establishing the locale, 20-2
internationalizing and localizing, 20-1
JMS example, 46-26
maintaining state across requests, 17-12
parsing and formatting localized dates and
numbers, 20-4
presentation-oriented, 6-1
providing localized messages, 20-2
retrieving localized messages, 20-3
securing, 48-1
service-oriented, 6-1
setting the resource bundle, 20-3
specifying context parameters, 6-12
specifying welcome files, 6-12
web clients, 1-5, 6-1
examples, 33-2
web components, 1-6, 6-1
applets bundled with, 1-6
concurrent access to shared resources, 17-4
forwarding to other web components, 17-11
including other web resources, 17-11
invoking other web resources, 17-10
mapping exceptions to error screens, 6-13
mapping filters to, 17-9
scope objects, 17-4
securing, 48-1
sharing information, 17-3
transactions, 51-9
types, 1-6
utility classes bundled with, 1-6
web context, 17-11
web container, 1-10, 6-2
loading and initializing servlets, 17-2
mapping URLs to web components, 6-9
web modules, 5-2, 5-4
Index-19
packaging and deploying, 6-6
undeploying, 6-8
viewing deployed, 6-7
web pages, XHTML, 8-2
web resource collections, 48-3
web resources, 5-4
Facelets, 8-12
mapping filters to, 17-9
unprotected, 48-3
web services, 1-10
declaring references to, 6-15
endpoint implementation classes, 34-14
examples, 28-2, 34-13
introduction, 27-1
JAX-RS compared to JAX-WS, 27-1
See also enterprise beans
web-resource-collection element, 48-3
WebSocket. See Java API for WebSocket
web.xml file, 5-4, 16-30, 47-9, 49-3
welcome files, 6-12
work flows, 32-4
writing managed bean methods, 12-10
for handling action events, 12-12
for handling value-change events, 12-13
for performing navigation, 12-11
for performing validation, 12-12
writing managed bean properties
converters, 12-10
listeners, 12-10
validators, 12-10
WSDL, 1-11, 27-1, 28-1, 28-10
wsgen tool, 1-23
wsimport tool, 1-23
X
xjc tool, 1-23
XML, 1-11, 28-1
XML schema
mappings of Java classes to XML data types,
mappings to Java data types, 28-9
Index-20
28-9