Enterprise Java Development@TOPIC@

Enterprise Java (JavaEE) Course Notes

Revision: v2015-09-09

Built on: 2015-11-18 03:26 EST

Abstract

This book contains course notes covering Enterprise Computing with Java. This course covers enterprise computing technologies using Java Enterprise Edition (Java EE). The course describes how to build multitier distributed applications, specifically addressing web access, business logic, data access, and applications supporting enterprise service technologies. For the web access tier, the focus will be on integrating the web tier with enterprise applications. For the business logic tier, session beans for synchronous business processing and message-driven beans and timers for asynchronous business processing will be described. The data access tier discussion will focus on data access patterns and the Java Persistence API. Finally, enterprise services will be discussed, including the Bean Validation API, Java Naming and Directory Interface (JNDI), Dependency Injection for Java (JSR-330), Context and Dependency Injection for JavaEE (CDI; JSR-299), remote method invocation (RMI), Java API for XML Binding (JAXB), and Java API for RESTful Wed Services (JAX-RS), Java Transaction API (JTA), Java EE security, and Java Message Service (JMS). Students will build applications using the technologies presented.

The material currently covers standards adopted as of JavaEE 6 and is being actively updated with information from JavaEE 7.


I. Enterprise Computing with Java (605.784.31) Course Syllabus
1. Course Description
1.1. Meeting Times/Location
1.2. Description
1.3. Student Background
1.4. Student Commitment
1.5. Course Text(s)
1.5.1. Recommended Text(s)
1.5.2. Optional Text(s)
1.6. Required Software
1.7. References
1.8. Grading
1.9. Grading Policy
1.10. Academic Integrity
1.11. Instructor Availability
2. Syllabus
3. Course Projects
3.1. Project 0: Sanity Check
3.2. Project 1: Data Access Tier and Business Logic
3.3. Project 2: N-Tier Application
3.4. Project 3: Secure and Asynchronous Application
3.5. General Requirements
3.6. Submission Guidelines
II. Java Enterprise Edition (JavaEE) Intro
Purpose
1. Goals
2. Objectives
4. Java Technology Levels
4.1. Java Standard Edition(tm) (JavaSE or JSE)
4.2. Java Micro Edition(tm) (JavaME)
4.3. Java Enterprise Edition(tm) (JavaEE or JEE)
5. Why Enterprise?
6. JavaEE Architecture
6.1. Profiles
6.1.1. Web Profile
6.2. Application Components
6.2.1. Application Clients
6.2.2. Applets
6.2.3. Servlets/JSPs/JSF
6.2.4. Enterprise JavaBeans(tm) (EJB)
6.3. Containers
6.3.1. Servers
6.4. Resource Adapters
6.5. Databases
7. JavaEE Specifications
8. JavaEE Version Highlights
9. Summary
A. Sources
III. Development Environment Overview
Purpose
1. Goals
2. Objectives
10. Maven Basics
10.1. Directory Structure
10.1.1. Source Tree
10.1.2. Build Tree
10.2. Maven POM
10.2.1. Packaging
10.2.2. Project Identity
10.2.3. Maven Repositories
10.2.4. Properties
10.2.5. Dependencies
10.2.6. Build Definition
10.3. Maven Commands
11. Maven Profiles
11.1. Profile Definition
11.2. Activation
11.2.1. Explicit Activation/Deactivation
11.2.2. Activation/Deactivation By Rule
12. Maven Modules
12.1. POM Inheritance
12.2. Submodules
13. Dependency/Plugin Management
13.1. Dependency Management
13.2. Plugin Management
14. Maven Eclipse Integration
14.1. Project Import
14.2. Project Update
14.3. Project Refresh
15. Eclipse
15.1. Project Organization
15.2. Project Testing
15.2.1. Maven test from Eclipse
15.2.2. Raw JUnit within Eclipse
15.3. Program Debugging
15.3.1. Debugging within Eclipse
15.3.2. Debugging Maven test from Eclipse
IV. EMarket Semester Projects
V. Business Logic
Purpose
1. Goals
2. Objectives
30. Session Facade Pattern
30.1. Context
30.2. Problem
30.3. Forces
30.4. Solution
30.5. Consequences
31. Using Business Logic for Requirements
31.1. Business Interfaces Capture Functional Requirements
31.2. Business Objects Capture Data Requirements
31.3. Test Cases as Executable Requirements
31.4. Sample Project Layout
VI. Data Access Objects (DAOs)
Purpose
1. Goals
2. Objectives
32. Data Access Object (DAO) Pattern
32.1. Context
32.2. Problem
32.3. Forces
32.4. Solution
32.5. DAO Implementation Structure
32.6. Consequences
33. DAO Interface
33.1. DAO Interface
33.2. DAO Exceptions
33.3. DAO Implementation
33.4. DAO Test
34. Data Transfer Object (DTO) Pattern
34.1. Context
34.2. Problem
34.3. Forces
34.4. Solution
34.5. Consequences
35. RDBMS Schema
35.1. RDBMS
35.1.1. Background
35.1.2. Tables/Columns
35.1.3. Constraints
35.1.4. Relationships
35.1.5. Indexes
35.2. Data Definition Language (DDL)
35.2.1. Create Table
35.2.2. Drop Table
35.2.3. Create Foreign Key Constraint
35.2.4. Drop Foreign Key Constraint
35.2.5. Create Index
35.2.6. Drop Index
35.3. DDL Files in Maven Module
36. SQL Basics
36.1. Create/INSERT
36.2. Read/SELECT
36.3. Update/UPDATE
36.4. Delete/DELETE
37. Working with Native SQL
37.1. Java Database Connectivity (JDBC)
37.2. Java Persistence API (JPA) Native SQL
VII. Java Persistence API
Purpose
1. Goals
2. Objectives
38. JPA Overview
38.1. Background
38.2. EntityManager
38.3. Entity
38.4. JPA Example
38.5. Entity States
38.5.1. Managed
38.5.2. Detached
38.6. Persistence Context
38.7. Persistence Unit
38.8. Example Layout
38.9. Persistence.xml
38.9.1. Application Example
38.9.2. Server Example
38.9.3. Optional hibernate.properties
38.9.4. Sample orm.xml
38.9.5. persistence.xml Elements
38.9.6. Entity Discovery
38.10. Basic Steps
38.11. Entity Manager Methods
38.11.1. Basic CRUD Operations
38.11.2. Membership Operations
38.11.3. State Synchronization Operations
38.11.4. Locking Operations
38.11.5. Query Operations
38.11.6. Other Operations
39. Entity Manager CRUD Methods
39.1. persist()
39.2. find()
39.3. getReference()
39.4. merge()
39.5. remove()
40. Entity Manager Membership Methods
40.1. contains()
40.2. clear()
40.3. detach()
41. Entity Manager State Synchronization Methods
41.1. flush()
41.2. FlushMode
41.3. refresh()
42. Entity Manager Locking Methods
42.1. Primary Lock Types
42.2. LockModeType
42.3. lock()
42.4. find(lock)
42.5. refresh(lock)
42.6. getLockMode()
43. Entity Manager Query Methods
43.1. JPA Queries
43.2. Native Queries
43.3. Criteria Queries
44. Other Entity Manager Methods
44.1. isOpen()
44.2. close()
44.3. getTransaction()
44.4. joinTransaction()
44.5. unwrap()
44.6. getDelegate()
44.7. getMetaModel()
44.8. getEntityManagerFactory()
44.9. setProperties()/getProperties()
45. JPA Maven Environment
45.1. JPA Maven Dependencies
45.1.1. JPA API classes
45.1.2. JPA Provider classes
45.1.3. Database
45.2. Supplying Runtime Properties
45.2.1. Turn on Resource Filtering in pom.xml
45.2.2. Use ${variable} References in Resource Files
45.2.3. Define Property Values in Parent pom.xml
45.2.4. Run with Filtered Values
VIII. Java Persistence API: Entities
Purpose
1. Goals
2. Objectives
46. Identifying Entity Classes
46.1. Entities
46.2. Entity Name
46.3. Field/Property Access
46.3.1. Access Types
46.3.2. Defining Access using @Annotations
46.3.3. Defining Access using orm.xml
46.4. Approaches
46.4.1. Java First
46.4.2. Schema First
47. Mapping Entity Classes
47.1. Core Mappings
47.2. More Detailed Property Mappings
47.3. Entity Mapping Example
47.3.1. Example Schema
47.3.2. Mapping Entity Class with Annotations
47.3.3. Mapping Entity Class with orm.xml
47.4. More on Precision/Scale
47.5. Transient Properties
47.6. Lob Properties
47.7. Temporal and Enumerated Properties
47.7.1. Temporals
47.7.2. Enums
47.7.3. Temporal/Enum Example
48. Primary Keys
48.1. Generated Simple Primary Keys
48.1.1. GenerationType.AUTO
48.1.2. GenerationType.IDENTITY
48.1.3. GenerationType.SEQUENCE
48.1.4. GenerationType.TABLE
49. Composite Primary Keys
49.1. Example Composite Primary Key Class
49.2. Composite @IdClass
49.3. Composite @EmbeddedId
49.4. Composite Overrides
49.5. Composite Primary Key Summary
50. Multi-table Mapping
50.1. Multi-table Example
50.2. Summary
51. Embedded Object
51.1. Embedded Object Example
51.2. Summary
IX. Validation API
Purpose
52. Core Validation API
52.1. Validation Goals
52.2. Constraints
52.2.1. Annotating Class
52.2.2. Validating Instances
52.3. Constraint Groups
52.3.1. Uses
52.3.2. Defining Groups
52.3.3. Groups Applied to Classes
52.3.4. Validating with Groups
52.4. Custom Validators
52.4.1. Annotation
52.4.2. Validator
52.4.3. Annotating Class
52.4.4. Example Usage
52.5. Composite Constraints
52.5.1. Multiple Constraints
52.5.2. Replace With Composite
52.5.3. Composite Annotation
52.5.4. Composed Validations Individually Reported
52.5.5. @ReportAsSingleViolation
52.6. Group Sequences
52.6.1. Validation Groups and Sequence
52.6.2. Assign Constraints from Sequence
52.6.3. Sample Execution
52.6.4. Optionally Assign Sequence to be Default for Class
52.7. Validating Types
52.7.1. Annotation
52.7.2. Validator
52.7.3. Validator
52.8. Cascade Validation
52.8.1. Trigger Validation Cascade with @Valid
52.8.2. Validation
52.9. XML Descriptor
52.9.1. POJO Bean Class
52.9.2. META-INF/validation.xml
52.9.3. Constraint Mapping
52.10. Summary
53. JPA Persistence Lifecycle
53.1. Callbacks
53.2. Listeners
53.3. Summary
54. Validation API/JPA Integration
54.1. Entity Class
54.2. Persistence Unit
54.3. Validation
54.4. Validation with JPA
54.5. Summary
55. Validation API Build/Maven Aspects
55.1. Adding POM Dependencies
55.2. Adding Plugin Dependencies
X. Java Persistence API: Relations
Purpose
1. Goals
2. Objectives
56. One-to-One Relationships
56.1. One-to-One: Uni-directional
56.2. @OneToOne Annotation
56.3. @JoinColumn Annotation
56.4. @JoinColumns Annotation
56.5. One-to-One: Bi-directional
56.6. Bi-directional Relationships and Ownership
56.7. Other Topics
56.8. Summary
57. One-to-Many Relationships
57.1. One-to-Many: Uni-directional
57.2. @OneToMany Annotation
57.3. One-to-Many: Bi-directional
57.4. @ManyToOne Annotation
57.5. One-to-Many: Element Collection
57.6. @ElementCollection Annotation
57.7. Other Topics
57.8. Summary
58. Relationship Capabilities
58.1. Fetching
58.1.1. fetch=LAZY
58.1.2. fetch=EAGER
58.2. Cascades
58.3. Orphan Removal
58.4. Summary
59. Object Collections
59.1. Object Identity
59.1.1. Instance Id
59.1.2. Primary Key Id
59.1.3. Switching Ids
59.1.4. Business Id
59.2. Collection Types
59.3. Summary
60. Foreign Keys
60.1. Primary Key Join
60.1.1. @PrimaryKeyJoinAnnotation
60.2. Using Composite Primary Key Property as Foreign Key
60.2.1. Using @IdClass Composite Primary Key Property as Foreign Key
60.2.2. Using @EmbeddedId Composite Primary Key Property as Foreign Key
60.3. Using Foreign Key in Composite Primary Key
60.3.1. Using Foreign Key in @IdClass Composite Primary Key
60.3.2. Using Foreign Key in @EmbeddedId Composite Primary Key (@MapsId)
60.4. Join Tables
60.4.1. @JoinTable Annotation
60.5. Summary
61. Many-to-One Relationships
61.1. Many-to-One: Uni-directional
61.2. Summary
62. Many-to-Many Relationships
62.1. Many-to-Many: Uni-directional
62.2. Many-to-Many: Bi-directional
62.3. Summary
XI. Java Persistence API: Inheritance
Purpose
1. Goals
2. Objectives
63. Inheritance Strategy: Single Table
63.1. Single Table Strategy Overview
63.2. Single Table Example Database Schema
63.3. Single Table Example Java Mapping
63.4. Single Table Example Usage
63.5. @DiscriminatorColumn Annotation
63.6. Summary
64. Inheritance Strategy:Table per Concrete Class
64.1. Table per Concrete Class Strategy Overview
64.2. Table per Concrete Class Example Database Schema
64.3. Table per Concrete Class Example Java Mapping
64.4. Table per Concrete Class Example Usage
64.5. Summary
65. Inheritance Strategy:Join
65.1. Join Strategy Overview
65.2. Join Example Database Schema
65.3. Join Example Java Mapping
65.4. Join Example Usage (Persist)
65.5. Summary
66. Inheritance Strategy:Non-Entity
66.1. Non-Entity Strategy Overview
66.2. Non-Entity Example Database Schema
66.3. Non-Entity Example Java Mapping
66.4. Non-Entity Example Usage (Persist)
66.5. Summary
67. Mixed Inheritance Strategies
67.1. Which Strategy Gets Used for Subclass?
67.2. Generated Database Schema
67.3. Summary
XII. JPA Queries
Purpose
1. Goals
2. Objectives
XIII. JPA Tuning
Topics
76. SQL Tuning
76.1. Reasons for Inefficient SQL Performance
76.2. Execution Plan
76.3. Diagnostic Tools
76.3.1. Client/DAO Result
76.3.2. EXPLAIN PLAN
76.3.3. AUTOTRACE
76.3.4. Display Cursor Execution Plan within V$PLAN
76.4. Summary
77. Example Domain Model: Movies
77.1. Class Model
77.2. Database Schema
77.3. Database Size
77.4. Prepare DB Between Tests
78. Table Access
78.1. Full Table Scan
78.1.1. Full Table Scan: Unconstrained Access
78.1.2. Full Table Scan: Using Where (without Index)
78.1.3. RowId Scan: Using Where (with Index)
78.1.4. Full Table Scan: Invalidating Index using Function applied to Row Column
78.1.5. RowId Scan: Using Index with Function applied to Row Column
78.1.6. Full Table Scan: Invalidating Index by using Leading Wildcards
78.2. Order By
78.2.1. Order By using Sort
78.2.2. Order By using Index
78.2.3. Order By using Index DESC
78.2.4. Order By using Reverse Index DESC
78.3. Summary
79. Indexes
79.1. Index Range Scan
79.2. Unique Index Scan
79.3. Composite Index
79.3.1. Query Parts
79.3.2. First Term Indexed
79.3.3. First and Second Term Indexed (using Composite Index)
79.4. Index Fast Full Scan (with Composite Index)
79.4.1. Query Parts
79.4.2. Option: Use Range Scan and RowId Access
79.4.3. Option: Use Range Scan Alone with Composite Index
79.4.4. Option: Fast Full Scan
79.5. Summary
80. Joins
80.1. Foreign Keys
80.1.1. Query Parts
80.1.2. No Indexes
80.1.3. Perform Query with Support for Foreign Key Index
80.1.4. Foreign Key and Where Columns Indexed
80.1.5. Foreign Key, Where, and Join Columns Indexed
80.2. Join Types
80.2.1. Nested Loop Join
80.2.2. Hash Join
80.2.3. Sort Merge Join
80.3. Summary
81. JPA
81.1. Lazy and Eager Fetching
81.1.1. Get Parent
81.1.2. Get Parent and Children
81.2. Obtaining Instance Counts
81.2.1. Query Parts
81.2.2. Collection Size in DAO from Relation
81.2.3. Row Count in DAO from Query
81.2.4. Row Count in DB using Count() Query
81.2.5. Row Count in DB using Count Query without JOIN
81.3. Query Loops
81.3.1. Query Parts
81.3.2. Query Loops in DAO
81.3.3. Query Loops using DB Subquery
81.4. Paging
81.4.1. Query Parts
81.4.2. Paging within DAO
81.4.3. Paging within DB
81.5. Summary
82. H2 Execution Plans
82.1. Column Index
82.2. Summary
83. JPA/SQL Tuning Summary
83.1. Other Topics
XIV. Enterprise JavaBeans (EJB) Overview
Purpose
1. Goals
2. Objectives
84. Why Enterprise?
84.1. Related Patterns
84.1.1. Pattern: Session Facade
84.2. Pattern: Remote Facade
84.2.1. Context
84.2.2. Problem
84.2.3. Forces
84.2.4. Solution
84.2.5. Consequences
84.3. Pattern: Data Transfer Object (DTO)
84.3.1. Context
84.3.2. Problem
84.3.3. Forces
84.3.4. Solution
84.3.5. Consequences
85. Overview of EJB Styles
85.1. EJB Uses
85.2. EJB Granularity
85.3. EJB Bean Types
85.3.1. Entities (formerly Entity EJB)
85.3.2. Stateless Session EJB
85.3.3. Stateful Session EJB
85.3.4. Singleton Session EJB
85.3.5. Message Driven EJB (MDB)
85.4. EJB Interface Styles
85.4.1. Business Interface
85.4.2. Remote Interface
85.4.3. Local Interface
85.4.4. No Interface EJB
85.4.5. Other Interface Types
85.5. EJB Deployments
85.5.1. EJB Module
85.5.2. Naked EJB Deployment
85.5.3. EJB EAR Deployment
85.5.4. EJB WAR ("flexible") Deployment
85.5.5. EAR Deployment Class Loaders
B. Sources
XV. Basic Session EJB
Purpose
1. Goals
2. Objectives
86. Basic Session EJB POJO Aspects
86.1. POJO Class
86.1.1. Bean Class
86.1.2. Business Method
86.1.3. Interface
86.1.4. Serializable DTO
86.1.5. Business Exceptions
86.2. POJO Unit Test
86.2.1. JUnit Test Case
86.2.2. JUnit Test Method(s)
86.3. POJO Module
86.3.1. Built POJO Archive
86.3.2. Source POJO Module
86.4. Unit Test Execution
86.5. Maven Aspects: POJO
86.6. Summary
87. Basic Session EJB Component
87.1. Making POJO an EJB
87.1.1. Annotate Bean class with @javax.ejb.Stateless
87.1.2. Annotate Interface with @javax.ejb.Remote
87.1.3. Optionally Annotate Empty Interface Extending POJO Business Interface
87.1.4. @PostConstruct/@PreDestory
87.2. EJB Module
87.2.1. Source EJB Module
87.3. Naked EJB-based Deployment
87.4. Maven Aspects: EJB
87.5. JBoss Session EJB Pooling
87.6. Summary
88. EAR Deployment
88.1. EAR Artifact
88.1.1. EAR META-INF/application.xml
88.2. EAR-based EJB Deployment
88.3. Maven Aspects: EAR
88.3.1. EAR Module Build
88.3.2. EAR Module Cleanup
88.3.3. IT Test Module
88.4. Summary
89. WAR Deployment
89.1. WAR Artifact
89.1.1. WEB-INF/jboss-web.xml
89.2. WAR-based EJB Deployment
89.3. Maven Aspects: WAR
89.3.1. WAR Module Build
89.3.2. IT Test Module
89.4. Summary
90. IT Testing
90.1. EJB Access
90.1.1. JNDI
90.1.2. JBoss Remoting
90.1.3. EJB Client
90.1.4. Blending JBoss Remoting and EJB Client
90.2. Integration Test Session EJB
90.2.1. Integration Test (IT) JUnit Class
90.2.2. @Test Methods
90.3. IT Module
90.4. IT Test Execution
90.5. Summary
XVI. EJB Development Scenarios
Purpose
1. Goals
2. Objectives
91. Application Server
91.1. Server Configuration
91.1.1. Logger
91.2. Standalone Server
91.2.1. Standalone Server Start
91.2.2. Standalone Server Stop
91.3. Embedded Server
91.3.1. Embedded Server Setup
91.3.2. Embedded Server Start
91.3.3. Embedded Server Stop
91.4. Summary
92. Build Commands
92.1. Example Source Tree
92.2. Unit Tests
92.2.1. Resources Plugin
92.2.2. Surefire Plugin
92.3. Integration (IT) Tests
92.3.1. Cargo Plugin
92.3.2. Failsafe Plugin
92.4. Summary
93. IT Testing with IDE
93.1. Run IT Tests Against Server
93.2. Debug Code Running on Server
93.3. Summary
XVII. Configuring EJBs using ENC and JNDI
Topics
94. Global JNDI and the Enterprise Naming Context (ENC)
94.1. Java Naming and Directory Interface
94.2. Global JNDI Naming Context
94.2.1. Remote JNDI Naming Context
94.2.2. Local JNDI Naming Context
94.3. Enterprise Naming Context (ENC)
94.4. Summary
95. Populating the EJB's ENC
95.1. ENC/Class Population/Injection Sources
95.2. Populating ENC with Value Resource
95.3. Populating ENC with JDBC Resource
95.4. Populating ENC with JPA Resources
95.5. Populating ENC with JMS Resources
95.6. Populating ENC with EJB Resources
95.7. Summary
XVIII. JPA Server-Side Deployment
Purpose
96. Server-side Resources
96.1. SQL DataSource (defined in Server)
96.2. Server-side persistence.xml
96.2.1. persistence.xml Placement
96.2.2. Reference External @Entities
96.3. Summary
97. Persistence Unit/Context Injection
97.1. @PersistenceContext Injection
97.2. @PersistenceUnit Injection
97.3. Context and Dependency Injection (CDI)
97.4. Summary
98. Managed Entities and Remote Interfaces
98.1. Provider Proxy Classes
98.2. Cleansed DTOs
98.3. Lazy Load Exception
98.4. Load thru "Touching" Object Tree in Remote Facade
98.5. Load thru Fetching Object Tree in Query
98.6. Abstract Remote Interface View with DTO
98.7. Summary
99. Persistence Context Propagation
99.1. Stateless Persistence Context Interaction
99.2. Stateful Facade Persistence Context Interaction
99.3. Transaction Rollbacks
99.3.1. Stateless Transaction Rollback
99.3.2. Stateful Transaction Rollback
99.4. Pessamistic Locking
99.5. Summary
XIX. EJB Transactions and Concurrency
Purpose
1. Goals
2. Objectives
100. Transactions
100.1. Transaction Examples
100.2. Transaction ACID Properties
100.3. EJB Transaction Scenarios
100.3.1. Scenario: Multiple DB Updates
100.3.2. Scenario: Update Multiple Databases
100.3.3. Scenario: Coordinate JMS with Database Transaction
100.4. Transaction Terms
100.5. JTA and JTS Specifications
100.5.1. Java Transaction API (JTA)
100.5.2. Java Transaction API (JTA) and Java Transaction Service (JTS)
100.6. EJB Transactions
100.6.1. Container-Managed Transactions
100.6.2. Bean-Managed Transactions
100.7. Summary
101. Container-Managed Transactions
101.1. Transaction Scope
101.1.1. Transaction Not Supported
101.1.2. Transaction Required
101.1.3. Transaction Supports
101.1.4. Transaction Requires New
101.1.5. Transaction Mandatory
101.1.6. Transaction Never
101.1.7. All Transaction Scopes
101.2. @Asynchronous Methods and Transactions
101.3. EJB Lifecycle Methods
101.4. Callback Methods
101.4.1. Message Driven Callback
101.4.2. Timer Callbacks @Asynchronous
101.5. EJB Control of Container-Managed Transactions
101.5.1. EJBContext
101.6. Exceptions
101.6.1. Checked/Application Exceptions
101.6.2. Checked/Application Exception Rollback
101.7. Persistence Context Propagation
101.8. Summary
102. Bean-Managed Transactions
102.1. UserTransaction
102.2. Message-Driven Callbacks and Bean-Managed Transactions
102.3. Summary
103. Stateful Session Synchronization
103.1. Stateful Session Synchronization Events
103.2. Additional Stateful Rules
103.3. Summary
XX. Web/UI Applications
Purpose
1. Goals
2. Objectives
104. JavaServer Faces
104.1. Controller Bean
104.2. JSF Page
104.3. WAR Structure and Descriptors
104.4. Summary
XXI. Context and Dependency Injection (CDI)
Purpose
1. Goals
2. Objectives
105. Context and Dependency Injection (CDI) JSR-299
105.1. History
105.2. Injection Concept
105.3. CDI Activation
105.4. Summary
106. CDI Injection
106.1. Producer Field
106.2. Producer Method
106.3. Other Producers
106.4. @Any Instance
106.5. Bean Types
106.6. Named Beans
106.7. Summary
XXII. JAX-RS EJB
Purpose
1. Goals
2. Objectives
107. EJB WAR Deployment
107.1. WAR Structure
107.1.1. Deploying External EJB JARs
107.1.2. Deploying Embedded EJBs
107.2. WAR Clients
107.2.1. Accessing HTTP Resources
108. Resources, URI, and Methods
108.1. Resources
108.2. URIs
108.3. Methods
108.4. Response Codes
108.5. JAX-RS Resource Class
108.5.1. JAX-RS Resource POST Method
108.5.2. JAX-RS GET Resource Method
108.5.3. JAX-RS PUT Resource Method
108.5.4. JAX-RS DELETE Resource Method
108.6. HTTP Request/Response
109. XML Representations
109.1. XML Payload
109.2. Defining JAXB DTOs
109.2.1. Defining JAXB Attributes
109.2.2. Defining JAXB Elements
109.2.3. Defining JAXB Collections/Sequences
109.3. JAXB Marshalling/Demarshalling
109.3.1. JAXB Marshalling
109.3.2. JAXB Demarshalling
109.4. Marshaling XML to/from Resource Methods
109.4.1. Marshaling XML Requests to Resource Methods
109.4.2. Marshaling XML Response from Resource Methods
XXIII. JavaEE Security
Purpose
1. Goals
2. Objectives
110. JavaEE Security Access Control Points
111. EJB Security
111.1. EJB Access Control (Declarative)
111.2. Programmatic Security
111.3. Authentication/Authorization JBoss Setup
111.4. Summary
112. EJB Security RMI Client
112.1. JBoss Remoting
112.2. EJBClient
112.3. Security Sanity Check
112.4. Summary
113. run-as
113.1. Summary
114. Web Tier Access Control
114.1. Authentication
114.2. Security Constraints (web.xml)
114.3. FORM-based Login
114.4. BASIC Authentication
114.5. Summary
XXIV. JavaEE Interceptors
Purpose
1. Goals
2. Objectives
115. EJB Interceptors
115.1. Business Method Callbacks
115.2. InvocationContext
115.3. Lifecycle Callbacks
115.4. Timer Callbacks
115.5. Activating Interceptors
115.6. Summary
116. CDI Interceptors
116.1. @InterceptorBinding Annotation
116.2. Interceptor Class
116.3. CDI Bean Class
116.4. CDI Descriptor (beans.xml) Activation
116.5. Summary
117. Interceptor Example: Input Normalization and Validation
117.1. EJB Method Creates Contact
117.2. Non-normalized Caller Data
117.3. Partial Solution: Validation API
117.4. PrePersistCheck
117.5. PostNormalizedCheck
117.6. PreNormalizedCheck
117.7. Validator Interceptors
117.8. Normalization Interceptor
117.9. Bean Class
117.10. CDI Activation (bean.xml)
117.11. Example Output
117.12. Summary

This course covers enterprise computing technologies using Java Enterprise Edition (Java EE). The course describes how to build multitier distributed applications, specifically addressing web access, business logic, data access, and applications supporting enterprise service technologies. For the web access tier, the focus will be on integrating the web tier with enterprise applications. For the business logic tier, session beans for synchronous business processing and message-driven beans and timers for asynchronous business processing will be described. The data access tier discussion will focus on data access patterns and the Java Persistence API. Finally, enterprise services will be discussed, including the Bean Validation API, Java Naming and Directory Interface (JNDI), Dependency Injection for Java (JSR-330), Context and Dependency Injection for JavaEE (CDI; JSR-299), remote method invocation (RMI), Java API for XML Binding (JAXB), and Java API for RESTful Wed Services (JAX-RS), Java Transaction API (JTA), Java EE security, and Java Message Service (JMS). Students will build applications using the technologies presented.

The course is being actively updated to JavaEE 7 (JPA 2.1, EJB 3.2, and JMS 2.0) but a few JavaEE 6 APIs remain (JMS 1.1). The development environment used in class is JavaSE 8 and JavaEE 7-compliant.

Using modern development tools, commercial persistence providers, and application servers, students will design and implement several significant programming projects using the above mentioned technologies and deploy them to a Java EE environment that they will manage.

I am available at least 20min before class, breaks, and most times after class for extra discussion. I provide detailed answers to project and technical questions through the course newsgroup. You can get individual, non-technical questions answered via e-mail. I usually have all questions posted by 9pm answered by COB that evening. Students needing further assistance are also welcome make other arrangements during the week or schedule a web meeting using Adobe Connect.




  • Projects must build using Maven 3. Ant will be used late in the semester to wrap any interactive commands (e.g., launch JavaSE JMS subscriber)

  • All projects must be portable to build and deploy within grader and intructor environments. You may submit partial projects early to get portability feedback (not early content grading feedback).

  • Test Cases must be written using JUnit or another unit test frameworks that will run within a Maven surefire and failsafe environment.

  • Projects must be supplied with a README that points out how project meets requirements.

You should test your application prior to submission by

You will e-mail the projects to the grader and me with the following subject line

Your submission will include source zip and README (could be in source zip). You may also include pre-built artifacts if it does not add a huge size burden. The easiest way to do this is to zip up the project from the root after completing a build.

If you need to make a correction, the correction should have the following e-mail subject. The body should describe what you wish to revise.

Submission e-mails (mail to all):

  • Jim - jim.stafford@jhu.edu


Table 7.1. JavaEE 7 Specifications [2] [3]

Enterprise Application TechnologiesVersionWeb ProfileCourse Relevance
Enterprise JavaBeans (EJB)3.2EJB-litePrimary
Java Persistence API (JPA)2.1YY
Context and Dependency Injection (CDI)1.1YY
Dependency Injection for Java (JSR-330)1.0YY
Common Annotations for the Java Platform1.2YY
Java Transaction API (JTA)1.2YY
Java Message Service API (JMS)2.0 Y
Bean Validation1.1YY
Interceptors1.2Y(maybe)
Managed Beans1.0Y 
JavaEE Connector Architecture1.7  
JavaMail1.5  
Batch Applications for the Java Platform1.0  
Concurrency Utilities for Java EE1.0  
Web Service TechnologiesVersionWeb ProfileCourse Relevance
Java API for RESTful Services (JAX-RS)2.0YY
Java Architecture for XML Binding (JAXB)2.2 Y
Java API for XML-based Web Services (JAX-WS)2.2  
Web Services Metadata2.1  
Java API for XML-based RPC (JAX-RPC)1.1  
Java API for XML Registries (JAXR)1.0  
Web Services for JavaEE1.4  
Web Related TechnologiesVersionWeb ProfileCourse Relevance
Servlet3.1YMinor
JavaServer Pages (JSP)2.3Y 
JavaServer Faces (JSF)2.2Y 
Expression Language3.0Y 
JSTL1.2Y 
Management TechnologiesVersionWeb ProfileCourse Relevance
Java Authentication Service Provider Interface for Containers (JASPIC)1.1  
Java Authorization Service Provider Contract for Containers (JACC)1.5  
Java EE Management1.1  
Java EE Deployment1.2  
Debugging Support for Other Languages1.0Y 

Table 7.2. JavaEE 6 Specifications [4]

Enterprise Application TechnologiesVersionWeb ProfileCourse Relevance
Enterprise JavaBeans (EJB)3.1EJB-litePrimary
Java Persistence API (JPA)2.0YY
Context and Dependency Injection (CDI)1.0YY
Dependency Injection for Java (JSR-330)1.0YY
Common Annotations1.1YY
Interceptors1.1YY
Java Transaction API (JTA)1.1YY
Java Message Service API (JMS)1.1 Y
Bean Validation1.0Y(maybe)
Managed Beans1.0Y 
JavaEE Connector Architecture1.6  
JavaMail1.4  
Web Service TechnologiesVersionWeb ProfileCourse Relevance
Java API for RESTful Services (JAX-RS)1.1 Y
Java Architecture for XML Binding (JAXB)2.2 Y
Java API for XML-based Web Services (JAX-WS)2.2  
Web Services Metadata2.1  
Java API for XML-based RPC (JAX-RPC)1.1  
Java API for XML Registries (JAXR)1.0  
Web Services for JavaEE1.3  
Java API for XML Messaging (JAXM)1.3  
Web Application TechnologiesVersionWeb ProfileCourse Relevance
Servlet3.0YMinor
JavaServer Pages (JSP)2.2Y 
JavaServer Faces (JSF)2.0Y 
Expression Language2.2Y 
JSTL1.2Y 
Management TechnologiesVersionWeb ProfileCourse Relevance
Java Authentication Service Provider Interface for Containers (JASPIC)1.0  
Java Authorization Service Provider Contract for Containers (JACC)1.4  
Java EE Management1.1  
Java EE Deployment1.2  
Debugging Support for Other Languages1.0Y 

[5]

1.2

"CORBA Integration"; Dec 1999

  • RMI over IIOP

1.3

"Local Interface EJBs"; Sep 2001

  • Connector API

  • EJB (2.x) local interfaces and new CMP model

1.4

"Web Service Enabled"; Nov 2003

  • SOAP Web Services

  • Deployment, Management, JAAS

5

"Ease of Development"; May 2006

  • Annotations

  • Better Defaults

  • EJB and Servlet Dependency Injection

  • JPA, StAX, JAX-WS

6

"More Ease of Development"; Dec 2009

  • Profiles; making some components optional

  • Flexible deployments; no EJB.jar or EAR requirement

  • No interface EJBs

  • Component and Dependency Injection

7

"Offloading Additional Common Infrastructure Tasks and More Ease of Development"; June 2013

  • Additional Web standards; Web Sockets and JSON

  • HTTP Client API within JAX-RS

  • Batch API

  • Concurrency Utilities

  • More consistency between CDI and component models

  • More inherent integrations with Validation API

  • Simplified JMS API

  • JPA Schema generation

  1. "Java Platform, Enterprise Edition 6 Specification (JSR-316 Final Release)", Roberto Chinnici and Bill Shannon, http://jcp.org/aboutJava/communityprocess/final/jsr316, 2009 Sun Microsystems.

  2. "Java Platform, Enterprise Edition 7 Specification (JSR-342 Final Release)", Linda DeMichiel and Bill Shannon, https://jcp.org/aboutJava/communityprocess/final/jsr342/index.html, 2013 Oracle America, Inc.

  3. "JavaEE Version History", Wikipedia, http://en.wikipedia.org/wiki/Java_EE_version_history, September 3. 2012.

|-- pom.xml
|-- src
|   |-- main
|   `-- test
`-- target
    |-- classes
    |-- ex1-1.0-SNAPSHOT.jar
    |-- surefire-reports
    `-- test-classes
        
target
|-- classes
|   `-- myorg
|       `-- mypackage
|           `-- ex1
|               `-- App.class
|-- ex1-1.0-SNAPSHOT.jar
|-- log4j-out.txt
|-- surefire-reports
|   |-- myorg.mypackage.ex1.AppTest.txt
|   `-- TEST-myorg.mypackage.ex1.AppTest.xml
`-- test-classes
    |-- log4j.xml
    `-- myorg
        `-- mypackage
            `-- ex1
                `-- AppTest.class
classes

An exploded directory tree for built artifacts to be placed into the module archive

test-classes

An exploded directory tree for built artifacts used for test

*-reports

Results of unit and integration testing

{artifactId}-{version}.jar

Results of unit and integration testing

log4j-out.txt

An example output file of the build/tests written to the target directory


<?xml version="1.0"?>
<project 
    xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>myorg.myproject</groupId>
    <artifactId>ex1</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>My First Simple Project</name>
        ...
    <properties>
        ...
    </properties>

    <dependencies>
        ...
    <dependencies>

    <build>
        <plugins>
            ...
        </plugins>
    </build>
</project>

  1. Maven will first look for a dependency artifact in the local repository

  2. Maven will then look for a dependency artifact in a remote repository like ibiblio

  3. Maven will search all known repositories until the artifact is found or all repositories have been checked

  4. Maven will install module artifacts into the local repository during the install phase of the build

    $ mvn install
        ...
    [INFO] --- maven-install-plugin:2.3.1:install (default-install) @ ex1 ---
    [INFO] Installing /home/jcstaff/proj/ejava-javaee/solutions/ex1/target/ex1-1.0-SNAPSHOT.jar to 
        /home/jcstaff/.m2/repository/myorg/myproject/ex1/1.0-SNAPSHOT/ex1-1.0-SNAPSHOT.jar
    [INFO] Installing /home/jcstaff/proj/ejava-javaee/solutions/ex1/pom.xml to 
        /home/jcstaff/.m2/repository/myorg/myproject/ex1/1.0-SNAPSHOT/ex1-1.0-SNAPSHOT.pom
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
                    

Use -U to force an update check

Maven will limit its search of a remote repository to expressed time limits. If it attempts and fails to locate an artifact from a remote repository it will not re-attempt to query that repository until the time limit expires. Sometimes the failure has nothing to do with the repository not having the artifact (e.g., wireless network down) and when you clear the error you can force Maven to retry before the timeout period expires by adding a -U to the command line.

Use the -o offline flag to eliminate repository checks

Many times Maven will be too aggressive searching for artifacts you already know are not of value to the current build. You can tell Maven to work in an offline mode to bypass the work involved. This is helpful when you are disconnected from the network but will fail if you are truly missing a required artifact. You can activate/deactivate the offline more consistently using an element in the settings.xml


<offline>false</offline>

<dependencies>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.1</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
        <scope>test</scope>
    </dependency>
....
</dependencies>
GAV

Must provide its groupId, artifactId, and version for each dependency

scope

Defines when the dependency applies (default=compile)

type

Defines the artifact type of ther module (default=jar)

Value directly relates to the project packaging element of the dependency

|-- ejbsessionBankImpl
|       |-- ejbsessionBankImpl-3.0.2013.2-SNAPSHOT.jar
|-- ejbsessionBankEJB
|       |-- ejbsessionBankEJB-3.0.2013.2-SNAPSHOT.jar
|-- ejbsessionBankWAR
|       |-- ejbsessionBankWAR-3.0.2013.2-SNAPSHOT.war
|-- ejbsessionBankEAR
|       |-- ejbsessionBankEAR-3.0.2013.2-SNAPSHOT.ear
classifier

Defines a special type of artifact/custom from a module

`-- target
...
    |-- txHotelDAO-3.0.2013.2-SNAPSHOT.jar
    |-- txHotelDAO-3.0.2013.2-SNAPSHOT-sources.jar
    `-- txHotelDAO-3.0.2013.2-SNAPSHOT-tests.jar
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>${java.source.version}</source>
                <target>${java.target.version}</target>
            </configuration>
        </plugin>
         <!-- surefire.argLine is set in debugger profile -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.17</version>
            <configuration>
                <argLine>${surefire.argLine}</argLine>
            </configuration>
        </plugin>
        ...
  • New plugins can be added, but will need to be wired into a specific lifecycle phase of the build.

    
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>${maven-failsafe-plugin.version}</version>
        <configuration>
            <argLine>${surefire.argLine}</argLine>
        </configuration>
        <executions>
            <execution> <!-- run the tests here -->
               <id>integration-tests</id>
                   <phase>integration-test</phase>
               <goals>
                   <goal>integration-test</goal>
               </goals>
            </execution>
            <execution> <!--  delay failures to after undeploy -->
                <id>verify</id>
                <phase>verify</phase>
                <goals>
                    <goal>verify</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    The above example shows the failsafe plugin being configured to share some properties with surefire and have specific goals wired into the integration-test and verify lifecycle phases.

$ mvn (phase) (plugin:goal) -D(system-property) -P(profile)
        
  • phase

    clean

    Remove contents of target tree

    test

    Build the src/main and src/test tree and execute the unit tests as defined by the surefire plugin

    pre-integration

    Perform unit tests and perform any steps required to ready for integration test

    integration-test

    Perform integration tests as defined by the failsafe plugin

    post-integration-test

    Tear down anything required to perform integration tests

    verify

    Evaluate results of integration tests

    install

    Install module artifacts into local repository

  • (plugin:goal)

    • Manually trigger a plugin goal without a specific build lifecycle

    • ex. jetty:run, dependency:tree, or dependency:help

  • -D(system-property)

    • Manually define a system property key or key and value to be used as a property in the build

    • Must configure surefire/failsafe to promote these as properties Junit -- these are system properties of the maven build and not of the JVM tasks kicked off by the maven build.

  • -P(profile)

    • Manually trigger build configurations latched by a profile

    • e.g., which DB driver to use

  • -P!(profile)

    • Manually turn off a profile

    • e.g., turn off a profile activated by a rule or settings.xml

    Use -P\!(profile) with bash shell

    The bash shell requires the bang ("!") character to be escaped. Use -P\!(profile) when using the bash shell.

  • Provide groups of conditional configuration

  • Adds flexibility to build

  • Flexibility can sometimes add confusion for both developers and build tools -- be careful

  • Maven modules boundaries are highly influenced by the re-usable artifacts that must be produced

    • If you have many .jars, you likely have many maven modules

    • If you have few but large .jars, you likely have few but large maven modules

    • If you require different types of artifacts, you likely have different maven modules

  • Maven can be used in multi-module configuration

  • Many maven modules share the same configuration needs -- could lead to duplication

  • POM Inheritance helps mitigate duplication issues

  • Defines what is possible without actively imposing the dependency or plugin defined

  • Placed in a parent of multi-module project


Set program breakpoints where problems have been identified

Table of Contents

I. Project 1
16. eMarket Project 1 Description
16.1. Purpose
16.1.1. Goals
16.1.2. Objectives
16.2. Business Description
16.3. Technical Overview
16.4. Assembly Overview
17. Project 1 Technical Details
17.1. Database Schema
17.1.1. eSales Candidate Database Schema
17.1.2. eBidbot Candidate Database Schema
17.2. Business Objects
17.2.1. eSales Candidate Business Objects
17.2.2. eBidbot Candidate Business Objects
17.3. Validation API
17.4. Sales Ingest
17.5. DAOs
17.5.1. eSales DAOs
17.5.2. Bidbot DAOs
17.6. SQL Tuning (Indexes)
17.7. Business Logic
17.7.1. eSales Business Logic
17.7.2. eBidbot Business Logic
18. Project 1 Getting Started
19. Project 1 Testing
20. Project 1 Grading
II. Project 2
21. eMarket Project 2 Description
21.1. Purpose
21.1.1. Goals
21.1.2. Objectives
21.2. Technical Overview
22. Project 2 Technical Details
22.1. Data Tier and Business Logic Support
22.2. EJB Tier
22.2.1. eSales EJB Tier
22.2.2. eSales DTOs
22.2.3. eSales EAR Deployment
22.2.4. eSales RMI Test
22.2.5. eBidbot/eSales Business Logic Integration
22.2.6. eBidbot WAR Deployment
22.2.7. eBidbot EJB Tier
22.2.8. eBidbot DTOs
22.3. Web UI
22.3.1. eSales Web UI
22.3.2. eBidbot WEB UI Tier
22.4. Transactions
23. Project 2 Getting Started
24. Project 2 Testing
25. Project 2 Grading
III. Project 3
26. eMarket Project 3 Description
26.1. Purpose
26.1.1. Goals
26.1.2. Objectives
26.2. Technical Overview
27. Project 3 Technical Details
27.1. Data Tier, Business Logic, and EJB/WAR Support
27.2. eSales Access Restrictions
27.3. eSales RMI client Authentication
27.4. eBidbot Access Restrictions
27.5. eBidbot RMI client Authentication
27.6. eSalesWAR Access Restrictions
27.7. eBidbotWAR Access Restrictions
27.8. Interceptors and Validators
27.9. eSales JMS Publisher
27.10. eBidbot JavaSE Subscriber
27.11. eBidbot MDB Subscriber
27.12. eSales EJBTimer
27.13. eBidbot EJBTimer
28. Project 3 Testing
29. Project 3 Grading

eSales is planning an on-line auction site to allow sellers to auction items and buyers to place bids and ultimately purchase products. At the same time, eBidbot is planning an on-line automated bidding site that will help bidders make bids with eSales.

Sellers can start an auction using the eSales on-line auction site. They specify a title, category, description, asking price, start/stop time, and any images. Using the eSales buyer interface, buyers can manually bid on auctions until they close.

With eBidbot, buyers also have the option of using an independent site to place their bids. Buyers place orders with eBidbot, providing them the auction and min/max bidding parameters. eBidbot will become a trusted client of eSales and be able to make bids on behalf of the actual buyer.

Both eSales and eBidbot have come to you to develop the initial phase of their applications. You are tasked with implementing a low-cost prototype, based on current standards, to automate much of this activity. At this point in the project we are primarily looking to build the data access tiers for both the eSales and eBidbot (two separate systems). We will also add a minor amount of business logic to coordinate the data access between the individual data access objects.

For eSales, the system is initialized with a starting set of information pertaining to auctions, accounts, and addresses. New information can be added and updated.

For eBidbot, the system is initialized with an empty database that is designed to hold bids. The bids will be for auctions in eSales, an associated account, and maximum bid price. The eBidbot site will make bids for the account until the auction is closed or bidding has exceeded the defined maximum. Information about the ietm being auctioned will be obtained through an interface with eSales implemented later.

The work done during this project focuses on the business objects (BOs), the data access objects (DAOs) of the data access tier, and some initial business logic interfaces (BL) and business logic implementations (BLImpl). The DAOs will be based on the Java Persistence API (JPA). How you partition the implementations of your projects is up to you. A suggested starting point is provided at the end of this project description.

The business objects encapsulate the core business data and rules of the application. You will design the business objects and then map them to the database. You are required to implement required CRUD (Create, Read, Update, and Delete) capability with JPA but you only need to implement the CRUD methods that are necessary to complete the provided end-to-end scenario. You will be required to encapsulate all object to relational (O/R) mapping within the DAOs, descriptor files, and/or class metadata annotations. You will be given a set of test data to initially populate your applications and be the source of data for the ingest requirement. To use the data, you will ingest using a parser supplied by the instructor. There is a sample thread in the projects/eMarket/eSales directory that shows how to use the parser as well as other aspects technology within the project.

The database will have a functional schema and indexes to provide query performance. Business objects will be validated in the database using schema constraints and within the JVM using the Validation API.

The business logic will provide a set of classes with concise methods that map easily to the provided end-to-end scenario. The business logic will ensure proper use of the overall application, delegating some business logic functionality to the business objects and full O/R responsibility to the DAOs. eSales will have an ingest requirement as well as the requirement to manipulate and add to what was ingested. eBidbot will start fresh and obtain all data from users and coordinate with eSales. However, for project 1, eBidbot will be unable to fully implement data exchange with eSales because remote interfaces will not be implemented until project2. Some of that must be stubbed at this point. You are only required to implement enough business logic methods that it takes to implement the end-to-end scenarios specified later within this specification.

The test acceptance for the first project will be the unit tests and an integration test that takes the business logic, data access tier, and business objects through a provided end-to-end scenario that will never change during the semester. You are required to supply the following tests:

  • A unit test that implements the steps of the provided eSales end-to-end scenario

  • A unit test that implements the steps of the provided Bidbot end-to-end scenario

  • At least one unit test per architectural layer (BO, DAO, BL) that demonstrates your ability to test at that level.

Tip

The amount of work that you can implement within the bounds of this project spec could be endless if you attempted to account for everything/anything. It is very important that you limit your work to only what is necessary to implement (and test) the functionality required for the end-to-end scenario. That means you may have entities that are designed to be created but never modified while having other entities that go through a full lifecycle. When deciding to add or skip certain capabilities -- always ask yourself "does the business logic need this behavior to implement the end-to-end scenario".

Since the work is for separate applications, we will need to establish two separate application projects for this work; eSales and eBidbot. The development can physically share resources (e.g., same database and application server), but should be easily separated. It is suggested that you form a root for the overall eMarket work to coordinate integration testing, and then group the lower-level work under two child projects; eSales and eBidbot. See some suggested project layouts at the bottom of this specification. A sample set of projects that implement a thin eSales thread has been made available. Please ignore the TestData sub-project when using the example to craft your source tree. You will depend on projects within that tree -- not re-implement them and not copy them. See the Getting Started section towards the end of this specification for a more detailed sample project layout.

Note

You will likely copy significant portions of the thin thread example and other class examples into your project. Be aware that the thin thread and other example pom.xml files inherit from the class root project that provides dependencyManagement and pluginManagement duties. You will either need to also inherit from the dependencies/pom.xml or compensate by re-defining the management sections in the root pom.xml of your project.

Since students in the class will be producing parallel implementations for the applications and submitting them for evaluation, it is asked that you come up with unique names for your artifacts. This could be done by replacing the "e" in eMarket, eSales, and eBidbot with a unique name that corresponds to your newsgroup or college login (ex. jcsMarket, jcsSales, jcsBidbot). You should also use this same pattern for java packages (ex. jcs.sales, jcs.bitbot), DB tables (e.g., JCS_), etc.

There should be no use of System.out.println() in the code and all implementations must use a logging API with log4j as the logging provider. You may leave debug in your code, but this should be able to be turned on/off with the proper logging priority changes in the log4j.xml configuration.

Note

There are a lot of technical details presented with this specification. This is done to provide clarity and a starting point for design discussion. However, it is not done so to specify specific class or method naming, project layout, or order of work. You are free to make many technical adjustments to the ideas presented.

Design 2 sets of database schema that account for the following information. Although we will deploy the 2 database schemas to the same database for the project, they should be designed to be independently deployed to separate databases. eSales and eBidbot are two independent applications. This will primarily affect your attempt re-use tables or to make primary key assumptions between the two.




Design an initial business interface and business logic for the applications. The core O/R mapping work will be done by the DAOs. However, it is the ultimate responsibility of these business logic implementations that either it or the business objects enforce the business rules of the application. The DAOs only perform O/R mapping and do not enforce such things as a minimum bid. The business logic is assumed to work within the context of a single, externally controlled transaction. Do not attempt to control the transaction of the EntityManager within these objects or you will NOT be portable to the EJB tier. You need only implement the behavior required to implement the end-to-end use case listed in the testing section. Some of the anticipated methods are listed below.


AccountMgmt/AccountMgmtImpl

encapsulates the actions required to create, get, update and close an account.

  1. createaccount - you will need to at least create a seller and two or more buyer accounts.

SellerMgmt/SellerMgmtImpl

encapsulates the actions required to create and get auctions for a seller.

  1. createAuction - creates a new auction for a seller. All dates and properties of the auction need to be of consistent and legal values.

  2. getUserAuctions - returns a collection of auctions associated with a seller. This can be used to determine if the auction has been added.

  3. getAuction - returns a specific auction by ID. This can be used to track the state of a specific auction for a seller.

BuyerMgmt/BuyerMgmtImpl

encapsulates the actions required to get and bid on auctions.

  1. getOpenAuctions - returns a collection of auctions that have not ended. This can be used to pick a specific auction to bid on.

  2. placeBid - creates a bid for a specific user and auction. The auction must be open, the user must exist, and the bid amount must be greater than any pre-existing bid.

  3. getAuction - returns a specific auction by ID. This can be used to track the state of a specific auction for a buyer.

TestSupport/TestSupport

a useful tool during testing that encapsulates how to get the application back into a known state prior to running a test or to inspect values not normally exposed through the normal business interfaces.

  1. getAccounts - get all accounts in the system.

  2. removeAccount - sanely remove an account from the system. This may require removing the account from any current bids, etc. in order to satisfy referential integrity.

  3. getAuctions - get all auctions in the system.

  4. removeAuction - sanely remove an auction from the system. This may require removing bids, images, and other objects that may have references to this object.

  5. clearAll - sanely take the state of the system down to a coldstart.

Ingestor

the Ingestor written as a part of a separate requirement is also logically considered part of this tier.

  1. ingest - point an externally provided parser at a set of test data and use the DAOs to populate the system to a known state.

The following sketch of two directory structures can be used as a starting point for your overall application. The first is a simplified project layout that collapses the number of sub-projects into a single "Impl" project. It is suggested that you use this layout if you are new to maven and want the simplest configuration possible. The second is a more robust layout and is closer to a multi-developer environment. Use the later structure if you want to better simulate a work environment where the work of multiple developers needs clearer separation.



  1. Provide a JUnit test for your business objects (BOs) that test the manipulation of the data. An example test might be to try adding a bid to a closed auction. These tests should be packaged with the BOs. There should be a separate project and test for both eSales and eBidbot. It is anticipated that these tests will be a minimal demonstration of understanding.

  2. Provide a JUnit test for your eSales and eBidbot JPA DAOs. This should test the implementation for the required CRUD operations for each type of object. It is understood that some of the operations will be handled by cascades, so you might not have a set of methods handling each type of business object. This test should be packaged with the DAOs.

  3. Provide a JUnit test for your business logic to test the basic functionality of your business logic design, including ingest. The ingestor test should be able to reference a known data file and ingest records into the database using the DAOs. These tests should be packaged with the business logic implementation.

  4. Provide a set of JUnit test programs to verify the following end-to-end scenario in eSales. This test should be implemented as a JUnit test and packaged with the business logic implementation.

  5. Provide a set of JUnit test programs to verify the following end-to-end scenario in eBidbot. This test should be implemented as a JUnit test and packaged with the business logic implementation.

Your project will be graded on completeness and quality of product. In order for you to receive full credit in each area, it must be a) complete, b) done well, and c) tested. The breakdown of grading will be as follows:

The following table contains examples of where projects have lost points in the past. Of course, each project submitted can introduce new issues or different severity levels of the same issues. Do not treat this as a complete list.

Table 20.1. Sample Lost Points

README   
Not provided10  
Projects cleanly builds with Maven   
groupIds, schema, java packaging, etc do not have a project-specific name mangler2  
Avoidable build errors2  
Key areas not building10  
Poluting project with do-nothing tests or tests that are not tests2  
Managing multiple copies of the same source file.1  
Large commented out blocks of code.2-5  
Non-portable references to external resources (e.g., ingested file)2  
Managed Schema   
Database columns not well defined and constrained (e.g., FKs, non-null, max size)1  
Improper use of DATE, TIME, and/or TIMESTAMP 1  
No definition of any indexes2  
Business Objects   
Improper/no TemporalType declaration for Dates1  
PK classes (if exist) did not implement required constructs1  
Use of Validation API   
Missing any declaration of validation criteria in BOs3  
Not explicitly performing validation2  
JPA DAO and JPA O/R Mapping   
Missing key relationships5  
Managing transactions in DAO1  
Relationships should not be modeled as entities2  
Using provider-specific mechanisms over JPA-provided technique1  
Not honoring dependencies. Attempt to delete entities with incoming relationships/FKs.1  
Walking the object tree functionally works but using a JPA-QL query would be much cleaner and more efficient. 2  
Ingest   
Re-used IDs from ingested XML file and did not generate IDs local to project2  
Did not include a unit test that *verified* injest worked1  
Business Logic   
Implemented stateful logic (Wrong!)5  
No separate testing of business logic. Relied too much on end-to-end as unit test.1  
Managing transactions in business logic1  
Did not implement all methods required for end-to-end1  
Not exhibiting good command of what it means for an entity to be managed and what you do and don't need to do in that state 1  
Persisting BOs from other application. Not preserving separation between applications.1  
End-to-end Integration Test   
Poluted, hard to follow, too much extra stuff2  
Missing resetAll and populate at start of scenarios5  
Missing step X1  

The project will continue along two parallel paths; eSales and eBidbot. However, this time we will add several new project types; EJB, EAR, WAR, and Test. We will add all new project types to eSales. We will add (or migrate to) the WAR type to eBidbot. These new sub-projects will become siblings to your existing eSales Impl -or- BO, DAO, and BLImpl sub-modules. For eBidbot, you have the option of making the WAR a sibling module, the only module, or migrating the existing Impl project to be a WAR project ( and remain with a single module for eBidbot). The new projects will depend on your legacy work. The remote interface of the EJB will also require specific design of what gets externalized to the client. The remote clients do not share the same address space we had in Project 1 and we cannot afford to serialize the entire contents of a database full of related information. Data Transfer Objects (DTOs) will be part of the EJB remote interface design.

You have finished a significant amount of eSales during Project 1; the O/R mapping and core business logic of a non-trivial business model. You will now host the data access tier and business logic within an EJB component. This EJB component will supply the EntityManager, control transaction boundaries, provide local interaction for the Web Tier, and a RMI interface for remote clients. Security will be addressed in the next project. To limit the scope of the project, the Web UI requirements will be constrained to a limited number of use cases. You are to deploy eSales using an EAR and eBidbot using only a WAR.

eBidbot will require additional work as well. With a remote interface for eSales in hand and the ability to either simulate or operate with a live instance, we can now complete the rest of the the business logic that will also be hosted within an EJB tier. We'll try to keep the Web-UI minimal.

You may develop your Web tier in an alternate environment, such as Jetty. However, it must be submitted as part of the application that runs within JBoss/Wildfly.

Add separate Web UIs (WARs) to both applications to demonstrate integration between the Web UI and EJB Tiers.

The following sketch of directory structure can be used as a starting point for your overall application. It assumes you already have either a consolidated Impl -or- a BO, DAO, and BLImpl set of projects in place from Project 1. You will not have the option of consolidating the EJB, WAR, EAR, and RMI Test into a single project for eSales. They must be implemented as separate projects with proper dependencies between them declared. You *do* have the option of merging all modules into a single WAR module for eBidbit or many of the alternatives as long as eBidbit is deployed as a WAR.


Your project will be graded on completeness and quality of product. In order for you to receive full credit in each area, it must be a) complete, b) done well, and c) tested. The breakdown of grading will be as follows:

The following table contains examples of where projects have lost points in the past. Of course, each project submitted can introduce new issues or different severity levels of the same issues. Do not treat this as a complete list.

Table 25.1. Sample Lost Points

README   
Not provided10  
README did not indicate where X was located and it was not obvious even after ...2  
The WebUI is hard to navigate (fine) but README offered no assistance5  
Projects cleanly builds with Maven   
One of your IT tests assume the DB is setup correctly prior to running and that would only be true of we were running a common server database instance across our unit and IT tests. 2  
Testing does not produce consistent results - out of four runs of mvn install the process failed twice and succeeded twice. 2  
Build was not portable. I had to make changes. Sending me a copy of this beforehand would have caught this. 2  
Project 1 functionality   
DB schema is under-constrained1  
Project 1 end-to-end scenarios no longer exist/run2  
EJB Tier, remote interface, and EAR deployment   
Attempting to set the state of a @Stateless EJB. What do you think will happen to that state when you get a different bean instance the next time you call? 5  
With auto-create DDL turned on (hibernate.hbm2ddl.auto" value="create") your application deletes all data when redeployed. Deleting all data should be restricted to only an explicit call to resetAll(). 5  
Not separating a single call into separate transactions to drop and then create schema. First action may fail when not exist. 2  
You have methods that will only work in a @Local interface a part of your @Remote interface 2  
Reusing business logic classes instead if EJB components - repeating the same work of the reusable EJB component in each EJB that needs to reuse the functionality. Inject @Local interfaces. Do not repeat instantiation and setup of identical business logic/DAO classes. 2  
Injest was not implemented within a deployed EJB. It was mistakely implemented the same as project 1 in a JUnit client. 5  
You have not integrated the two applications at the EJB remote interface level. The second application does not make a single remote call to the first application. All interaction is occcuring outside of the server-side and results passed in. 5  
WAR/EJB deployment   
You are deploying EJBs from the first application within your second application's WAR. Look at your built/deployed artifact and correct dependencies. 5  
Web UI integration   
UI does not provide a path to satisfy a step in the end-to-end scenario (that the IT test shows works). 2  
EJB/Impl functionality called by UI fails and is not exercised by end-to-end IT test 2  
This is a real bust when tested on the deployment platform. This should have been easily noticed. Pressing resetAll() results in the following error displayed. 5  
Transactions   
Transaction scope not explicitly defined for EJB. You are accepting container defaults. 1  
No attempt to demonstrate transaction rollback 10  
Scenario shows business logic check but not a rollback of actions (store) to a transactional resource (DB). The requirement called for you to persist something all the way to the database - such that if you stopped in a breakpoint you would see the data - and then have the data thrown away due to a rollback. 7  
End-to-end Integration Test   
Poluted, hard to follow, too much extra stuff2  
Missing resetAll and populate at start of scenarios5  
Missing step X1  
No. I want different functionality in this step1  

The project will build on the core implementation from Projects 1 and 2. We will mostly extend existing projects with security and asynchronous logic.

Java EE defines authentication and authorization to be independent of the overall API and capability. JBoss and other application servers provide simple, default mechanisms that are easy to demonstrate and more sophisticated mechanisms that are realistic for deployments that require no change to the JavaEE-compliant application code. We will use the simple, default/"other" security-domain defined within the standard JBoss installation. This uses the RealmUsersRoles login-module -- which is powered by two property files supplied and pre-populated by the class server files from ejava-wildfly901.


We are going to have a couple types of users. Some of the users will have zero, one, or more of these roles. Because of the static nature of our authentication, all users will have a login configured before the application is even deployed to the server.


If a user has a login for one application, they will use the same account to access the other application (e.g., user3 might have both esales-user and ebidbot-user roles).


Note

To clarify, your application will have a static set of logins and will ingest a set of accounts. A user with a login and no account can login, but won't be able to do anything meaningful. A user with an account and no login won't be able to access the system. Normally the login would be created at the same time as the account. Except for your JBoss configuration and your "Create Account" logic, no other part of your project should be aware of this tradeoff made for class project simplicity.

Some actions are open to any users; authenticated or not. Authentication will be performed using a JNDI login. All users will have a password of "password1!".

eBidbot will run-as an esales-trusted user and pass the userId for the eSales bidder with the placed bid.

For some asynchronous activity, we will implement an Auction Topic with eSales that will be used to provide updates to auction information. eBidbot will listen to this topic using a Message Driven Bean to keep orders up to date and to specifically know when they are closed. A stand-alone client will also be used to subscribe to auction events. The topic(s) will be pre-defined in your application server along with users and roles. However, you will have to design the type, structure, and payload of the messages on the topic(s).

eSales and eBidbot will use EJB Timers to help perform periodic business logic, like checking for completed auctions or making bids.

  1. Provide JUnit IT tests that verify the EJB functionality of eSales accessed through its remote interface using new access control restrictions.

  2. Provide JUnit IT tests that verify the EJB functionality of eBidbot using its new access control restrictions and ability to authenticate with eSales.

  3. Provide a JUnit IT tests that demonstrates the functionality of the JavaEE interceptor/validator.

  4. Implement the scripted use case below as an automated JUnit test and manually accessed script through the Web UI. All command line implementations must be wrapped in an Ant runtime script to encapsulate the classpath details in a portable manner (see the class jmsNotifier project for an example of using an Ant runtime script). The full JSE subscriber need not be part of the automated end-to-end JUnit test. The JUnit test/module must be delivered in a state that can be executed in a debugger -- whether directly within Eclipse or using a remote debugging session.


Your project will be graded on completeness and quality of product. In order for you to receive full credit in each area, it must be a) complete, b) done well, and c) tested. The breakdown of grading will be as follows:

The following table contains examples of where projects have lost points in the past. Of course, each project submitted can introduce new issues or different severity levels of the same issues. Do not treat this as a complete list.

Table 29.1. Sample Lost Points

README   
The WebUI is hard to navigate (fine) but README offered no assistance5  
Projects cleanly builds with Maven   
Using rogue users that are not part of the standard class setup in your end-to-end. 3  
Initial build fails. Looks to depend on DB schema bleedover between unit and IT tests. 2  
Project 1 and 2 functionality   
Second application being deployed as EAR and not WAR 2  
Relying on persistence unit to create schema -- thus blowing away all DB data on deployment 2  
Missing scenario feature (e.g., wrong data) from project 2 end-to-end scenario. 1  
Attempting to set the state of a @Stateless EJB. What do you think will happen to that state when you get a different bean instance the next time you call? 2  
Not self managing schema. With the end-to-end having resetAll() in place, why did you rely on the JPA provider to initialize your schema? 1  
Client Security Login   
Fine, but too many fine-grain logins. 0  
EJB Security   
Using credential logins for the JMS Connection from EJBs -- versus leveraging the @RunAs role 1  
Not relying on declaritive security to perform the role checks. You are also having the caller authorized for the role supply instance-specific information. For example, any division coordinator is allowed to report the score for any division. 2  
Not constraining authorized caller to manage only their information. Caller is passing references to information using identifiers that could be associated with any user versus "manage my stuff". By relying on those identifiers you are allowing them to "manage that stuff which may or may not be my stuff". 3  
EJB module not being associated with a specific security-domain. Relying on defaults. 2  
@RunAs takes a role -- not a principal 1  
WAR Security   
Requiring login to pages that should allow anonymous access. 1  
WAR is not properly locked down. 2  
Mixed use of BASIC and FORM. When signing in to perform action a Basic authentication popup appears and logout no longer functions, need to close browser to log out.    
EJB JMS Publisher   
Copied provided example wholesale and did not adjust to be your solution (e.g., features specific to the example are not required for project, comments specific to example are not appropriate for a project solution). 2  
Not closing resources (JMS 1.1) This eventually exhausts resources over time. 2  
Could not find testing of this anywhere to makeup for the fact that the end-to-end was not implemented 2  
EJB MDB Subscriber   
Not implemented 10  
Using System.out versus logging framework or better error reporting 1  
Java SE JMS Listener   
Did not provide your subscriber any credentials to interact with the server. 2  
Didn't work out of box. JMS topic mis-named 1  
EJB Timers   
It would be a better design to treat the timer() callback as an interface facade and not the triggering implementation mechanism. You have combined EJB Timer, JMS publishing, and business logic within a single method. 0  
End-to-end Integration Test   
Your configuration made it hard to run the end-to-end scenario in a debugger. All JNDI names and properties were solely expressed in the pom.xml rather than having suitable defaults in the IT test and overrides from the pom.xml. With that type of setup you did not have your pom.xml and surefire setup to allow remote debugging. 2  
Poluted, hard to follow, too much extra stuff2  
Missing resetAll and populate at start of scenarios5  
Missing step X1  
No. I want different functionality in this step1  



/**
 * Purchasing handles payment of purchased products.
 */
public interface Purchasing {
    /**
     * Creates an account for the user to use in purchasing products.
     * @param email
     * @param firstName
     * @param lastName
     * @return
     */
    Account createAccount(String email, String firstName, String lastName);
    /**
     * Completes the purchase of the items in the user's shopping cart,
     * empties the cart, and returns the total cost paid.<p/>
     * 
     * Note that this capability is not yet fully defined.
     * @param email
     * @param password
     * @return
     */
    double checkout(String email, String password);
}
/**

 * The catalog maintains a view of the inventory known to our application. 
 */
public interface Catalog {
    /**
     * Returns a list of products in the catalog chunked into page sizes.
     * @param offset
     * @param limit
     * @return
     */
    List<Product> getProducts(int offset, int limit);
    /**
     * Adds the selected product to the users' shopping cart and returns
     * the count of items.
     * @param id
     * @param validEmail
     */
    int addToCart(int id, String validEmail);
}
/**

 * A user shall be able to establish an account with just a first 
 * and last name and a unique email address.
 */
@Test
public void establishAccount() {
    log.info("*** establishAccount ***");
    
    //the user will supply their email address, first and last name
    String email="jharb@ravens.com";
    String firstName="john";
    String lastName="harbaugh";
    Account account = purchasing.createAccount(email, firstName, lastName);
    
    //they will get back a generated password to use as a login for the account
    assertNotNull("no account returned", account);
    assertNotNull("no password assigned", account.getPassword());
}
/**

 * A user shall be able browse products in the catalog.
 */
@Test
public void browseCatalog() {
    log.info("*** browseCatalog ***");
    
        //the user will ask for product summaries in pages
    int pageSize=10;
    int offset=0;
    List<Product> products = catalog.getProducts(offset, pageSize);
    
        //they will receive <= a page size of product information
    assertNotNull("no products returned", products);
    assertTrue("no products provided", products.size() > 0);
    
        //they can page thru the entire set
    for (int i=0; products.size() != 0; i++) {
        offset += products.size();
        products = catalog.getProducts(offset, pageSize);
        assertTrue("this catalog never ends!!!", i<100);
    }
}
/**

 * A user shall be able to purchase a product in the catalog.
 */
@Test
public void purchaseProduct() {
    log.info("*** purchaseProduct ***");
    
        //the user selects a product
    Product product=null;
    Random random=new Random();
    for (int i=0; product == null; i++) {
        List<Product> products=catalog.getProducts(random.nextInt(100), 1);
        product=products.iterator().next();
        assertTrue("I can't find anything to buy!!!", i<1000);
    }
    
        //the user adds the product to their shopping cart by providing the 
        //product id and their credentials
    int count=catalog.addToCart(product.getId(), validEmail);
        //the user receives a count of the items in the cart
    assertEquals("somebody tweeked my cart!!!!", 1, count);
    
        //the user checks out with the cashier -- payment not yet implemented
    double total=purchasing.checkout(validEmail, validPassword);
    
        //the user gets a total amount back as their receipt
    assertEquals("price doesn't add up", product.getPrice(), total, .01);
}

  • DBMS based on a relational model

  • Introduced by E. F. Codd in 1970s

  • Some challenges by other forms but still remains a standard for corporate data stores

public class JDBCBookDAOImpl implements BookDAO {

    private Connection connection;
    
    public void setConnection(Connection connection) {
        this.connection = connection;
    }
    @Override
    public Book create(Book book) throws PersistenceException {
        PreparedStatement statement=null;
        ResultSet rs = null;
        try {
            statement=connection.prepareStatement(
                "insert into JPADAO_BOOK (ID, DESCRIPTION, PAGES, TITLE) " +
                "values (null, ?, ?, ?)");
            statement.setString(1, book.getDescription());
            statement.setInt(2, book.getPages());
            statement.setString(3, book.getTitle());
            statement.execute();
            statement.close();
            
            Field id = Book.class.getDeclaredField("id");
            id.setAccessible(true);
            statement = connection.prepareStatement("call identity()");
            rs = statement.executeQuery();
            if (rs.next()) {
                id.set(book, rs.getLong(1));
            }
            
            return book;
        } catch (SQLException ex) { 
            throw new PersistenceException("SQL error creating book", ex);
        } catch (NoSuchFieldException ex) {
            throw new RuntimeException("Error locating id field", ex);
        } catch (SecurityException ex) {
            throw new RuntimeException("Security error setting id", ex);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException("Error setting id", ex);
        } catch (IllegalAccessException ex) {
            throw new RuntimeException("Access error setting id", ex);
        } finally {
            try { rs.close(); } catch (Exception ex){}
            try { statement.close(); } catch (Exception ex){}
        }
    }
    ...
}

Table of Contents

Purpose
1. Goals
2. Objectives
38. JPA Overview
38.1. Background
38.2. EntityManager
38.3. Entity
38.4. JPA Example
38.5. Entity States
38.5.1. Managed
38.5.2. Detached
38.6. Persistence Context
38.7. Persistence Unit
38.8. Example Layout
38.9. Persistence.xml
38.9.1. Application Example
38.9.2. Server Example
38.9.3. Optional hibernate.properties
38.9.4. Sample orm.xml
38.9.5. persistence.xml Elements
38.9.6. Entity Discovery
38.10. Basic Steps
38.11. Entity Manager Methods
38.11.1. Basic CRUD Operations
38.11.2. Membership Operations
38.11.3. State Synchronization Operations
38.11.4. Locking Operations
38.11.5. Query Operations
38.11.6. Other Operations
39. Entity Manager CRUD Methods
39.1. persist()
39.2. find()
39.3. getReference()
39.4. merge()
39.5. remove()
40. Entity Manager Membership Methods
40.1. contains()
40.2. clear()
40.3. detach()
41. Entity Manager State Synchronization Methods
41.1. flush()
41.2. FlushMode
41.3. refresh()
42. Entity Manager Locking Methods
42.1. Primary Lock Types
42.2. LockModeType
42.3. lock()
42.4. find(lock)
42.5. refresh(lock)
42.6. getLockMode()
43. Entity Manager Query Methods
43.1. JPA Queries
43.2. Native Queries
43.3. Criteria Queries
44. Other Entity Manager Methods
44.1. isOpen()
44.2. close()
44.3. getTransaction()
44.4. joinTransaction()
44.5. unwrap()
44.6. getDelegate()
44.7. getMetaModel()
44.8. getEntityManagerFactory()
44.9. setProperties()/getProperties()
45. JPA Maven Environment
45.1. JPA Maven Dependencies
45.1.1. JPA API classes
45.1.2. JPA Provider classes
45.1.3. Database
45.2. Supplying Runtime Properties
45.2.1. Turn on Resource Filtering in pom.xml
45.2.2. Use ${variable} References in Resource Files
45.2.3. Define Property Values in Parent pom.xml
45.2.4. Run with Filtered Values


<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" 
version="2.0">

    <persistence-unit name="jpaDemo">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <mapping-file>META-INF/orm.xml</mapping-file>
        <properties>
            <!-- standard properties -->
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:./target/h2db/ejava"/>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.user" value="sa"/>
            <property name="javax.persistence.jdbc.password" value=""/>

            <!-- hibernate-specific properties -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="create"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <!-- set to 0 to improve error messages when needed
            <property name="hibernate.jdbc.batch_size" value="0"/>            
             -->
        </properties>
    </persistence-unit>
</persistence>

Above example defines properties for entity manager to establish physical connections to database



<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd" 
version="2.0">
    
    <entity class="ejava.examples.daoex.bo.Author" 
            access="FIELD"
            metadata-complete="false"
            name="jpaAuthor">
        <table name="DAO_AUTHOR"/>
        <attributes>
            <id name="id">
                <generated-value strategy="SEQUENCE" 
                    generator="AUTHOR_SEQUENCE"/>                
            </id>
        </attributes>
    </entity>
</entity-mappings>
public interface javax.persistence.EntityManager{
...
}
        
Author author = new Author();

author.setFirstName("dr");
author.setLastName("seuss");
author.setSubject("children");
author.setPublishDate(new Date());
log.debug("creating author:" + author);
em.persist(author);
log.debug("created author:" + author);
-creating author:ejava.examples.daoex.bo.Author@17e7691, id=0, fn=dr, ln=seuss, subject=children, pdate=Sun Sep 16 10:14:32 EDT 2012, version=0
-created author:ejava.examples.daoex.bo.Author@17e7691, id=50, fn=dr, ln=seuss, subject=children, pdate=Sun Sep 16 10:14:32 EDT 2012, version=0


//create initial author
Author author = new Author();
...
em.persist(author);
//create detached author with changes
Author author2 = new Author(author.getId());
author2.setFirstName("updated " + author.getFirstName());
...
//merge changes 
Author tmp = em.merge(author2);
em.getTransaction().begin();
em.getTransaction().commit();
...
//verify results
assertFalse("author2 is managed", em.contains(author2));
assertTrue("tmp Author is not managed", em.contains(tmp));
assertSame("merged result not existing managed", author, tmp);
...
//verify changes were made to the DB
Author author3 = em.find(Author.class, author.getId());
assertEquals("updated " + firstName, author3.getFirstName());            


em.persist(author);
//callers can detach entity from persistence context
log.debug("em.contains(author)="+em.contains(author));
log.debug("detaching author");
em.getTransaction().begin();
em.flush();
em.detach(author);
log.debug("em.contains(author)="+em.contains(author));
em.getTransaction().commit();
//changes to detached entities do not change database
author.setFirstName("foo");
em.getTransaction().begin();
em.getTransaction().commit();
Author author2 = em.find(Author.class, author.getId());
log.debug("author.firstName=" + author.getFirstName());
log.debug("author2.firstName=" + author2.getFirstName());
assertFalse("unexpected name change", 
        author.getFirstName().equals(author2.getFirstName()));
-em.contains(author)=true
-detaching author
-em.contains(author)=false
-author.firstName=foo
-author2.firstName=dr


em.persist(author);
em.getTransaction().begin();
em.getTransaction().commit();
//change DB state out-of-band from the cache
em.getTransaction().begin();
String newName="foo";
int count=em.createQuery(
        "update jpaAuthor a set a.firstName=:name where a.id=:id")
    .setParameter("id", author.getId())
    .setParameter("name", newName)
    .executeUpdate();
em.getTransaction().commit();
assertEquals("unexpected count", 1, count);
//object state becomes stale when DB changed out-of-band
log.debug("author.firstName=" + author.getFirstName());
assertFalse("unexpected name", author.getFirstName().equals(newName));
//get the cached object back in sync
log.debug("calling refresh");
em.refresh(author);
log.debug("author.firstName=" + author.getFirstName());
assertEquals("unexpected name", newName, author.getFirstName());
-author.firstName=dr
-calling refresh
-author.firstName=foo
        
src
|-- main
|   |-- java
|   |   `-- ejava
|   |       `-- examples
|   |           `-- daoex
|   |               |-- AuthorDAO.java
|   |               |-- bo
|   |               |   `-- Author.java
|   |               |-- DAOException.java
|   |               `-- jpa
|   |                   `-- JPAAuthorDAO.java
|   `-- resources
|       `-- META-INF
|           |-- orm.xml
|           `-- persistence.xml (could be placed in src/test branch)
`-- test
    |-- java
    |   `-- ejava
    |       `-- examples
    |           `-- daoex
    |               `-- jpa
    |                   |-- JPAAuthorDAOTest.java
    |                   |-- JPACRUDTest.java
    |                   `-- JPATestBase.java
    `-- resources
        |-- hibernate.properties (optional)
        `-- log4j.xml













Notice impact of temporal DB-mapping does effect until data saved and retrieved from database

  • Every entity must have a primary key

  • Primary keys must be unique

  • Map to one ("simple") or more ("composite") properties

  • Properties must be of type

    • Java primitive types -- including object wrappers

    • java.lang.String

    • Custom classes made up of legal property types








IDENTITY Requires Provider to Get All PK Values from Database

The provider must obtain the next primary key value from the database each time. Notice in the first case above -- the provider has already flushed the INSERT to the database during the persist and before our manual call to flush()





SEQUENCE Strategy Allows Clients to Self-Generate Groups of PK Values

The provider generates allocationSize primary key values before performing a flush or follow-on poll of the sequence. An allocationSize greater than one (1) is much less communication with the database than the IDENTITY strategy -- which would be somewhat analogous to a SEQUENCE allocationSize=1.





TABLE Strategy Allows Clients to Self-Generate Groups of PK Values

As will SEQUENCE, the TABLE strategy allows each client to generate an allocationSize amount of primary key values before requiring a flush of the current batch or polling for a new table value.

  • Primary key consisting of multiple properties

  • Represented using a primary key class

    • Must implement Serializable

      public class MowerPK implements Serializable {
    • Must have a public no-arg constructor

      public MowerPK() {}
    • Must implement hashCode() and equals() methods

      @Override
      
      public int hashCode() { ... }
      @Override
      public boolean equals(Object obj) { ... }
    • Must define properties that match with the definition of the entity, including access

      private String make;
      private String model;
  • Accessed using same strategy as entity using it













  • Map a single Java class to multiple tables in database

  • Uses a join of two or more tables and a single Java class

    1. One table is designated as primary

    2. Secondary and primary must have a column to join





  • Similar to @EmbeddedId except embedded object is not a primary key

  • Embedded object has no primary key -- housed in parent entity table

  • Embedded object represents some abstraction

  • Parent entity represents an abstraction with a primary key and the embedded object

    • The primary key could be the only thing the parent entity is providing






package ejava.jpa.example.validation;


import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import javax.validation.Constraint;
import javax.validation.Payload;
/**
 * Defines a constraint annotation for expressing a minimum age.
 */
@Documented
@Constraint(validatedBy={MinAgeValidator.class})
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
public @interface MinAge {
    String message() default "too young";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default{};
    int age() default 0;
}
package ejava.jpa.example.validation;

...
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class MinAgeValidator implements ConstraintValidator<MinAge, Date>{
    int minAge;
    @Override
    public void initialize(MinAge constraint) {
        this.minAge = constraint.age();
    }
    @Override
    public boolean isValid(Date date, ConstraintValidatorContext ctx) {
        if (date==null) { return true; }
        //get today's date
        Calendar latestBirthDate = new GregorianCalendar();
        latestBirthDate.add(Calendar.YEAR, -1*minAge);
        
        //get calendate date of object
        Calendar birthDate = new GregorianCalendar();
        birthDate.setTime(date);
        if (birthDate.after(latestBirthDate)) {
            String errorMsg = String.format("%d is younger than minimum %d", 
                    getAge(birthDate), 
                    minAge);
            ctx.buildConstraintViolationWithTemplate(errorMsg)
                .addConstraintViolation();
            return false;
        } else {
            return true;
        }
    }
    
    private int getAge(Calendar birth) {
    ...
...
}

Define a sequence of validation groups to be tested in order and short-circuit upon failure

Define Constraints external to Bean Class

Provide access to persistence lifecycle events

Table of Contents

Purpose
1. Goals
2. Objectives
56. One-to-One Relationships
56.1. One-to-One: Uni-directional
56.2. @OneToOne Annotation
56.3. @JoinColumn Annotation
56.4. @JoinColumns Annotation
56.5. One-to-One: Bi-directional
56.6. Bi-directional Relationships and Ownership
56.7. Other Topics
56.8. Summary
57. One-to-Many Relationships
57.1. One-to-Many: Uni-directional
57.2. @OneToMany Annotation
57.3. One-to-Many: Bi-directional
57.4. @ManyToOne Annotation
57.5. One-to-Many: Element Collection
57.6. @ElementCollection Annotation
57.7. Other Topics
57.8. Summary
58. Relationship Capabilities
58.1. Fetching
58.1.1. fetch=LAZY
58.1.2. fetch=EAGER
58.2. Cascades
58.3. Orphan Removal
58.4. Summary
59. Object Collections
59.1. Object Identity
59.1.1. Instance Id
59.1.2. Primary Key Id
59.1.3. Switching Ids
59.1.4. Business Id
59.2. Collection Types
59.3. Summary
60. Foreign Keys
60.1. Primary Key Join
60.1.1. @PrimaryKeyJoinAnnotation
60.2. Using Composite Primary Key Property as Foreign Key
60.2.1. Using @IdClass Composite Primary Key Property as Foreign Key
60.2.2. Using @EmbeddedId Composite Primary Key Property as Foreign Key
60.3. Using Foreign Key in Composite Primary Key
60.3.1. Using Foreign Key in @IdClass Composite Primary Key
60.3.2. Using Foreign Key in @EmbeddedId Composite Primary Key (@MapsId)
60.4. Join Tables
60.4.1. @JoinTable Annotation
60.5. Summary
61. Many-to-One Relationships
61.1. Many-to-One: Uni-directional
61.2. Summary
62. Many-to-Many Relationships
62.1. Many-to-Many: Uni-directional
62.2. Many-to-Many: Bi-directional
62.3. Summary


Uni-directional

Only one class ("owner") knows of the relationship

  • Uses the @OneToOne annotation

  • Defines mapping to database

    • Uses either @JoinColumn or @JoinTable

Bi-directional

Both classes know of the relationship

  • Both classes use the @OneToOne annotation

  • One class is considered the owner and maps relation to the database

    • Uses either @JoinColumn or @JoinTable

    • Changes here change the database

  • One class is considered the inverse and names the other entity's property

    • @OneToOne(mappedBy="owning-property")

    • Changes here do *not* change database


  • Relation realized through a foreign key

  • Foreign key represented by a separate column

  • Foreign key from owning entity table references primary key of inverse entity table


Figure 56.5. One-to-One Uni-directional Usage

//create the owning side 

ejava.examples.orm.rel.annotated.Person person = new Person();
person.setFirstName("john");
person.setLastName("doe");
person.setPhone("410-555-1212");
//create the inverse side 
ejava.examples.orm.rel.annotated.Photo photo = new Photo();        
photo.setImage(image);        
//add photo to person and persist object tree
person.setPhoto(photo); //this sets the FK in person
log.info("added photo to person:" + person);
em.persist(person);        
assertTrue("personId not set", person.getId() != 0);
assertTrue("photoId not set", photo.getId() != 0);
log.info("created person:" + person);
-added photo to person:Person@1201f5bc, id=0, name=john doe, phone=410-555-1212, 
    photo=Photo@130b5045, id=0. image=46080 bytes
Hibernate:
    insert into ORMREL_PHOTO (PHOTO_ID, image) 
    values (null, ?)
Hibernate:
    insert into ORMREL_PERSON (PERSON_ID, firstName, lastName, phone, PERSON_PHOTO) 
    values (null, ?, ?, ?, ?)
-created person:Person@1201f5bc, id=1, name=john doe, phone=410-555-1212, 
        photo=Photo@130b5045, id=1. image=46080 bytes
//verify what we can get from DB

em.flush(); em.clear();
Person person2 = em.find(Person.class, person.getId());
assertNotNull(person2);
assertNotNull(person2.getPhoto());
log.info("found person:" + person2);
Hibernate:
    select
        person0_.PERSON_ID as PERSON1_24_0_,
        person0_.firstName as firstNam2_24_0_,
        person0_.lastName as lastName3_24_0_,
        person0_.phone as phone4_24_0_,
        person0_.PERSON_PHOTO as PERSON5_24_0_ 
    from ORMREL_PERSON person0_ 
    where person0_.PERSON_ID=?
Hibernate:
    select
        photo0_.PHOTO_ID as PHOTO1_25_0_,
        photo0_.image as image2_25_0_ 
    from ORMREL_PHOTO photo0_ 
    where photo0_.PHOTO_ID=?
-found person:Person@29564bb9, id=1, name=john doe, phone=410-555-1212, 
    photo=Photo@785e7845, id=1. image=46080 bytes

optional:boolean (default=true)

Designates whether relation is required. Default is true.

fetch:FetchType (default=EAGER)

Use EAGER or LAZY fetching of relationship when loading this entity. More of coverage of fetch in Fetching section

orphanRemoval:boolean (default=false)

Remote entity only exists for use by this relation. Automatically delete when relation terminated.

cascade:CascadeType[] (default=none)

Perform actions taken on this entity on related entity

targetEntity:Class

Define type for related class (if related Java type over-generalized)

mappedBy:String

Used by inverse side to specify owning entity property that maps relation to DB


  • No additional foreign key used to satisfy the bi-directional aspect of relation



Note

Notice only owning entity table is updated when relationship formed.

Figure 56.9. One-to-One Uni-directional Example Usage (cont.)

        

        //locate them from DB
        em.flush(); em.clear();
        Applicant applicant3 = em.find(Applicant.class, applicant.getId());
        Borrower borrower3 = em.find(Borrower.class, borrower.getId());
        assertEquals(applicant.getId(), borrower3.getApplication().getId());
        assertEquals(borrower.getId(), applicant3.getBorrower().getId());
Hibernate:
   select
        applicant0_.id as id1_12_2_,
        applicant0_.APP_BORROWER as APP2_12_2_,
        applicant0_.APP_PERSON as APP3_12_2_,
        borrower1_.BORROWER_ID as BORROWER1_15_0_,
        borrower1_.endDate as endDate2_15_0_,
        borrower1_.startDate as startDat3_15_0_,
        person2_.PERSON_ID as PERSON1_24_1_,
        ...
    from ORMREL_APPLICANT applicant0_ 
    left outer join ORMREL_BORROWER borrower1_ 
            on applicant0_.APP_BORROWER=borrower1_.BORROWER_ID 
    inner join ORMREL_PERSON person2_ 
            on applicant0_.APP_PERSON=person2_.PERSON_ID 
    where applicant0_.id=?
Hibernate:
    select
        applicant0_.id as id1_12_2_,
        applicant0_.APP_BORROWER as APP2_12_2_,
        applicant0_.APP_PERSON as APP3_12_2_,
        borrower1_.BORROWER_ID as BORROWER1_15_0_,
        borrower1_.endDate as endDate2_15_0_,
        borrower1_.startDate as startDat3_15_0_,
        person2_.PERSON_ID as PERSON1_24_1_,
        ...
    from ORMREL_APPLICANT applicant0_ 
    left outer join ORMREL_BORROWER borrower1_ 
            on applicant0_.APP_BORROWER=borrower1_.BORROWER_ID 
    inner join ORMREL_PERSON person2_ 
            on applicant0_.APP_PERSON=person2_.PERSON_ID 
    where applicant0_.APP_BORROWER=?
        -

  • Notice the extra joins that occur with default fetch mode=EAGER

  • inner joins used for optional=false relationships

  • left outer joins used for optional=true relationships







Uni-directional

Only one side ("owner") knows of the relationship

  • Uses the @OneToMany annotation

  • Defines mapping to database

    • Uses either @JoinColumn or @JoinTable

    Note

    @JoinTable adds the foreign key to the child table and not to the owning entity class table in this uni-directional case

Bi-directional

Both classes know of the relationship

  • Many side required to be owning side and maps relation to the database

    • Uses the @ManyToOne annotation

    • Uses either @JoinColumn or @JoinTable

    • Changes here change the database

  • One side required to be inverse and names the other entity's property

    • @OneToMany(mappedBy="owning-property")

    • Changes here do *not* change database




  • Relationship formed when inverse side added to owning collection


  • The foreign key is in the inverse entity class table

  • No construct in inverse class maps to this foreign key column






  • @XxxToXxx Relationship annotated with fetch=LAZY property


  • Parent accessed, debug printed, and then child collection accessed


  • Debug for parent printed before child rows retrieved

  • Child rows retrieved when parent collection accessed



  • Same as fetch=LAZY case


  • Child objects fetched with parent

  • Access to child collection occurs after all children fetched




Note

In this case, the primary key is used as the foreign key and must be set. To use the foreign key as the primary key -- use @MapsId

    //@PrimaryKeyJoinColumn  //the two tables will be joined by PKs
    @MapsId
    private Person identity;
    public Borrower(Person identity) {
        this.identity = identity;
    }


  • Setting primary key prior to persisting

  • Foreign key used twice -- once for relation and once for primary key




  • HOUSE_ID is both primary and foreign key for ROOM









  • No longer modeling separate primary key - derived from foreign key











  • Separate table created to hold foreign keys

  • Can be used for all relationship enumatations and directions


  • Join table name either derived from associated tables or explicitly named

  • Join table columns either derived from referenced table column or explicitly named


  • Unique constraint enforces the (1)-to-Many aspect of relationship









Uni-directional

Only one side ("owner") knows of the relationship

  • Uses the @ManyToMany annotation

  • Defines mapping to database

    • Must use @JoinTable

Bi-directional

Both classes know of the relationship

  • One side required to be owning side and maps relation to the database

    • Uses the @ManyToMany annotation

    • Must use @JoinTable

    • Changes here change the database

  • One side required to be inverse and names the other entity's property

    • @ManyToMany(mappedBy="owning-property")

    • Changes here do *not* change database





  1. Rows added to join table rather than updating entity class tables with foreign key




  • Owning and inverse sides now both need to be set



  • Parent defines default mapping for all derived types


  • Supplies type-specific column value


  • Accepts default type-specific column value


  • Two rows inserted into single base table with discriminator type supplied


  • Single table queried for objects


  • Single table "sparsely" filled based on type


  • Parent defines default mapping for all derived types, including PK generation

  • Using a common SEQUENCE allows sub-classes to have unique PKs across all tables


  • Subclasses name their specific entity class table


  • Rows for entities placed into separate tables


  • Query through parent type causes SQL "UNION ALL" of each concrete sub-class table


  • Table per concrete class

  • No unused columns

  • Parent columns repeated in each sub-class table


  • Each persist() must insert into concrete class table and parent class table(s)


  • Parent class table joined with each sub-class table during query of parent type


  • Entities span multiple tables


  • Parent class is not a legal entity -- has no @Id

Note

In this example, the implementation of BaseObject actually has an id attribute that the derived classes make use of. However, it is marked as @Transient in the base class and @Id in the derived Entity classes since MappedSuperClasses do not have primary keys. This specific example could have also used TABLE_PER_CLASS because of the availability of an id property in the base class.


  • "version" column name from parent being renamed

  • "id" property defined in this class given custom column name

  • Transient attribute in parent being reused to hold @Id for subclass using PROPERTY access


  • Entity accepts mapping defaults


  • Rows are inserted into type-specific entity class tables


  • Separate tables are accessed when obtaining each type


  • Separate tables per concrete class (like TABLE_PER_CLASS)

  • No unused columns (like TABLE_PER_CLASS)

Table of Contents

Purpose
1. Goals
2. Objectives
I. General Queries
68. JPA Query Types
68.1. JPA Query Language (JPA-QL) Queries
68.2. Native SQL Queries
68.2.1. SqlResultSetMappings
68.3. Criteria API Queries
68.4. Strongly Typed Queries
68.4.1. Metamodel API
68.4.2. Query using JPA Metamodel
68.4.3. Canonical Metamodel
68.4.4. Generating Canonical Metamodel Classes
68.5. Summary
69. JPA Query Overview
69.1. EntityManager Query Methods
69.2. Query.getSingleResult()
69.3. Query.getResultList
69.4. Parameters
69.5. Paging Properties
69.6. Pessimistic Locking
69.7. Bulk Updates
69.8. Named Queries
69.9. Summary
II. JPAQL
70. JPA Query Language
70.1. Simple Entity Query
70.2. Non-Entity Queries
70.3. Multi-select Query
70.3.1. Multi-select Query with Object[]
70.3.2. Multi-select Query with Tuple
70.3.3. Multi-select Query with Constructor
70.4. Path Expressions
70.4.1. Single Element Path Expressions
70.4.2. Collection Element Path Expressions
70.5. Eager Fetching through JOINs
70.5.1. Lazy Fetch Problem
70.5.2. Adding Eager Fetch during Query
70.6. Distinct Results
70.7. Summary
71. JPAQL Where Clauses
71.1. Equality Test
71.2. Like Test
71.3. Formulas
71.4. Logic Operators
71.5. Equality Tests
71.6. Between
71.7. Testing for Null
71.8. Testing Empty Collection
71.9. Membership Test
71.10. Subqueries
71.11. All
71.12. Any
71.13. Summary
72. JPAQL Functions
72.1. String Functions
72.1.1. Base Query
72.1.2. LOWER
72.1.3. UPPER
72.1.4. TRIM
72.1.5. CONCAT
72.1.6. LENGTH
72.1.7. LOCATE
72.1.8. SUBSTRING
72.2. Date Functions
72.3. Order By
72.4. Aggregate Functions
72.4.1. COUNT
72.4.2. MIN/MAX
72.4.3. SUM/AVE
72.5. Group By
72.6. Having
72.7. Summary
III. Criteria API
73. JPA Criteria API
73.1. Criteria API Demo Template
73.2. Simple Entity Query
73.3. Non-Entity Query
73.4. Multi-select Query
73.4.1. Multi-select Query with Object[]
73.4.2. Multi-select Query with Tuple
73.4.3. Multi-select Query with Constructor
73.5. Path Expressions
73.5.1. Single Element Path Expressions
73.5.2. Collection Element Path Expressions
73.6. Eager Fetching through JOINs
73.6.1. Lazy Fetch Problem
73.6.2. Adding Eager Fetch during Query
73.7. Distinct Results
73.8. Summary
74. Criteria Where Clauses
74.1. Equality Test
74.2. Like Test
74.2.1. Like Test Literal
74.2.2. Like Test Literal Parameter
74.2.3. Like Test Concatenated String
74.2.4. Like Test Single Character Wildcard
74.3. Formulas
74.4. Logic Operators
74.5. Equality Tests
74.6. Between
74.7. Testing for Null
74.8. Testing Empty Collection
74.9. Membership Test
74.10. Subqueries
74.11. All
74.12. Any
74.13. Summary
75. Criteria Functions
75.1. String Functions
75.1.1. Base Query
75.1.2. LOWER
75.1.3. UPPER
75.1.4. TRIM
75.1.5. CONCAT
75.1.6. LENGTH
75.1.7. LOCATE
75.1.8. SUBSTRING
75.2. Date Functions
75.3. Order By
75.4. Aggregate Functions
75.4.1. COUNT
75.4.2. MIN/MAX
75.4.3. SUM/AVE
75.5. Group By
75.6. Having
75.7. Summary

Three fundamental query types within JPA

  • JPA Query Language (JPA) - entity/property/relationship-based

  • Native SQL - table/column-based

  • Criteria API - entity/property/relationship-based using Java classes


  • "c" is part of root query

  • "c" represents rows from Customer entity table(s)

  • "c.lastName" is path off root term

  • ":firstName" is parameter placeholder

  • "c.firstName" is path off root term

  • "Customer.class" type parameter allows for a type-safe return result


  • Placeholder is replaced by runtime parameter

  • Zero-or-more results are requested

  • Entities returned are managed



  • "c" represents rows in table

  • specific columns (or *) are return for each row

  • "?" marks a positional parameter -- non-portable to use named parameters in native SQL queries

  • TypedQuery<T>s not supported in native SQL queries because of a conflict with legacy JPA 1.0 API


  • Query execution similar to other query types

  • User-provided SQL executed

Note

Legacy JPA 1.0 Native SQL query syntax already used the signature of passing in a Class for createNativeQuery(). In this context, it was an entity class that contained JPA mappings for the query -- not the returned entity type. This prevented createNativeQuery() from being updated to return a typed result in JPA 2.0.







  • "CriteriaBuilder" used as starting point to build objects within the query tree

  • "CriteriaQuery<T>" used to hold the definition of query

  • "Root<T>" used to reference root level query terms

  • "CriteriaBuilder.from()" used to designate the entity that represents root query term

    • Result used to create path references for query body

  • "CriteriaBuilder.select()" officially lists the objects returned from query

  • "CriteriaBuilder.where()" builds a decision predicate of which entities to include

  • "CriteriaBuilder.equal()" builds an equals predicate for the where clause

  • "Root<T>.get()" returns the property referenced in path expression

  • "CriteriaBuilder.parameter()" builds a parameter placeholder within query. Useful with @Temporal date comparisons


  • Query execution identical to JPA-QL case



  • Access to properties within entities done through type-safe accessors


  • Results identical to previous approaches



  • Construct or generate a canonical metamodel class to provide type-safe, easy access to properties


  • Use canonical metamodel class to provide type-safe, easy access to properties ("Customer_.firstName")


  • Result is identical to previous approaches


  • More work to get here but clean, result

  • Type-safe - queries will not compile if entity changes





  • :firstName and :lastName act as placeholders for runtime query parameters

  • Runtime parameters supplied using placeholder names

  • A parameter for each placeholder must be supplied - no defaults

  • A placeholder must exist for each parameter supplied - no extras


  • Appended numbers (?1) assign an ordinal value

  • No numbers supplied (?) cause default value based on order


  • Dates are specified as DATE, TIME, or TIMESTAMP


  • Change directly applied to database, not the cached entity

  • Number of entities changed returned



  • Bulk deletes do not trigger cascades

  • Entity instance exists in memory even after deleted from database



  • Keeping stale entities around will produce confusing results

  • "em.clear()" should be avoided except at end of transaction since un-manages everything




  • Example query uses Native SQL to return all columns for table



  • Individual elements of select are matched up against class constructor


  • Constructed class may be simple POJO -- no need to be an entity

  • Instances are not managed

  • Suitable for use as Data Transfer Objects (DTOs)


  • Each row returned as instance of provided class


  • A normal JOIN (implicit or explicit) may honor the fetch=LAZY property setting of the relation

  • Can be exactly what is desired

  • Can also cause problems or extra work if not desired


  • Sales are lazily fetched when obtaining Store


  • Accessing the Sale properties causes a LazyInitializationException when persistence context no longer active or accessible

One Row per Parent is Returned for fetch=LAZY

Note that only a single row is required to be returned from the database for a fetch=LAZY relation. Although it requires more queries to the database, it eliminates duplicate parent information for each child row and can eliminate the follow-on query all together when not accessed.








  • Compare entities and not primary/foreign key values


Can be used to determine membership in a collection


  • Defines a shorthand for a subquery




  • List all clerks that have all sales above $125.00 or none at all

  • -or- List all clerks with no sale <= $125.00


  • Manny excluded because has 1 sale below $125.00

  • Moe included because has only $150.00 sale

  • Jack included because has no sales that fail criteria


  • List all clerks that have all sales below $125.00 or none at all

  • -or- List all clerks with no sale >= $125.00


  • Manny excluded because has 1 sale above $125.00

  • Moe excluded because has only $150.00 sale

  • Jack included because has no sales that fail criteria


  • List all clerks that have at least one sale above $125.00


  • Manny included because has 1 sale above $125.00

  • Moe included because $150.00 sale qualifies him as well

  • Jack excluded because has no sales that meet criteria


  • List all clerks that have at least one sale below $125.00


  • Manny included because has 1 sale below $125.00

  • Moe excluded because his only $150.00 sale above criteria

  • Jack excluded because has no sales that meet criteria


  • Located two Sales that occurred prior to today's date


  • Located no sales on today's date


  • Update all sales to today


  • Now locating sales for today's date

Note

Bulk commands (i.e., update) invalidate cached entities. You must refresh their state with the database or detach/clear them from the persistence context to avoid using out-dated information.



  • Aliases may be assigned to select terms for named-access to results


  • Query defined to return instances of Tuple class

  • Tuples provide access using

    • get(index) - simular to Object[]

    • get(index, Class<T> resultType) - typed access by index

    • get(alias) - access by alias

    • get(alias, Class<T> resultType) - typed access by alias

    • getElements() - access thru collection interface




  • Individual elements of select() are matched up against class constructor


  • Constructed class may be simple POJO -- no need to be an entity

  • Instances are not managed

  • Suitable for use as Data Transfer Objects (DTOs)




  • All paths based off root-level FROM (or JOIN) terms

  • Paths use call chaining to change contexts

  • Paths -- used this way -- must always express a single element. Must use JOINs for paths involving collections

  • All paths based off root-level FROM (or JOIN) terms



  • Automatic INNER JOIN formed between Sale and Store because of the cross-entity path



  • A normal JOIN (implicit or explicit) may honor the fetch=LAZY property setting of the relation

  • Can be exactly what is desired

  • Can also cause problems or extra work if not desired


  • Sales are lazily fetched when obtaining Store


  • Accessing the Sale properties causes a LazyInitializationException when persistence context no longer active or accessible


One Row per Parent is Returned for fetch=LAZY

Note that only a single row is required to be returned from the database for a fetch=LAZY relation. Although it requires more queries to the database, it eliminates duplicate parent information for each child row and can eliminate the follow-on query all together when not accessed.













  • Compare entities and not primary/foreign key values



Can be used to test for an empty collection




  • Sub-select returns values from collection under test

  • Outer query tests for no existing (EMPTY)values




  • Sub-select returns values from collection under test

  • Outer query tests for existing (NOT EMPTY)values

Can be used to determine membership in a collection



  • Defines a shorthand for a subquery





  • List all clerks that have all sales above $125.00 or none at all

  • -or- List all clerks with no sale <= $125.00


  • Manny excluded because has 1 sale below $125.00

  • Moe included because has only $150.00 sale

  • Jack included because has no sales that fail criteria



  • List all clerks that have all sales below $125.00 or none at all

  • -or- List all clerks with no sale >= $125.00


  • Manny excluded because has 1 sale above $125.00

  • Moe excluded because has only $150.00 sale

  • Jack included because has no sales that fail criteria



  • List all clerks that have at least one sale above $125.00


  • Manny included because has 1 sale above $125.00

  • Moe included because $150.00 sale qualifies him as well

  • Jack excluded because has no sales that meet criteria



  • List all clerks that have at least one sale below $125.00


  • Manny included because has 1 sale below $125.00

  • Moe excluded because his only $150.00 sale above criteria

  • Jack excluded because has no sales that meet criteria




  • Located two Sales that occurred prior to today's date




  • Located no sales on today's date

  • Update with a bulk query

Note

Criteria API added Bulk Updates in JPA 2.1




  • Update all sales to today




  • Now locating sales for today's date

Note

Bulk commands (i.e., update) invalidate cached entities. You must refresh their state with the database or detach/clear them from the persistence context to avoid using out-dated information.

Table of Contents

Topics
76. SQL Tuning
76.1. Reasons for Inefficient SQL Performance
76.2. Execution Plan
76.3. Diagnostic Tools
76.3.1. Client/DAO Result
76.3.2. EXPLAIN PLAN
76.3.3. AUTOTRACE
76.3.4. Display Cursor Execution Plan within V$PLAN
76.4. Summary
77. Example Domain Model: Movies
77.1. Class Model
77.2. Database Schema
77.3. Database Size
77.4. Prepare DB Between Tests
78. Table Access
78.1. Full Table Scan
78.1.1. Full Table Scan: Unconstrained Access
78.1.2. Full Table Scan: Using Where (without Index)
78.1.3. RowId Scan: Using Where (with Index)
78.1.4. Full Table Scan: Invalidating Index using Function applied to Row Column
78.1.5. RowId Scan: Using Index with Function applied to Row Column
78.1.6. Full Table Scan: Invalidating Index by using Leading Wildcards
78.2. Order By
78.2.1. Order By using Sort
78.2.2. Order By using Index
78.2.3. Order By using Index DESC
78.2.4. Order By using Reverse Index DESC
78.3. Summary
79. Indexes
79.1. Index Range Scan
79.2. Unique Index Scan
79.3. Composite Index
79.3.1. Query Parts
79.3.2. First Term Indexed
79.3.3. First and Second Term Indexed (using Composite Index)
79.4. Index Fast Full Scan (with Composite Index)
79.4.1. Query Parts
79.4.2. Option: Use Range Scan and RowId Access
79.4.3. Option: Use Range Scan Alone with Composite Index
79.4.4. Option: Fast Full Scan
79.5. Summary
80. Joins
80.1. Foreign Keys
80.1.1. Query Parts
80.1.2. No Indexes
80.1.3. Perform Query with Support for Foreign Key Index
80.1.4. Foreign Key and Where Columns Indexed
80.1.5. Foreign Key, Where, and Join Columns Indexed
80.2. Join Types
80.2.1. Nested Loop Join
80.2.2. Hash Join
80.2.3. Sort Merge Join
80.3. Summary
81. JPA
81.1. Lazy and Eager Fetching
81.1.1. Get Parent
81.1.2. Get Parent and Children
81.2. Obtaining Instance Counts
81.2.1. Query Parts
81.2.2. Collection Size in DAO from Relation
81.2.3. Row Count in DAO from Query
81.2.4. Row Count in DB using Count() Query
81.2.5. Row Count in DB using Count Query without JOIN
81.3. Query Loops
81.3.1. Query Parts
81.3.2. Query Loops in DAO
81.3.3. Query Loops using DB Subquery
81.4. Paging
81.4.1. Query Parts
81.4.2. Paging within DAO
81.4.3. Paging within DB
81.5. Summary
82. H2 Execution Plans
82.1. Column Index
82.2. Summary
83. JPA/SQL Tuning Summary
83.1. Other Topics

Figure 76.3. EXPLAIN PLAN Example using Text SQL Commands

 
EXPLAIN PLAN FOR
select * from
    ( select
        movie0_.TITLE as col_0_0_,
        person2_.FIRST_NAME as col_1_0_,
        person2_.LAST_NAME as col_2_0_ 
    from JPATUNE_MOVIE movie0_ 
    inner join JPATUNE_DIRECTOR director1_ on movie0_.DIRECTOR_ID=director1_.PERSON_ID 
    inner join JPATUNE_PERSON person2_ on director1_.PERSON_ID=person2_.ID 
    order by title DESC ) 
where
    rownum <= :limit;
SET LINESIZE 100
SET PAGESIZE 0
select * from table(DBMS_XPLAN.DISPLAY());
plan FOR succeeded.
Plan hash value: 857441453
 
----------------------------------------------------------------------------------------------------
| Id  | Operation                 | Name           | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT          |                |   774K|   477M|       | 25766   (1)| 00:05:10 |
|*  1 |  COUNT STOPKEY            |                |       |       |       |            |          |
|   2 |   VIEW                    |                |   774K|   477M|       | 25766   (1)| 00:05:10 |
|*  3 |    SORT ORDER BY STOPKEY  |                |   774K|    45M|    53M| 25766   (1)| 00:05:10 |
|*  4 |     HASH JOIN             |                |   774K|    45M|    11M| 14333   (1)| 00:02:52 |
|*  5 |      HASH JOIN            |                |   271K|  8746K|  5568K|  5115   (1)| 00:01:02 |
|   6 |       INDEX FAST FULL SCAN| DIRECTOR_PK    |   271K|  2385K|       |   191   (1)| 00:00:03 |
|   7 |       TABLE ACCESS FULL   | JPATUNE_PERSON |  1637K|    37M|       |  1854   (1)| 00:00:23 |
|*  8 |      TABLE ACCESS FULL    | JPATUNE_MOVIE  |   774K|    20M|       |  7169   (1)| 00:01:27 |
----------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter(ROWNUM<=TO_NUMBER(:LIMIT))
   3 - filter(ROWNUM<=TO_NUMBER(:LIMIT))
   4 - access("MOVIE0_"."DIRECTOR_ID"="DIRECTOR1_"."PERSON_ID")
   5 - access("DIRECTOR1_"."PERSON_ID"="PERSON2_"."ID")
   8 - filter("MOVIE0_"."DIRECTOR_ID" IS NOT NULL)






  • Access paths - strategies used to access data within table

  • Indexes - good for when accessing small amounts of data out of much larger data set

  • Full table scans - good for small tables and unrestricted row access

  • Any row can be *functionally* accessed with either method

  • Use execution plans to help use the appropriate technique

Database engine derives all information from the table directly from the physical storage location for the table. Table storage is not arranged in any guaranteed order.

Order returned results by one or more columns

  • Can be unique or non-unique

  • Can be simple or composite

  • Can be normal (ascending) or descending

  • Can be reverse key (for monotonically incrementing column values) to balance B*-tree

  • Can be function-based (to address normalization uses)

  • Can be used to implement sort for "order by"

  • Can be used to implement the entire table (Index-organized Table(IOT))

  • Can be traversed in different ways

    • Unique Scan - used with "unique" or "primary key" indexes to return a single value

    • Range Scan - used with "unique" and "non-unique" indexes to return multiple matching rows

    • Full Scan - used with composite indexes where leading where column is not part of index (i.e., can use col2 of composite)

    • Fast Full Scan - used when all columns of query (where and select) are contained within composite index -- table is skipped

    • ...

  • Can be coalesced or rebuilt with

    ALTER INDEX (index-name) (COALESCE | REBUILD)
    • Coalesce - repairs index in place. Good for small repairs

    • Rebuild - totally rebuilds index. Good for large repairs

Indexes with multiple columns to match the where clause and optionally the select and join clauses as well.

Incorporate terms from select clause into composite index to bypass table access.

Improving performance of foreign key joins.

Used when driving table is small and join condition used to access second table

Used when driving table too large to fit into memory and join based on equality

Avoiding inefficient uses of JPA.

Cost impacts of lazy and eager fetch joins

Get just the root parent of an object graph

Get just the root parent of an object graph with fetch=LAZY relationships


  • Two one-to-many relationships (cast and genres) -- genres is a non-entity ElementCollection

  • One one-to-one relationship (director)

  • All use fetch=LAZY


  • Only parent table is queried

  • Children are lazily loaded


  • Unique scan of Movie primary key index to satisfy where clause and locate rowId

  • Row access by rowId to satisfy select clause


* "Thick" parent has an extra Movie.plot text property mapped to potentially make child joins more expensive. Thin parent does not have Movie plot mapped so the results can focus on access to smaller, related entities.

Fetch=LAZY Speeds Access to Single Entity Core Information

Choosing fetch=LAZY for relationships allows efficient access to the core information for that entity without paying a price for loading unnecessary relations.

Get just the root parent of an object graph with fetch=EAGER relationships

Figure 81.8. Relationships


<entity class="ejava.jpa.examples.tuning.bo.Movie">
    <attributes>
        <many-to-one name="director" fetch="EAGER">
            <join-column name="DIRECTOR_ID"/>
        </many-to-one>
        <one-to-many name="cast" fetch="EAGER" mapped-by="movie"/>
        
        <element-collection name="genres" fetch="EAGER">
            <column name="GENRE"/>
            <collection-table name="JPATUNE_MOVIEGENRE">
                <join-column name="MOVIE_ID"/>
                <unique-constraint>
                    <column-name>MOVIE_ID</column-name>
                    <column-name>GENRE</column-name>
                </unique-constraint>
            </collection-table>
        </element-collection>

        <transient name="plot"/>
    </attributes>
</entity>
public class MovieRole {

...
    @ManyToOne(optional=false, fetch=FetchType.LAZY,
            cascade={CascadeType.DETACH})
    @JoinColumn(name="ACTOR_ID")
    private Actor actor;

<entity class="ejava.jpa.examples.tuning.bo.MovieRole">
    <attributes>
        <many-to-one name="actor" fetch="EAGER">
            <join-column name="ACTOR_ID"/>
        </many-to-one>
    </attributes>
</entity>
public class Actor {

...
    @OneToOne(optional=false, fetch=FetchType.EAGER,
            cascade={CascadeType.PERSIST, CascadeType.DETACH})
    @MapsId
    @JoinColumn(name="PERSON_ID")
    private Person person;
public class Director {

...
    @OneToOne(optional=false, fetch=FetchType.EAGER,
            cascade={CascadeType.PERSIST, CascadeType.DETACH})
    @JoinColumn(name="PERSON_ID")
    @MapsId
    private Person person;

  • Movie.director, Movie.genres, Movie.cast relationships overridden in XML to be fetch=EAGER

  • MovieRole.actor relationship overridden in XML to be fetch=EAGER

  • Director.person and Actor.person already fetch=EAGER


  • Single query (as before), but this time it also brings in the entire object graph


  • Explain plan shows use of indexes and no full table scans (a missing FK index for MovieRole.movie could have been costly)

  • Execution plan is significantly more costly than lazy alternative


Fetch=EAGER for Single Entity adds Noticeable Overhead

Choosing fetch=EAGER for relationships will make access to a single entity within the relationship more expensive to access. Consider creating a value query, value query with a result class, or a native query when querying for only single entity under these conditions.

Get just the root parent and *ONLY* the parent of an object graph with fetch=EAGER relationships by using a NativeQuery and Result Class



  • We define an alternate JPA-QL query for provider to use that does not include relationships

  • Result class not mapped beyond this query -- does not have to be an entity class


  • Value query with result class constructor permits a bypass of fetch=EAGER relationships


  • Execution plan identical to fetch=LAZY case


* Thick/Thin or Eager/Lazy should not matter to this approach since we only access a specific set of fields in the Movie that does not include Movie.plot.

Use JPA Value or Native Queries to Override Relationship Definitions

JPA provides many escape hatches to achieve desired results. Use JPAQL value queries with Object[], Tuple, or custom result class -or- use SQL to provide efficient override of fetch=EAGER definitions.

Result Class Instances are not Managed

Even though we used an entity class in this example, it is being used as a simple POJO and the returned instance is not managed. Result Classes for value queries provide convenient type-safe access to results. However, they are unmanaged and cannot be used for follow-on entity operations.

Get parent and children in an object graph

Get parent and children in an object graph with fetch=LAZY relationships

Get parent and children in an object graph with JOIN FETCH query



  • EAGER aspects adding by query adding FETCH to JOIN query construct


  • Query identical to fetch=EAGER case



Make use of JPA Queries to Achieve Tuned-for-Use Query

JPA provides several means to access an entity and its relationships. The properties defined for the relationship help define the default query semantics -- which may not be appropriate for all uses. Leverage JOIN FETCH queries when needing to fully load specific relationships prior to ending the transaction.

Pulling back entire rows from table rather than just the count

Get size of a relationship collection.


  • DAO first gets Movie by primary key

  • DAO follows up by accessing size of relationship


  • Provider will issue follow-on query for all entities in relation

  • Entity data not used by DAO -- i.e. wasted


  • Provider will issue one query for entire object graph, to include entities in relation

  • Entity data not used by DAO -- i.e. even more data is wasted


Using Relation Collections to Just Obtain Size is Inefficient

Pulling back relationship graphs to just obtain the count in that relationship is inefficient and requires DB to do much more work than it has to.

Query for relationships and count resulting rows


  • DAO forms query for just related entities


  • Provider forms query for related entities


  • Provider forms query for related entities and fetch=EAGER relationship specification causes additional MovieRole.actor to be immediately obtained -- except through separate queries by primary key.


Using fetch=EAGER Relationships can Magnify Data Retrieval Issues

When the entity model over-uses fetch=EAGER, the negative results can be magnified when pulling back unnecessary information from the database.

Performing separate subqueries off initial query

Using DAO to perform initial query and follow-on queries based on results


  • DAO makes N separate queries based on results of first query

  • Distinct was not required in query since it was issued per-movie. Distinct was handed within the DAO using a Java Set to hold the results and hashcode()/equals() implemented within Person class.


  • SQL generated queries single table


  • Range scan of compound index(actor_id, person_id) used to satisfy the person_id in where clause and movie_id for select clause

* Query was optimized to bypass Actor table


  • Range scan on compound_index(movie_id, actor_id) to satisfy where condition for Movie.id and locate MovieRole rowId

  • Unique scan of Person primary key index to obtain rowId for Person.id=MovieRole.actor.id

  • Person row accessed by rowId to satisfy select clause

* Query was optimized to bypass Actor table

** Compound index(movie_id, actor_id) permitted MovieRole table and lookup of MovieRole.actorId to be bypassed.


Beware of Query Loops Driven from Query Results

Query loops driven off of previous query results can be a sign the follow-queries could have been combined with the initial query to be accomplished within the database within a single statement.

Also beware of how the loop size can grow over the lifetime of the application. The number may grow significantly after testing/initial deployment to a significant size (i.e., from 100 to 100K loops). Defining as a single statement and applying paging limits can help speed the originally flawed implementation.

Expressing nest query as subquery to resolve within database.


  • Distinct was required to remove duplicates


  • SQL generated uses a non-correlated subquery


  • Range scan of MovieRole composite(actor_id, movie_id) used to satisfy subquery where clause for person_id and obtain movie_id

  • Range scan of MovieRole composite(movie_id, actor_id) used to join movie_ids with root query and obtain person_id

  • Unique scan of Person primary key index to locate rowId

  • Person row accessed by rowId

* cast4_ and movierole0_ are both MovieRoles. cast4_ is joined with Movie and subject Person in subquery. movierole0_ is joined with Movie and associated Person in root query.

** execution plan indicates subquery could have been re-written as a JOIN


Delegate Query Logic to Database

If possible, express query as a single transaction to the database rather than pulling data back and re-issuing subqueries from the DAO. Apply paging constraints in order to address issues with excess growth over time.

Placing reasonable limits on amount of data returned

Implementing paging within the DAO

Figure 81.66. DAO Code/JPAQL

public Collection<Person> oneStepFromPersonByDAO(Person p, Integer offset, Integer limit, String orderBy) {

    Collection<Person> result = new HashSet<Person>();
    //performing core query
    List<String> movieIds = createQuery(
            "select role.movie.id from MovieRole role " +
            "where role.actor.person.id=:personId", String.class)
            .setParameter("personId", p.getId())
            .getResultList();
    
    //loop through results and issue sub-queries
    int pos=0;
    for (String mid: movieIds) {
        List<Person> people = createQuery(
                "select role.actor.person from MovieRole role " +
                "where role.movie.id=:movieId", Person.class)
                .setParameter("movieId", mid)
                .getResultList();
        if (offset==null || (offset!=null && pos+people.size() > offset)) {
            for(Person pp: people) {
                if (offset==null || pos>=offset) {
                    result.add(pp);
                    if (limit!=null && result.size() >= limit) { break; }
                }
                pos+=1; 
            }
        } else {
            pos+=people.size();
        }
        if (limit!=null && result.size() >= limit) { break; }
    }
    return result;
}

  • DAO logic gets complicated when self-implementing paging.

  • OrderBy is not implemented by this DAO algorithm. All rows in the table would be required in order to perform ordering within the DAO.




  • This example performs better or equal to previous loop/subquery example when earlier pages are requested -- thus fewer rows returned

  • fetch=EAGER/LAZY have no impact on this test since the entity queried for has no relationships

Performance Degrades in DAO as Row Sizes Increase

Paging within the Java code starts off near equivalent to the database solution for small row sizes but gradually gets worse when row sizes increase and later pages are requested.

Implementing paging within the database


  • JPA calls to TypedQuery.setFirstResult(), setMaxResults(), and adding the orderBy to the text of the query are abstracted behind withQuery() and createQuery() helper functions within the DAO example class and are not shown here


  • Generated SQL is essentially the same as the looping/subquery example except with the addition of "order by" and paging constructs.


  • Execution plan is similar as described in the looping/subquery example

  • Extra cost to sort rows prior to paging operation added


DB-based Paging Scales

Since only the requested page of rows is returned, delegating paging to the database provides consistent performance for varying row quantities.

Doing Paging within DB enables Sorting

Implementing paging across multiple subquery calls to the database can get ugly and error-prone. Implementing paging for a single query issued to the database is quite trivial.




  • Performs stateless actions on server-side

  • Maintains no conversational state

    • Each method ignorant of what went before it and after it

    • Persistence Context re-instantiated with each call (Transaction-Scope)

  • Methods take in a set of parameters and return a result

  • Maintains implementation state

    • example: DataSource

    • example: JMS connections

    • example: References to other EJBs

  • Examples:

    • TaxCalculator.calcTax(doubt amount)

    • BuyerMgmt.placeBid(int auctionId, double amount)

    • Dmv.getExpiredLicenses()

  • Good for implementing stateless access to resources

  • Contains no means to provide individualized access other than through separate deployments and call parameters


Figure 85.5. Example Stateful EJB

@javax.ejb.Stateful

public class ReservationEJB implements ReservationRemote {
    @PersistenceContext(unitName="ejbjpa-hotel", type=PersistenceContextType.EXTENDED)
    private EntityManager em;
    
    @EJB
    private HotelMgmtLocal hotelMgmt;
    
    @Resource
    private SessionContext ctx;
    
    private List<Guest> guests = new LinkedList<Guest>();
    @Override
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public int addGuest(Guest guest) {
        if (guest!=null) {
            guests.add(guest);
            em.persist(guest); //<== no transaction active yet
        }
        return guests.size();
    }
    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Remove
    public List<Guest> reserveRooms() throws RoomUnavailableExcepton {
        List<Room> rooms = hotelMgmt.getAvailableRooms(null, 0, guests.size());
        if (rooms.size() < guests.size()) {
            //no rollback needed, we didn't do anything
            throw new RoomUnavailableExcepton(String.format("found on %d out of %d required", 
                    rooms.size(), guests.size()));
        }
        //assign each one of them a room
        List<Guest> completed = new ArrayList<Guest>(guests.size());
        Iterator<Room> roomItr = rooms.iterator();
        for (Guest guest: guests) {
            Room room = roomItr.next();
            try {
                //the room could be unavailable -- depending on whether pessimistic lock created
                guest = hotelMgmt.checkIn(guest, room); //<== will attempt to also persist guest
                completed.add(guest);
            } catch (RoomUnavailableExcepton ex) {
                //rollback any previous reservations
                ctx.setRollbackOnly();
                throw ex;
            }
        }
        return completed;
    }
}

  • Used to cache resources for client on server-side

  • Maintains conversational state

    • Object can cache values between calls

      • example: iterator

      • Persistence Context (with cache of entities) can be retained between calls (Extended-Scope)

    • Lifetime ends on timeout or specific client call

  • Maintains implementation state

    • Not sharable between clients

    • All resources allocated to perform work for one instance

  • Able to react to transaction completion/rollback (i.e., get callback)

    • example: commit data cache

    • example: issue message

  • Good for caching client state and back-end resource state over a multi-call session

  • Inefficient to scale cached state for each user and across multiple servers


  • Used to receive JMS messages

  • Similar to Stateless EJB, but with no callable interface

  • Typically provides a JMS facade for injected Session EJBs

  • Good for implementing a JMS interface facade to business logic

  • Unable to be called outside the scope of a JMS/JCA call -- should delegate to Session EJBs

  • Has no client context (i.e., anonymous)

Figure 85.13. Example JAX-RS Interface



import java.net.URI;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
@Path("/products")
public class ProductsResource {
        @Inject
        private InventoryMgmtEJB ejb;
        @Context 
        private UriInfo uriInfo;
        @POST @Path("")
        @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
        @Produces(MediaType.APPLICATION_XML)
        public Response createProduct(
                        @FormParam("name") String name,
                        @FormParam("quantity") Integer quantity,
                        @FormParam("price") Double price,
                        @FormParam("category") String category) {
             Product product = new Product(name, quantity, price);
             Product p = ejb.addProduct(product, category);
             URI uri = UriBuilder.fromUri(uriInfo.getAbsolutePath())
                                     .path(ProductsResource.class, "getProduct")
                                     .build(p.getId());
             return Response.created(uri)
                             .entity(p)
                             .build();
        }
}

  • EJBs are based on Plain Old Java Objects (POJOs)

  • Standard POJO rules apply...

$ mvn clean test                        
...
[INFO] Deleting .../ejb-basic-ejb/target
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ ejb-basic-ejb ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory .../ejb-basic-ejb/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ ejb-basic-ejb ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 5 source files to .../ejb-basic-ejb/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ ejb-basic-ejb ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ ejb-basic-ejb ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to .../ejb-basic-ejb/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.17:test (default-test) @ ejb-basic-ejb ---
[INFO] Surefire report directory: .../ejb-basic-ejb/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running info.ejava.examples.ejb.basic.pojo.GreeterTest
16:57:12,237 INFO  (GreeterTest.java:41) -*** dto ***
16:57:12,243 DEBUG (GreeterEJB.java:41) -sayHello(Name [firstName=thing, lastName=one])
16:57:12,249 INFO  (GreeterTest.java:27) -*** pojoGreeter ***
16:57:12,250 DEBUG (GreeterEJB.java:27) -sayHello(cat inhat)
16:57:12,252 INFO  (GreeterTest.java:35) -*** badName ***
16:57:12,255 DEBUG (GreeterEJB.java:27) -sayHello()
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.239 sec - in info.ejava.examples.ejb.basic.pojo.GreeterTest

Results :

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.815 s
...
  • Add essential EJB aspects to POJO classes

  • Deploy to server and test

17:19:52,979 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) 
JNDI bindings for session bean named GreeterEJB in deployment unit deployment "ejb-basic-ejb.jar" are as follows:

        java:global/ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:app/ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:module/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:jboss/exported/ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:global/ejb-basic-ejb/GreeterEJB
        java:app/ejb-basic-ejb/GreeterEJB
        java:module/GreeterEJB

17:19:53,012 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016005: Starting Services for CDI deployment: ejb-basic-ejb.jar
17:19:53,029 INFO  [org.jboss.weld.deployer] (MSC service thread 1-2) JBAS016008: Starting weld service for deployment ejb-basic-ejb.jar
17:19:53,485 INFO  [org.jboss.as.server] (DeploymentScanner-threads - 1) JBAS018559: Deployed "ejb-basic-ejb.jar" (runtime-name : "ejb-basic-ejb.jar")
  • Useful when need to deploy EJB with dependent artifacts or without WAR

19:50:07,583 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) JNDI bindings for session bean named GreeterEJB in deployment unit subdeployment "ejb-basic-ejb.jar" of deployment "ejb-basic-ear-4.0.0-SNAPSHOT.ear" are as follows:

        java:global/ejb-basic-ear/ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:app/ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:module/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:jboss/exported/ejb-basic-ear/ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:global/ejb-basic-ear/ejb-basic-ejb/GreeterEJB
        java:app/ejb-basic-ejb/GreeterEJB
        java:module/GreeterEJB

19:50:07,588 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016005: Starting Services for CDI deployment: ejb-basic-ear-4.0.0-SNAPSHOT.ear
19:50:07,596 INFO  [org.jboss.weld.deployer] (MSC service thread 1-2) JBAS016008: Starting weld service for deployment ejb-basic-ear-4.0.0-SNAPSHOT.ear


<project>
    <groupId>info.ejava.examples.ejb.basicejb</groupId>
    <artifactId>ejb-basic-ear</artifactId>
    <packaging>ear</packaging>

    <dependencies>
        <!-- The EAR must have a scope=compile dependency on the EJB -->
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>ejb-basic-ejb</artifactId>
            <version>${project.version}</version>
            <type>ejb</type>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- provide properties here to impact the EAR packaging -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ear-plugin</artifactId>
                <configuration>
                    <defaultLibBundleDir>lib</defaultLibBundleDir>
                    <!-- eliminates use of version in EAR JNDI name portion -->
                    <applicationName>${project.artifactId}</applicationName>
                    <modules>
                        <!-- eliminates use of the version in the EJB JNDI name -->
                        <ejbModule>
                            <groupId>${project.groupId}</groupId>
                            <artifactId>ejb-basic-ejb</artifactId>
                            <bundleFileName>ejb-basic-ejb.jar</bundleFileName>
                        </ejbModule>
                    </modules>
                </configuration>
            </plugin>
        </plugins>
    </build>    
  • Useful in WAR deployments

20:47:51,929 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] 
(MSC service thread 1-2) JNDI bindings for session bean named GreeterEJB in deployment unit deployment "ejb-basic-war.war" are as follows:

        java:global/ejb-basic-war/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:app/ejb-basic-war/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:module/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:jboss/exported/ejb-basic-war/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
        java:global/ejb-basic-war/GreeterEJB
        java:app/ejb-basic-war/GreeterEJB
        java:module/GreeterEJB

20:47:51,970 INFO  [org.jboss.weld.deployer] (MSC service thread 1-2) JBAS016005: Starting Services for CDI deployment: ejb-basic-war.war
20:47:51,988 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016008: Starting weld service for deployment ejb-basic-war.war
20:47:52,353 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-1) JBAS017534: Registered web context: /ejb-basic-war
  • Unit tests test POJO classes in a single Maven phase

  • IT tests test components deployed to the server using multiple phases Maven Lifecycle Reference

    pre-integration-test

    Deploy artifacts

    integration-test

    Execute tests

    post-integration-test

    Undeploy artifacts

    verify

    Evaluate test results (possibly fail build after artifacts undeployed)

  • IT tests require remote access

    • Access Type

      • JBoss Remoting

      • EJB Client

    • JNDI Properties

    • JNDI Name

  • IT tests test EJB deployed to server

  • InitialContextFactory looks for custom naming extensions when encountering naming prefix ("ejb:")

  • java.naming.factory.url.pkgs lists base package names to start looking for extensions

  • jboss-ejb-client.jar must be in the classpath

$ mvn dependency:tree

[INFO] +- info.ejava.examples.common:jboss-rmi-client:pom:4.0.0-SNAPSHOT:test
[INFO] |  +- org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:jar:1.0.0.Final:test
[INFO] |  +- org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:jar:1.0.0.Final:test
[INFO] |  +- org.jboss:jboss-ejb-client:jar:2.0.1.Final:test
  • Provider looks for "ejb" extension below "org.jboss.ejb.client.naming" package

#jndi.properties
java.naming.factory.url.pkgs=org.jboss.ejb.client.naming
$ jar tf ~/.m2/repository/org/jboss/jboss-ejb-client/2.0.1.Final/jboss-ejb-client-2.0.1.Final.jar | grep org.jboss.ejb.client.naming
...
org/jboss/ejb/client/naming/ejb/SecurityActions$1.class
org/jboss/ejb/client/naming/ejb/EjbNamingContext$2.class
org/jboss/ejb/client/naming/ejb/EjbNamingContext.class
org/jboss/ejb/client/naming/ejb/EjbNamingContextSetup.class
org/jboss/ejb/client/naming/ejb/ejbURLContextFactory.class
org/jboss/ejb/client/naming/ejb/SecurityActions.class
org/jboss/ejb/client/naming/ejb/EjbJndiIdentifier.class
org/jboss/ejb/client/naming/ejb/EjbJndiNameParser.class
org/jboss/ejb/client/naming/ejb/SecurityActions$2.class
org/jboss/ejb/client/naming/ejb/SecurityActions$3.class
org/jboss/ejb/client/naming/ejb/EjbNamingContext$1.class
...

import static org.junit.Assert.*;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import info.ejava.examples.ejb.basic.dto.Greeting;
import info.ejava.examples.ejb.basic.dto.Name;
import info.ejava.examples.ejb.basic.ejb.BadRequestException;
import info.ejava.examples.ejb.basic.ejb.GreeterRemote;
...
public class GreeterIT {
    private static final Logger logger = LoggerFactory.getLogger(GreeterBase.class);
    protected Properties jndiProperties; // varies whether using Remoting or EJBClient
    protected String jndiName; // varies whether accessing EJB, WAR or EAR deployment and access
    protected Context jndi;
    protected GreeterRemote greeter;
    @Before
    public void setUp() throws Exception {
        jndi = new InitialContext(jndiProperties);
        greeter = (GreeterRemote) jndi.lookup(jndiName);
    }   
    @After
    public void tearDown() throws Exception {
        if (jndi != null) {
            jndi.close(); // produces errors with JBoss Remoting
        }   
    }   
$ mvn clean verify
...
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ ejb-basic-test ---
[INFO] Deleting .../ejb-basic-example/ejb-basic-test/target
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ ejb-basic-test ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ ejb-basic-test ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 4 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ ejb-basic-test ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 5 source files to .../ejb-basic-example/ejb-basic-test/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.17:test (default-test) @ ejb-basic-test ---
[INFO] 
[INFO] --- maven-jar-plugin:2.5:jar (default-jar) @ ejb-basic-test ---
[WARNING] JAR will be empty - no content was marked for inclusion!
[INFO] Building jar: .../ejb-basic-example/ejb-basic-test/target/ejb-basic-test-4.0.0-SNAPSHOT.jar
...

[INFO] --- cargo-maven2-plugin:1.4.3:redeploy (cargo-prep) @ ejb-basic-test ---
Sep 28, 2014 11:58:23 PM org.xnio.Xnio <clinit>
INFO: XNIO version 3.2.2.Final
Sep 28, 2014 11:58:23 PM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.2.2.Final
Sep 28, 2014 11:58:23 PM org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 4.0.3.Final

...
[INFO] --- maven-failsafe-plugin:2.17:integration-test (integration-tests) @ ejb-basic-test ---
[INFO] Failsafe report directory: .../ejb-basic-example/ejb-basic-test/target/failsafe-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------

Running info.ejava.examples.ejb.basicejb.ejbclient.GreeterRemotingWARIT
23:58:26,441 INFO  (GreeterIT.java:43) -using jndiName=ejb-basic-war/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
...
23:58:27,811 INFO  (GreeterIT.java:43) -using jndiName=ejb:ejb-basic-ear/ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
...
23:58:28,167 INFO  (GreeterIT.java:43) -using jndiName=ejb-basic-ear/ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
...
23:58:28,289 INFO  (GreeterIT.java:43) -using jndiName=ejb:/ejb-basic-war/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote

Results :

Tests run: 12, Failures: 0, Errors: 0, Skipped: 0

[INFO] 
[INFO] --- cargo-maven2-plugin:1.4.3:undeploy (cargo-post) @ ejb-basic-test ---
[INFO] 
[INFO] --- maven-failsafe-plugin:2.17:verify (verify) @ ejb-basic-test ---
[INFO] Failsafe report directory: .../ejb-basic-example/ejb-basic-test/target/failsafe-reports
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.036 s

Two primary ways to run the application server

  • Standalone. Can be local or remote

  • Embedded within IDE. Shares same JVM.


  • root-logger sets default versbosity to INFO

  • additional logger sets verbosity for info.ejava.* to DEBUG


  • EJB class used to create logger named after the class' fully qualified name

  • @PostConstruct logging at INFO level

  • business method logging at DEBUG level


  • Console configured (by default) to only output INFO and above


  • server.log will print all verbosity levels

  • Many/most build commands can be automated through Maven or other scripts

  • Used in interactive development and automated/headless builds

Plugin Page

  • Copies resource files from src tree to target tree

  • Can optionally "filter" variables and replace them with build time values (from environment's settings.xml)

  • Useful in customizing environment-specific properties

    • server URLs

    • server port#s


  • Source file uses variables to template source file


  • Concrete values are put in place for specific environment


  • Properties defined either within pom.xml, settings.xml, or -Dsystem-properties

  • includes/exclused aids in filtering wrong files

  • avoid filtering binary files -- corrupts them (Ant has same issue)

Plugin Page

  • Runs unit tests

  • Runs after tests compiled and before IT tests


  • Plugin always enabled by default. Declaration used only to customize

  • Configuration defines environment for JVM

  • Easy way to supply system properties (-Dsystem-property=value)

  • values can be hard-coded or use properties to allow easier overrides


  • Useful when turning off all unit tests to concentrate on IT tests

  • Can turn off problem test(s)


  • Just defining version here

Figure 92.8. Run Unit Tests

$ mvn clean test

...
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ ejb-basic-ejb ---
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ ejb-basic-ejb ---
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ ejb-basic-ejb ---
...
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ ejb-basic-ejb ---
...
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ ejb-basic-ejb ---
...
[INFO] --- maven-surefire-plugin:2.17:test (default-test) @ ejb-basic-ejb ---

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running info.ejava.examples.ejb.basic.pojo.GreeterTest
02:11:38,695 INFO  (GreeterTest.java:41) -*** dto ***
02:11:38,701 DEBUG (GreeterEJB.java:45) -sayHello(Name [firstName=thing, lastName=one])
02:11:38,707 INFO  (GreeterTest.java:27) -*** pojoGreeter ***
02:11:38,708 DEBUG (GreeterEJB.java:31) -sayHello(cat inhat)
02:11:38,711 INFO  (GreeterTest.java:35) -*** badName ***
02:11:38,713 DEBUG (GreeterEJB.java:31) -sayHello()
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.238 sec - in info.ejava.examples.ejb.basic.pojo.GreeterTest

Results :

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.871 s

  • Just definiing version here

Plugin Page

  • Manages deployment of components to containers

  • Not specific to JBoss/Wildfly

  • Specializations for Maven and JBoss/Wildfly

  • Can run embedded within each IT module build or use remote instance

  • Typically configured within module with IT tests


  • Plugin declaration enacts parent-defined behavior

  • Module specifies artifacts to deploy

  • Module specification is not required if deployment is self (i.e., the primary EJB/WAR/EAR produced by this module)


  • Used to simply undeploy module from server

  • Requires artifact to be present

  • Profile keeps behavior from running under conditions that would fail build

Figure 92.11. Parent Definition


<pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.codehaus.cargo</groupId>
            <artifactId>cargo-maven2-plugin</artifactId>
            <version>${cargo-maven2-plugin.version}</version>
            <configuration>
                <container>
                    <containerId>${cargo.containerId}</containerId>
                    <type>remote</type>
                    <log>target/server.log</log>
                    <output>target/output.log</output>
                </container>
                <configuration>
                    <type>runtime</type>
                    <properties>
                        <cargo.hostname>${jboss.mgmt.host}</cargo.hostname>
                        <cargo.jboss.management.port>${jboss.mgmt.port}</cargo.jboss.management.port>
                    </properties>
                </configuration>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>org.wildfly</groupId>
                    <artifactId>wildfly-controller-client</artifactId>
                    <version>${wildfly.version}</version>
                </dependency>
            </dependencies>
            <executions>
               <execution>
                   <id>cargo-prep</id> 
                       <phase>pre-integration-test</phase>
                   <goals>
                        <goal>redeploy</goal>
                   </goals>
               </execution>
                <execution>
                    <id>cargo-post</id>
                    <phase>post-integration-test</phase>
                    <goals>
                        <goal>undeploy</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</pluginManagement>

  • Parent defines boiler-plate portion

  • Child will provide module-specific information


  • Builds a new packaged, deployable artifact

  • Deploys and leaves on server

  • (optional)-DskipTests bypasses any unit tests

  • Notice that build completes immediately after deploy with no IT tests or undeploy


  • Undeploys atifact from server

  • Useful in automating cleanup

  • -Pundeploy activates latched profile

Plugin Page

  • Runs integration (IT) tests

  • Must be declared, not configured in by default

  • Runs after deployer completes and prior to undeployer


  • Plugin definition causes IT tests to run

  • Configuration defines environment for JVM


  • Can turn off problem or lengthy test(s)


  • Defines version# and wires plugin into build phases when declared by child module

Figure 92.17. Run IT Tests



$ mvn clean verify

$ mvn clean verify
...
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ ejb-basic-test ---
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ ejb-basic-test ---
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ ejb-basic-test ---
...
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ ejb-basic-test ---
...
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ ejb-basic-test ---
...
[INFO] --- maven-surefire-plugin:2.17:test (default-test) @ ejb-basic-test ---
...
[INFO] --- maven-jar-plugin:2.5:jar (default-jar) @ ejb-basic-test ---
...
[INFO] --- cargo-maven2-plugin:1.4.3:redeploy (cargo-prep) @ ejb-basic-test ---
Oct 01, 2014 2:28:02 AM org.xnio.Xnio <clinit>
INFO: XNIO version 3.2.2.Final
Oct 01, 2014 2:28:02 AM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.2.2.Final
Oct 01, 2014 2:28:02 AM org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 4.0.3.Final
...
[INFO] --- maven-failsafe-plugin:2.17:integration-test (integration-tests) @ ejb-basic-test ---

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
...

Results :

Tests run: 12, Failures: 0, Errors: 0, Skipped: 0
...
[INFO] --- cargo-maven2-plugin:1.4.3:undeploy (cargo-post) @ ejb-basic-test ---
...
[INFO] --- maven-failsafe-plugin:2.17:verify (verify) @ ejb-basic-test ---
...
-------------------------------------------------------
[INFO] BUILD SUCCESS


  • Runs all phases and stops just prior to installing into local repository

  • Cannot bypass unit tests (unless includes/excludes used)

  • Deploy artifacts to server

  • Run IT tests in IDE

  • Connect with Debugger


  • Not required when using embedded server (just use debug-as)

  • Standalone server must be restarted after making this edit




  • Debugger Client port must match what JBoss debugger listen port


  • You can optionally add modules now to resolve source code references


  • Execution will stop at server breakpoint

  • No sourcecode will show up if not yet in search path


  • Add as many projects as you wish

Note

You may have to stop and re-run your test for the source code path to take effect.


  • Notice we are seeing variables as well as line of execution

  • Populate ENC

  • Lookup resource in ENC

  • Inject ENC resource

  • Inject resource without ENC



  • jar-file element able to reference external JAR using a deterministic, portable path in EAR

  • jar-file element not usable in WARs


Note

There is no need to declare "class" entity references into a properly configured "jar-file" that is located in the classpath of a deployed EAR. Use "class" entity references when using a WEB-INF/classes/META-INF deployment of a WAR -- or if you really need to only include specific entities in the archive.

@PersistenceContext

Injected with EntityManager

Transaction Scoped
  • persistence context only sees a single Tx

  • container injects EntityManager with Tx active

Extended Scope
  • persistence context may see multiple Tx

  • only relevant for Stateful EJBs

@PersistenceUnit

Injected with EntityManagerFactory

  • May be used to implement BEAN-managed transactions


  • Room has mandatory reference to Floor and option reference to Guest

  • fetch=LAZY references most likely will be proxies implemented by JPA provider classes


  • Room entities returned from query are passed to client


  • Room returned with proxy class (Floor_$$_jvst9a8_0)between Room and Floor

  • Requires client to have hibernate-core in classpath


  • EJB Remote facade creating new instances of @Entity classes


  • Client now gets Room.floor without provider proxy class in between


  • Rooms fetch=LAZY

  • Rooms must be fetched within same DB session when using that collection


  • Floor being marshaled directly back to client without addressing LAZY fetches


  • Floor can be accessed

  • Floor.room access causes Lazy-load exception of collection


  • Server-side code, within the DB session boundary stimulates references to be loaded prior to marshaling back to client





  • Join fetch used to EAGER-ly load child rows

  • Less trips to DB for fatch=LAZY mappings


  • Still have to know "when is enough -- enough"


  • More information than the client wants/needs

  • More information than what client should have

  • But that is how out server-side model is designed...


  • Client only needed to know if room was occupied -- not by who


  • Room DTO class is only expressing that room is occupied


  • Similar to @Entity cleansing since DTO classes aren't managed

  • Can indirectly solve LAZY-load issue because @Entity is walked on server-side

  • Must still pay attention to DB access for performance reasons


  • Client no longer has access to who is in each room -- but server-side does


  • EJB will instantiate persistence context if does not yet exist

  • Stateless EJBs may only have transaction-scope persistence contexts

  • Stateful EJBs may have transaction-scope or extended persistence contexts

  • EJBs can share persistence contexts

    • Stateless EJB can propagate its tx-scope persistence context to a called EJB

    • Stateful EJB can propagate its tx-scoped or extended persistence context to a called EJB

    • Stateless EJB can work with extended persistence context provided by upstream Stateful client

    • Stateful EJB cannot transform propagated tx-scope persistence context into an extended

  • EJB Facade can act as sharing point for common persistence context


  • (Error checking removed)

  • Locate specific room

  • Add guest to DB

  • Associate room with guest


  • Client performs actions one at a time


  • Persistence context created

  • Available rooms loaded into persistence context

  • Result is returned

  • Persistence context destroyed


  • Persistence context created

  • Specific room loaded into persistence context

  • Guest inserted into DB


  • Guest inserted into DB

Note

The transaction does not end until existing the Stateless EJB method. That means any DB constraint violations will not occur within the context of the EJB call that caused it unless you call em.flush() (as a form of debug) prior to exiting the business method.


  • Room.occupant foreign key updated

  • Guest returned to client

  • Persistence context destroyed


  • Stateful EJB injects @PersistenceContext -- propagated in downstream EJB calls

  • Extended persistence context -- may be associated with zero or more transactions

  • Performing in-memory actions outside of transaction boundary


  • Method executed within active JTA transaction with persistence context associated with transaction

  • Guests already managed but will be fully persisted in this method

  • Calls to Stateless HotelMgmtEJB executed on this EJB's persistence context

  • @Remove indicates stateful instance to be discarded after method called


  • Multiple requests are issued to Stateful EJB

  • Specific method(s) act on that state


  • em.persist() outside of transaction causing causing sequence call but no table inserts


  • Downstream Stateless HotelMgmtEJB queried for rooms

  • Rooms loaded into persistence context


  • SQL inserts issued to DB during flush (requires transaction active)


  • Stateless HotelMgmtEJB accesses Rooms from EntityManager first-level cache -- no additional DB access

  • Stateless HotelMgmtEJB updates Room.occupant FK to reference Guest -- who is also already managed and in first-level cache

  • JTA Transaction committed by container after Stateful EJB method exits

  • Stateful EJB and persistence context also destroyed after method exits


  • Rejects checkin when invalid

  • Completes check-in when valid


  • Stateless EJB commits each of these check-ins


  • Additional check-in rejected -- nothing committed


  • Each check-in occured in own transaction

  • Later error did not impact previous completed transactions


  • Same stateful process as before -- but with one additional Guest (one too many)


  • Client attempts to check-in to all Rooms

  • Checked exception will be thrown


  • Five (5) Guests are flushed to database prior to the rollback


  • Persisted Guests removed from database as a part of transaction rollback

  • Early check-ins never flushed to DB -- discarded as part of rollback


  • All check-ins associated with Rooms removed as a part of rollback

Unit of work that accesses one more more resources (usually databases)

  • set of one or more activities related to each other

  • must be completed together or not at all

EJB is primarily a transaction framework/platform for application code

Figure 100.4. Container-Managed Transactions

Container-Managed Transactions
@Stateless

@TransactionManagement(TransactionManagementType.CONTAINER)
public class HotelMgmtEJB implements HotelMgmtRemote, HotelMgmtLocal {
...
    @PersistenceContext(unitName="ejbjpa-hotel")
    private EntityManager em;
    private HotelDAO dao;                                                                                                                                                                                                                                                                                                                                   
    private HotelMgmt hotelMgmt;
     
    @PostConstruct
    public void init() {
        dao = new JPAHotelDAO();
        ((JPAHotelDAO)dao).setEntityManager(em);
        hotelMgmt = new HotelMgmtImpl();
        ((HotelMgmtImpl)hotelMgmt).setHotelDao(dao);
    }
    @Override
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public Room getRoom(int number) {
        return hotelMgmt.getRoom(number);
    }
    
    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)    
    public Guest checkIn(Guest guest, Room room) throws RoomUnavailableExcepton {
        return hotelMgmt.checkIn(guest, room);
    }

  • Declarative interface to transactions

  • Declarative attributes tell container to execute a method

    • within a transaction (MADATORY, REQUIRED, REQUIRES_NEW, SUPPORTS)

    • without a transaction (SUPPORTS, UNSUPPORTED, NEVER)

  • Container completes transaction protocol prior to marshaling return objects



  • getUserTransaction()

    • Returned instance can use used to demarcate transactions

    • Restricted to EJBs using bean-managed transactions

  • getRollbackOnly()

    • Tests whether current transaction is going to be rolled back at the end

    • Restricted to EJBs using container-managed transactions

  • setRollbackOnly()

    • Allows EJBs to trigger the current transaction to be rolled back at the end

    • Restricted to EJBs using container-managed transactions


Resources created/modified within the transaction -- including resources operated on by called EJBs -- will be rolled back.


Even though the application did not throw an exception and gracefully returned a result -- the IT test shows the entity was not stored during the callback

No automatic rollback by default


Checked exceptions, but default, do not trigger rollbacks


An error in processing can be reported with an exception without rollback


IT test verifies entity thrown with the exception was persisted

Checked/Application exceptions can be configured to trigger a rollback


Annotation tells container to automatically rollback transaction if thrown


An error in processing can be reported with an exception without rollback


IT test verifies entity thrown with the exception was persisted

  • Programmatic interface to transactions

  • Interactions through javax.transaction.UserTransaction interface

    • Everything between utx.begin() and utx.commit() is within a single transaction

    • Bean is in control


  • Can inject @PersistenceContext/EntityManager or @PersistenceUnit/EntityManagerFactory


  • Stateful session EJBs using container-managed transactions can receive transaction events

  • EJBs using bean-managed transactions are in control of their transaction and do not need events


  • Provides a rich Model View Controller (MVC) framework for developing web-based UIs

  • Integrates well with many CDI concepts



  • CDI @Named used to specify name for page to use

  • Class required to implement Serializable unless RequestScoped


  • Page refers to @Name.property and accesses using associated methods (SellerController.getProperty() and Product.setName() in this case)

  • Controller holds this state until action called


  • Page refers to action using @Name.methodName

  • Action methods take no arguments. They act on state supplied by setters.

  • Action methods return a String result used for navigation

  • Action methods may interact with business methods/resources to perform task



  • Useful in interacting with back-end resources and other page controllers

  • ProductCatalog is a Java business interface that is implemented by a DAO and EJB.

  • @Inject tells the provider to inject an implementation that matches the specified type

  • @Tx is defined within the application to further qualify which provider of the ProductCatalog interface is used

  • ErrorController is a sibling PageController for crudely displaying error messages and stack traces


  • Simple example contains business data state and data access methods

Many mark-up languages can be used (e.g., JSP, XHTML, etc.)


  • Page uses XHTML markup -- must be a legacy XML document

  • Page uses JSF types xmlns:h="http://xmlns.jcp.org/jsf/html" to interact with framework and controller bean



  • Standard html begin/end tags and basic HTML document formatting

  • JSF provides replacement h:head and h:body tags


  • Form bound to UIForm instance supplied by provider. Permits controller bean to manage page form.

  • Form will display the starting state of Product

  • Form will update the properties of Product

  • commandButton registered to action method in controller


  • selectMenu calls getCategories() to obtain choice list

  • selectMenu will store that value in SellerController.getProduct().setCatagory()


  • commandButton calls SellerController.add() action

  • SellerController.add() action acts on the state and provides a navigation result

Figure 104.14. Example Table with Row Actions


    <h:form>
     <h:dataTable value="#{sellerController.products}" var="p">
...         
            <h:column>
                <f:facet name="header">
                    <h:column>
                        <h:outputText value="Name"></h:outputText>
                    </h:column>
                </f:facet>
                <h:outputText value="#{p.name}"/>
            </h:column>
...         
         <h:column>
             <f:facet name="header">
                 <h:column>
                     <h:outputText value="Actions"></h:outputText>
                 </h:column>
             </f:facet>
             <h:panelGrid columns="2">
                 <h:commandButton value="save" action="#{sellerController.save}">
                     <f:setPropertyActionListener 
                         target="#{sellerController.product}" 
                         value="#{p}"/>
                 </h:commandButton>
             </h:panelGrid>
         </h:column>
     </h:dataTable>
    </h:form>
    public String save() {

        product.setSeller(user.getMember());
        product = catalog.addProduct(product);  //EJB call
        Collections.sort(products, new Product.ProductASC());
        return null;
    }

  • Table displays column and row data

  • Example shows columns for each property of the product

  • Example adds commandButton to each row to control actions with back-end


  • index.xhtml and seller-products.xhtml meant to be bookmarked and called at any time -- please in public web space

  • error.xhtml meant to be navigated to from other controllers. Placed in non-public WEB-INF directory

  • faces-config.xml can be used for navigation flow and pre-dates @Annotations

  • beans.xml enables CDI processing


  • FacesServlet declared to process all JSF pages

  • PROJECT_STAGE=Development enables extra debug in output


  • Provides a top level entry page

  • Example provides link(s) to more detailed pages

  • This and follow-on pages may or may not reference a controller


  • Any "error" output from seller-products will navigate to error page


  • CDI activated when file exists (blank, empty, or populated)


  • Beans can be simple POJOs, EJBs, Servlets, etc.

  • CDI Beans generalize behavior provided by larger frameworks


  • Type-safe, Java-based container injection

  • Container will match injection point with managed bean of requested type

  • Error if container finds multiple classes satisfying requested type


  • @Annotation qualifier specializes injection type to remove ambiguity


  • java.lang.annoation

    @Retention

    how long the class is retained (default=CLASS)

    RententionPolict

    • CLASS - annotation recorded in class file but not available at runtime

    • RUNTIME - annotation recorded in class and available at runtime

    • SOURCE - annotation discarded by compiler

    @Target

    kind of Java construct the annotation applies to

    ElementType

    • TYPE

    • FIELD

    • METHOD

    • PARAMETER

    • (more)

  • javax.inject (JSR-330)

    @Inject

    an injection target

    @Named

    string qualifier (for JSPs, etc. to reference bean using text)

    @Qualifier

    identifies qualifier annotations

  • javax.enterprise.inject (JSR-299)

    @Produces

    an injection source

    @Any

    no qualifiers

    Instance<Bean>

    runtime source of type Bean

  • Prior to JavaEE 6

    • EJB beans could only be deployed in EJB modules

    • EJB modules integrated with WARs using common EAR

  • Starting with JavaEE 6

    • EJB beans can be embedded within WAR

    • EJB modules can be deployed within WAR

|-- index.html                                                                                                                                                        
`-- WEB-INF                                                                                                                                                           
    ...
    |-- jboss-web.xml
    |-- lib
    `-- web.xml
        
	WEB-INF/lib/
	`-- webejbCustomerEJB-3.0.2012.2-SNAPSHOT.jar
WEB-INF
|-- beans.xml                                                                                                                                                     
|-- classes
|   |-- ejava
|   |   `-- examples
|   |       `-- ejbwar
|   |           `-- inventory
|   |               |-- bo
|   |               |   |-- Categories.class
|   |               |   |-- Category.class
|   |               |   |-- InventoryRepresentation.class
|   |               |   |-- Product.class
|   |               |   `-- Products.class
|   |               |-- client
|   |               |   |-- InventoryClient.class
|   |               |   `-- InventoryClientImpl.class
|   |               |-- dao
|   |               |   |-- InventoryDAO.class
|   |               |   `-- InventoryDAOImpl.class
|   |               |-- ejb
|   |               |   |-- InventoryMgmtEJB.class
|   |               |   `-- InventoryResources.class
|   |               |-- rmi
|   |               |   |-- InventoryMgmtRemote.class
|   |               |   `-- InventoryMgmtRMIEJB.class
|   |               `-- rs
|   |                   |-- Application.class
|   |                   |-- CategoriesResource.class
|   |                   |-- PrettyPrinter.class
|   |                   |-- ProductsResource.class
|   |                   |-- ResourceHelper.class
|   |                   `-- TxFilter.class
|   `-- META-INF
|       `-- persistence.xml
...
        


@Path("/products")
public class ProductsResource {
    private static final Log log = LogFactory.getLog(ProductsResource.class);
    @Inject
    private InventoryMgmtEJB ejb;
    @Context
    private Request request;
    @Context 
    private UriInfo uriInfo;
    ...


@XmlRootElement(name="catageory", namespace=InventoryRepresentation.NAMESPACE)
@XmlType(name="Category", namespace=InventoryRepresentation.NAMESPACE)
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Category extends InventoryRepresentation {
    private int id;
    private String name;
    private Integer productCount;
    private List<Product> products=new ArrayList<Product>();
    public Category() {}
    public Category(String name) {
        this.name=name;
    }
...    
}
  • EJB access restrictions

    • Declarative

    • Programmatic

  • EJB assignment to Security Domain

  • Server definition of Security Domain

  • Server Security Domain authentication and authorization


  • javax.annotation.security annotations define access requirements to EJB methods


  • Access restrictions can also be defined in the ejb-jar.xml deployment descriptor


  • Permits more fine-grain access control down to the object level

  • role can be literal or a logical mapping (see below)


  • Permits role-name within Java code to be mapped to security role


  • Assigns one or more EJBs to a security-domain defined on server

  • Security is ignored until this is place

  • JBoss default security-domain is "other"

Wildfly Security Realms Wiki

  • Realm

  • User Credentials (username and password)


  • Watches over interactions

  • Defines policy on what can take place


  • Defines authentication and authorization sources

  • Optionally defines a default user for anonymous

$local default user bypasses authentication

JBoss can operate in a mode to trust a user connecting from the same machine and running under the same operating system identity that launched the server. This allows for development scenarios to bypass login credentials and Command Line Interface (CLI) to operate without credential prompts.


<local default-user="$local" allowed-users="*" skip-group-loading="true"/>

JBoss Ships with Sample Authentication and Authorization Impl

JBoss installs with a set of static files to implement user authentication and authorization. This can be augmented or replaced by more dynamic sources such as a database or LDAP.


  • Authenticates identity of user

  • Username and hashed password stored in static file


  • Assigns roles to authenticated user

  • Username and roles stored in static file

  • JBoss Remoting and JNDI InitialContext

  • EJBClient and CallbackHandler

  • Changing Users

  • Access Violations

  • Access Granted


  • factory.initial set to JBoss Remoting implementation

  • provider.url set to address of JBoss server

  • ejb.context set to "true" to use this library to establish EJB contexts

  • url.pkgs option and used for alternate namespaces (e.g., "ejb:")


  • Using generic JBoss Remoting JNDI name


  • Client provides credentials in JNDI prior to obtaining InitialContext

  • Must use current JNDI Context to lookup @Remote


  • Client can switch credentials with a change in InitialContexts and @Remote reference


  • Fixed credentials can be placed in jndi.properties when known and not changing


  • factory.initial not important, will delegate to naming extension

  • url.pkgs defines Java package with EJBClient extensions

  • provider.url ignored in this case

  • ejb.context not used and set to false in this case


  • SSL_ENABLED=false - example setup does not yet cover SSL and would require trustStore

  • SASL_DISALLOWED_MECHANISMS=JBOSS-LOCAL-USER - disallowing default user to be set to $local

  • callback.handler.class=info.ejava...BasicCallbackHandler - provider credentials via callback

Figure 112.8. CallbackHandler used to Provide Credentials

import javax.security.auth.callback.CallbackHandler;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.RealmCallback;
public class BasicCallbackHandler implements CallbackHandler {
    private String name;
    private char[] password;
    private String realm="ApplicationRealm";
    public BasicCallbackHandler(String name, String password) {
        this.name = name;
        setPassword(password);
    }
    public void handle(Callback[] callbacks) 
        throws UnsupportedCallbackException, IOException {
        for (Callback cb : callbacks) {
            if (cb instanceof NameCallback) {
                ((NameCallback)cb).setName(name);                
            }
            else if (cb instanceof PasswordCallback) {
                ((PasswordCallback)cb).setPassword(password);
            }
            else if (cb instanceof RealmCallback) {
                ((RealmCallback)cb).setText(realm);
            }
            else {
                throw new UnsupportedCallbackException(cb);
            }
        }
    }
}

  • Class was registered in jboss-ejb-client.properties

  • Class responds to handle() callbacks


  • CallbackHandler accessed at class-scope

  • Must register credentials at class level

  • Credentials tied to connection. Cannot change identities without breaking and re-establishing connection (with proprietary API)


  • EJBClient stores credentials with connection

  • Must establish new connection to have CallbackHandler called again


  • No need to get new InitialContext or new lookup of @Remote


  • Fixed credentials can be placed in jboss-ejb-client.properties when known and not changing


  • Implement security query methods in a EJB


  • Client asserts security query results to verify setup correctly


  • EJBAccessException thrown when accessing method not allowed


  • Access to method protected by declarative security granted

  • Results of programmatic security checks returned in formatted text string

  • No caller context

  • Elevate access

  • Run-as role-name and identity


  • security-identity of bean defaults to caller identity


  • EJB can discard caller's identity/roles and run-as a specific role

  • Requires specification of an identity (provider-specific annotation)


  • Specifies specific user-identity to run-as

  • Vendor-specific


  • user1 is allowed to call method restricted to admin when proxied by run-as EJB

  • proxy EJB sees caller as user1 and having all assigned roles

  • proxied EJB sees caller as admin1 and only having assigned admin role

  • Lock down access to web pages and commands

  • Identify user prior to EJB interaction


  • Anything accessed via specified url-pattern must have admin role-name

  • Communication must be encrypted (i.e., switch to HTTPS)


  • Obtain missing user credentials using FORM when navigating to protected urls


  • Servlet accessible via multiple URLs

Example Creates Security Hole on Purpose

The example creates a security hole on purpose to be able to demonstrate EJB security backs the WEB security. The servlet mapped above is accessible through multiple URLs -- each restricted differently but attempting to provide the same functionality. If you access the servlet through the anonymous URL you will encounter many access failures communicating with the EJB. If you access the servlet using the admin URL you will be able to access all functionality.


  • Assigning web-tier to same security-domain as EJB tier

  • Interpose on contructor, EJB business and lifecycle methods

  • Interceptor lifecycle is same as the bean it interposes on (i.e., Stateless/Stateful)





  • Decouples EJB and Interceptor classes

  • Assign to specific EJBs or globally

  • Assign to specific EJB methods or global to class

  • Can control order applied


  • @Annotation near-equivalent to EJB deployment descriptor

  • Couples EJB class to Interceptor class

  • Cannot assign globally to all EJBs

  • Can assign to specific EJB methods or global to class

  • Can control order applied

  • Extends Java Interceptors specified in EJB Spec

  • Not specific to EJBs -- any POJO

  • EJB Bean Class

  • Business method(s)

  • Normalization and validation concerns

  • Decouple data manipulation/validation from business/DAO logic

Figure 117.8. Validator Base Class

public class ValidatorInterceptor {

    @Inject
    private Validator validator;
    private Class<?>[] groups;
    
    protected ValidatorInterceptor() {}
    public ValidatorInterceptor(Class<?>[] groups) { this.groups = groups; }
    
    @AroundInvoke
    public Object invoke(InvocationContext ctx) throws Exception {
        logger.debug("validating method: {}, groups: {}", ctx.getMethod(), Arrays.toString(groups));
        //validate each parameter
        for (Object param: ctx.getParameters()) {
            logger.debug("validating param: {}, groups: {}", param, Arrays.toString(groups));
            Set<ConstraintViolation<Object>> violations = validator.validate(param, groups);
            if (!violations.isEmpty()) {
                Exception ex = new InvalidParam(param.toString(), getErrors(violations));
                logger.debug("aborting call, found error: {}", ex.getMessage());
                throw ex;
            }
        }
        return ctx.proceed();
    }
    
    private List<String> getErrors(Set<ConstraintViolation<Object>> violations) {
        List<String> errors = new ArrayList<String>(violations.size());
        for (ConstraintViolation<Object> v: violations) {
            errors.add(v.toString());
        }
        return errors;
    }
}

  • Grabs parameters from InvocationContext

  • Validates each of them against assigned validation group


  • Define @InterceptorBinding (@Validation) and @Interceptor role for CDI

  • Define validation group(s) for base class


  • Defines @InterceptorBinding (@Validator) and @Interceptor role

  • Defines @AroundInvoke for business method

  • Subjects each parameter to normalization rules

  • Details of normalization omitted (initial caps for each name/word)