Anda di halaman 1dari 426

Oracle 10g: Build J2EE Applications

Volume II Student Guide

D17247GC11 Edition 1.1 June 2005 D18758

Authors Lynn Munsinger Sunitha Patel Glenn Stokol Gary Williams Technical Contributors and Reviewers Anna Atkinson Scott Brewton Kenneth Cooper Craig Hollister Taj-ul Islam Istvan Kiss Peter Laseau Glenn Maslen Monica Motley-Mosser Nagavalli Pataballa Holger Dindler-Rasmussen Glenn Stokol Vasiliy Strelnikov Venkat Tallapragada Publisher Joseph Fernandez

Copyright 2005, Oracle. All rights reserved. This documentation contains proprietary information of Oracle Corporation. It is provided under a license agreement containing restrictions on use and disclosure and is also protected by copyright law. Reverse engineering of the software is prohibited. If this documentation is delivered to a U.S. Government Agency of the Department of Defense, then it is delivered with Restricted Rights and the following legend is applicable: Restricted Rights Legend Use, duplication or disclosure by the Government is subject to restrictions for commercial computer software and shall be deemed to be Restricted Rights software under Federal law, as set forth in subparagraph (c)(1)(ii) of DFARS 252.227-7013, Rights in Technical Data and Computer Software (October 1988). This material or any portion of it may not be copied in any form or by any means without the express prior written permission of Oracle Corporation. Any other copying is a violation of copyright law and may result in civil and/or criminal penalties. If this documentation is delivered to a U.S. Government Agency not within the Department of Defense, then it is delivered with Restricted Rights, as defined in FAR 52.227-14, Rights in Data-General, including Alternate III (June 1987). The information in this document is subject to change without notice. If you find any problems in the documentation, please report them in writing to Education Products, Oracle Corporation, 500 Oracle Parkway, Box SB-6, Redwood Shores, CA 94065. Oracle Corporation does not warrant that this document is error-free. All references to Oracle and Oracle products are trademarks or registered trademarks of Oracle Corporation. All other products or company names are used for identification purposes only, and may be trademarks of their respective owners.

Contents
Preface 1 Introduction Course Objectives 1-2 Course Environment 1-4 Course Overview 1-5 About the Course Applications 1-8 Order Entry Schema 1-9 Human Resources (HR) Schema 1-10 HR Application Flow Diagram 1-11 Summary 1-12 J2EE Overview Objectives 2-2 Java 2, Enterprise Edition Platform 2-3 J2EE Platform 2-4 Benefits of the J2EE Platform 2-5 J2EE Components 2-7 J2EE 1.3 Components 2-8 J2EE Architecture 2-9 Client-Tier Components 2-10 J2EE Web-Tier Components 2-11 What Is a Servlet? 2-13 What Is a JavaServer Page (JSP)? 2-14 Web-Tier Components: Summary 2-15 Business-Tier Components 2-16 Enterprise JavaBeans (EJB) 2-17 J2EE Communication APIs 2-18 J2EE Server 2-19 Oracle Application Server 10g Containers for J2EE (OC4J) 2-21 J2EE Applications 2-22 Packaging J2EE Application Components 2-23 JARs 2-24 WARs 2-25 EJB JARs 2-26 EARs 2-27 EAR File Structure for a J2EE Application: Example 2-28 OC4J Architecture 2-29 OC4J Server Configuration Files 2-30 Relation of Configuration Files 2-31

iii

Data Sources 2-32 Application Logging 2-33 J2EE Application Deployment to Oracle Application Server 10g 2-34 Oracle Enterprise Manager 2-35 JDeveloper and J2EE 2-36 Oracle JDeveloper 10g Environment 2-37 Oracle JDeveloper 10g Visual Design Tools 2-38 Summary 2-39 Practice 2-1: Overview 2-40 3 Designing J2EE Applications Objectives 3-2 Realizing J2EE Benefits 3-3 J2EE Issues 3-4 J2EE Design Patterns 3-5 Implementing Design Patterns by Using MVC 3-6 The Model 3-7 The View 3-8 The Controller 3-9 MVC in Oracle Application Server 10g Containers for J2EE 3-10 Designing J2EE Applications 3-11 Flow Diagram: Example 3-12 Summary 3-13 Practice 3-1: Overview 3-14 Creating the Web Tier: Servlets Objectives 4-2 Overview 4-3 About Java Servlets 4-4 Principal Features of Servlets 4-5 Life Cycle of Servlets 4-6 HTTP Servlets 4-7 Inside an HTTP Servlet 4-8 Servlet: Example 4-9 The doGet() Method 4-10 The doPost() Method 4-11 The HttpServletRequest Object 4-12 The HttpServletResponse Object 4-13 Methods for Invoking Servlets 4-14 Your First Servlet 4-15 Handling Input: The Form 4-16

iv

Handling Input: The Servlet 4-17 Initialization and Destruction 4-18 Error Handling 4-19 Debugging a Servlet 4-20 SingleThreadModel 4-21 JDeveloper Environment 4-23 Servlet Mapping 4-24 Servlet Mapping in JDeveloper 4-25 Invoking a Servlet 4-26 Specifying J2EE Web Module Settings 4-27 Creating a Connection to Oracle Application Server 10g 4-28 Deploying to OC4J 4-29 Summary 4-30 Practices 4-1, 4-2, and 4-3: Overview 4-31 5 Accessing the Database with Servlets Objectives 5-2 Review of JDBC 5-3 Querying in JDBC 5-4 JDBC and Servlets 5-5 Synchronizing Shared Resources 5-6 Transaction Handling 5-7 Connection Pooling 5-9 Data Sources 5-10 Data Source Definition 5-11 data-sources.xml: Example 5-12 Using Data Sources 5-13 Summary 5-14 Practice 5-1: Overview 5-15 Using Advanced Techniques in Servlets Objectives 6-2 Overview 6-3 HTTP Headers 6-4 Request Headers 6-5 Sending a Response 6-6 Response Headers 6-7 Setting Status Codes 6-8 Example 6-9 Sending Multimedia Content 6-10

Cookies 6-12 Setting Cookies 6-13 Retrieving Cookies 6-14 About State Preservation 6-15 State Preservation: Example 6-16 ServletContext 6-17 RequestDispatcher 6-18 RequestDispatcher: Example 6-19 Servlet Filters 6-20 Using Filters 6-21 doFilter() Method 6-22 Using Filters 6-23 Configuring Filters 6-24 Application Lifecycle Events 6-25 ServletContext Events 6-26 HttpSession Events 6-27 Example of an Event Listener 6-28 Error Handling 6-29 Summary 6-30 Practices 6-1 and 6-2: Overview 6-31 7 Maintaining State in J2EE Applications Objectives 7-2 Overview 7-3 Session Basics 7-4 Threading 7-6 URL Rewriting 7-7 HttpSession 7-8 Session Objects 7-9 Session-Based Page Counter 7-10 Session Life Cycle 7-11 Session Tracking in OC4J 7-12 Sessions and Events 7-13 Creating Distributable Applications 7-17 Summary 7-18 Practice 7-1: Overview 7-19 Creating the Web Tier: JavaServer Pages Objectives 8-2 JavaServer Pages 8-3 Comparing Servlets and JSPs 8-4

vi

Invoking JSPs 8-5 The Date JSP 8-6 The Date Servlet 8-7 Automated JSP Features 8-8 JSP Life Cycle 8-9 Basic JSP Elements 8-10 Declarations 8-11 Expressions 8-12 Scriptlets 8-13 Implicit Objects 8-14 Example 8-16 Directives 8-18 include: Example 8-19 page Directive 8-20 JSP and JavaBeans 8-22 Using JavaBeans with JSP 8-23 scope Attribute of <jsp:useBean> Tag 8-25 Accessing and Setting Bean Property 8-26 JSP XML Document 8-28 Traditional Syntax Versus XML Syntax 8-29 JDeveloper and JSPs 8-31 Creating JSPs Visually 8-32 JSP Tag Insight 8-33 Summary 8-34 Practices 8-1, 8-2, and 8-3: Overview 8-35 9 Modularizing JavaServer Pages Development with Tags Objectives 9-2 Custom Tags 9-3 Custom Tag Library Components 9-4 Tag Handler: Example 9-5 Tag Library Descriptors 9-6 Using a Custom Tag 9-7 Tags with Attributes 9-8 Creating a Custom Tag in JDeveloper 9-9 Tag Libraries in JDeveloper 9-10 Registering Tag Libraries 9-11 Using Tag Insight 9-14 JSP Standard Tag Library (JSTL) 9-15 Core Tag Library 9-16 Utilizing Core Tags 9-18
vii

Expression Language 9-19 Using Iteration Tags 9-20 Using the URL Tags 9-21 XML Tag Library 9-23 SQL Tag Library 9-24 Accessing a Database with SQL Tags 9-25 Querying Using SQL Tags 9-26 Inserting, Updating, and Deleting Data 9-27 Formatting Tags 9-28 Internationalization Concepts 9-29 Internationalizing Strings 9-30 Formatting Numbers and Dates 9-31 Transforming XML Documents 9-34 JSTL in JDeveloper 9-35 Summary 9-36 Practice 9-1: Overview 9-37 10 Communicating in J2EE Objectives 10-2 Overview of RMI 10-3 Role of RMI in J2EE 10-4 Communication in a J2EE Environment 10-5 How Clients Locate a Distributed Component 10-7 Java Naming and Directory Interface (JNDI) 10-8 J2EE Container and JNDI Interface 10-9 Naming Service 10-10 JNDI Terminology 10-11 Main JNDI Class and Interface Accessing an Object in JNDI Namespace 10-13 Getting the JNDI InitialContext 10-14 Initial Context Factories 10-16 lookup() Method 10-17 Obtaining a Reference to a Local Resource 10-18 Obtaining a Reference to a Remote Resource 10-19 Setting JNDI Environment Properties 10-20 Using RMI over HTTP Tunneling 10-24 Using Environment References with JNDI 10-25 Configuring Environment Variables 10-26 Specifying an EJB Reference 10-28 Configuring EJB References 10-29

viii

Configuring Data Source References 10-31 Summary 10-33 Practice 10-1: Overview 10-34 11 Creating the Business Tier: Enterprise JavaBeans Objectives 11-2 Enterprise JavaBeans (EJB) 11-3 When to Use EJBs 11-4 Types of EJBs 11-5 Session Beans 11-7 Entity Beans 11-9 Message-Driven Beans 11-10 EJB Architecture 11-11 EJB Server 11-12 EJB Container 11-13 Services Provided by the EJB Container 11-14 EJB Client 11-16 EJB Interfaces and Classes 11-17 Remote Interface and Remote Object 11-18 Home Interface and Home Object 11-19 Local Interface and Local Home Interface 11-20 EJB Bean Class 11-21 The EJB Deployment Process 11-22 ejb-jar.xml File 11-23 orion-ejb-jar.xml File 11-24 Creating an EJB in JDeveloper 11-25 Using the EJB Wizard 11-26 Adding Methods to the Bean 11-28 Deploying to Oracle Application Server 10g from JDeveloper 11-29 Summary 11-30 Practice 11-1: Overview 11-31 12 Implementing Business Tasks with Session EJBs Objectives 12-2 Session Beans 12-3 javax.ejb.SessionBean Interface 12-5 Types of Session Beans 12-7 When to Use Session Beans 12-9 Life Cycle of a Stateless Session Bean 12-11 Home Interface for Stateless Session Beans 12-12 Remote Interface for Stateless Session Beans 12-14

ix

The Session Bean Class 12-15 The Session Bean Class: Business Methods 12-17 Bean Class for the Stateless Session Bean 12-18 Deployment Descriptor 12-19 Client Application 12-20 Client Application for Stateless Session Beans 12-21 Life Cycle of a Stateful Session Bean 12-25 Home Interface for Stateful Session Bean 12-26 Client Application for Stateful Session Bean 12-27 Summary 12-28 Practices 12-1 and 12-2: Overview 12-29 13 Managing Persistent Data in the Business Tier Objectives 13-2 Entity Beans 13-3 Representing Data in Entity Beans 13-5 When to Use Entity Beans 13-6 Callback Methods to Load and Store Data 13-7 Session Beans Versus Entity Beans 13-9 Types of Entity Beans 13-11 BMP Beans Versus CMP Beans 13-12 Components of an Entity Bean 13-14 Creating, Removing, Finding, and Selecting Entity Beans 13-15 Home Interface of an Entity Bean 13-17 Creating a Bean Instance 13-18 Finding an Entity Bean Instance 13-20 Removing an Entity Bean 13-22 Home Methods of Entity Beans 13-23 Component Interfaces of an Entity Bean 13-24 Primary Key Class of an Entity Bean 13-25 Bean Class of an Entity Bean 13-26 javax.ejb.EntityBean Interface 13-28 Life Cycle of an Entity Bean 13-30 Deployment Descriptor 13-32 Summary 13-35 Practice 13-1: Overview 13-36 14 Achieving State Management in the Business Tier Objectives 14-2 Features of BMP Entity Beans 14-3 Developing a BMP Entity Bean 14-4

Features of CMP Entity Beans 14-5 Implementing Methods in CMP Beans and BMP Beans 14-7 Developing a CMP Entity Bean 14-9 CMP Bean: Example 14-10 Bean Class of a CMP EJB: CMP Fields 14-11 Remote Interface: Departments 14-12 Home Interface: DepartmentsHome 14-13 Bean Class: DepartmentsBean 14-14 Deployment Descriptor ejb-jar.xml 14-17 Mapping CMP Fields to Database Table Columns 14-21 Default Mapping of CMP Fields to Database Table Columns 14-22 Explicit Mapping of CMP Fields to Database Table Columns 14-23 Client for Departments Bean 14-25 Summary 14-28 Practice 14-1: Overview 15 Container-Managed Relationships (CMRs) Objectives 15-2 Relationships 15-3 Implementing Relationships 15-4 Cardinality and Direction of Relationships 15-5 One-to-One Relationships 15-7 One-to-Many Relationships 15-8 Many-to-Many Relationships 15-9 Oracle TopLink 15-10 TopLink: Integration of J2EE Applications with Data Sources at Run Time 15-11 TopLink: Integrated with Oracle JDeveloper 10g 15-12 Implementing Relationships 15-13 Defining Abstract Accessor Methods 15-14 Accessor Methods in 1:1 Relationships 15-15 Accessor Methods in 1:M Relationships 15-16 Checking Relationship Mappings in JDeveloper 15-17 Accessor Methods in M:N Relationships 15-18 Implementing a Relationship in the Deployment Descriptor 15-19 Implementing 1:1 Relationships 15-21 Implementing 1:M Relationships 15-23 Implementing M:N Relationships 15-25 Mapping Relationship Fields to Database 15-27 Default Mapping of Relationship Fields 15-28 Explicit Mapping of Relationship Fields 15-30

xi

Using JDeveloper to Create CMR Beans 15-31 Summary 15-32 Practice 15: Overview 16 Developing Message-Driven Beans Objectives 16-2 Overview of Messaging Systems 16-3 Types of Message Consumption 16-4 Java Message Service (JMS) 16-6 JMS Application Architecture 16-7 Point-to-Point Model 16-8 Publish-and-Subscribe Model 16-9 Using JMS Interfaces 16-10 JMS Message Structure 16-12 Sending a Message to a Queue 16-13 Receiving Messages 16-15 Asynchronous Message Delivery 16-16 Message-Driven Beans 16-17 MDB Architecture 16-18 Associating JMS Resources with an MDB 16-19 State Diagram of an MDB 16-20 Developing MDBs 16-22 Interfaces to Be Implemented for MDBs 16-23 Implementing an MDB Class 16-24 Receiving Messages in an MDB Class 16-25 Creating the Deployment Descriptor 16-26 ejb-jar.xml: Example 16-28 Mapping in OC4J-Specific Deployment Descriptor 16-29 orion-ejb-jar.xml: Example 16-30 Creating an MDB with JDeveloper 16-31 Testing the MDB 16-34 Summary 16-35 Practice 16-1: Overview 16-36 17 Integrating J2EE Components Objectives 17-2 Overview 17-3 Creating Remote Clients for EJBs 17-4 Importing the EJB Home Interface 17-5 Create a Reference to the EJB 17-6

xii

Passing Arguments to the EJB Method 17-7 Creating an EJB Reference 17-8 Creating Local Clients for EJBs 17-9 ejb-local-ref Element 17-10 EJB Tags 17-11 useHome Tag 17-12 useBean Tag 17-13 createBean Tag 17-14 iterate Tag 17-15 Using the EJB Tags 17-16 Deploying an Application: Web Tier 17-17 Deploying an Application: EJB Tier 17-18 Deploying an Application: EAR File 17-19 Deploying from Oracle Enterprise Manager 17-20 Summary 17-21 Practice 17-1 and 17-2: Overview 17-22 18 Distributing Modular Applications: Introduction to Web Services Objectives 18-2 What Is a Web Service? 18-3 Web Service 18-4 Service-Oriented Architecture 18-6 Web Services Constituents 18-7 Benefits of Web Services 18-9 Web Services Model 18-11 RPC-Style Web Services 18-12 Document-Style Web Services 18-13 Oracle Support for Web Services 18-14 SOAP: XML Messaging for Web Services 18-15 Communication with SOAP 18-16 SOAP Messages 18-17 Web Services Description Language (WSDL) 18-19 WSDL 18-20 UDDI Registry 18-22 How UDDI Is Used 18-24 Searching for a Web Service by Using UDDI 18-25 UDDI Specification 18-26 tModel 18-27 UDDI Support in Oracle JDeveloper 10g 18-31 UDDI Browsing with Oracle JDeveloper 10g 18-32 UDDI Publishing and Browsing with Oracle Enterprise Manager 18-33
xiii

Utilizing External Web Services from JDeveloper 18-34 Summary 18-35 Practice 18-1: Overview 18-36 19 Distributing Modular Applications: Developing Web Services Objectives 19-2 Oracle Application Server 10g Web Services 19-3 Developing a Web Service with a Stateless Java Class 19-4 Defining an Interface 19-5 Defining a Stateless Java Class 19-7 Creating the Web Service 19-10 Creating the Client Application 19-11 Deploying the Web Service 19-13 Testing the Web Service 19-14 Web Service Home Page 19-15 Testing the Deployed Web Service with Home Page 19-16 Testing the sayHello Operation 19-17 Serializing and Encoding Parameters and Results 19-19 Developing a Stored Procedure Web Service 19-20 Generating Wrapper Classes Using JPublisher 19-21 Exposing a Function as a Web Service by Using Oracle JDeveloper 10g 19-22 Publishing the Package as a Web Service 19-23 JMS Web Services 19-24 Summary 19-26 Practice 19-1: Overview 19-27 20 Implementing Security in J2EE Applications Objectives 20-2 Goals of J2EE Security Architecture 20-3 Overview of J2EE Security Architecture 20-4 Java Authentication and Authorization Service (JAAS) 20-5 Authorization of a Client 20-8 JAAS Provider Types in OC4J 20-9 Configuring Security 20-10 Defining the Users, Groups, and Roles 20-11 Managing Users and Groups with the JAZN Admintool 20-13 Defining the Logical Roles 20-15 Defining and Using Logical Roles in Web Applications (web.xml) 20-16 Defining and Using Logical Roles in EJBs (ejb-jar.xml) 20-18 Mapping Logical Roles to Users and Groups 20-19 Programmatic Access to a Callers Security Context 20-20

xiv

Client Authentication 20-21 EJB Client Authentication with the jndi.properties file 20-22 EJB Client Authentication with a Hashtable 20-23 Setting Access Control with JDeveloper 20-24 Creating Web Application Security Roles 20-25 Web Application Login Authentication 20-26 Web Application Authorization 20-27 Creating EJB Security Roles 20-28 Setting Method Permissions 20-29 Method Access in EJB Deployment Descriptors 20-30 Creating a Mapping for the Logical Roles 20-31 Mapping JAZN Identities to a Logical Role 20-32 Mapping Results in orion-ejb-jar.xml 20-34 Accessing the EJB with New Permissions 20-35 Summary 20-36 Practice 20-1: Overview 20-37 21 Oracle Application Server 10g Transaction Support Objectives 21-2 What Is a Transaction? 21-3 Enterprise JavaBeans (EJB) Support for Transactions 21-4 EJB Transaction Model 21-5 Demarcating Transactions 21-6 Container-Managed Transactions 21-7 CMT: Transaction Attributes 21-8 Transaction Attribute: NotSupported 21-10 Transaction Attribute: Required 21-11 Transaction Attribute: Supports 21-12 Transaction Attribute: RequiresNew 21-13 Transaction Attribute: Mandatory 21-14 Transaction Attribute: Never 21-15 CMT: The setRollbackOnly() Method 21-16 JDeveloper: Setting Transaction Attributes 21-17 Java Transaction API (JTA) 21-19 JTA: The UserTransaction Interface 21-20 Bean-Managed Transactions Demarcation 21-21 BMT Demarcation: Process 21-22 Using UserTransaction Support in EJBs 21-23 Client-Demarcated Transactions Using UserTransaction 21-24 BMT Demarcation: Restrictions 21-25 Local and Global Transactions 21-26
xv

Single-Phase Commit 21-27 Data Source Revisited 21-28 Default data-sources.xml 21-29 Emulated Versus Nonemulated Data Sources 21-30 Retrieve Connection to Data Source 21-31 Global Transaction Resource Request Flow 21-33 Resource Request Flow 21-34 Enlisting Database Resources 21-36 Summary 21-38 Practice 21-1: Overview 21-39 Appendix A: Practice Solutions Appendix B: Schema Descriptions Appendix C: Oracle JDeveloper 10g - Quick Reference Appendix D: BMP Entity EJBs J2EE Connector Architecture BMP Bean: Example D-2 Remote Interface: JobsBMP D-3 Home Interface: JobsBMPHome D-4 Primary Key Class: JobsBMPPK D-6 User-Defined Exception: JobSalException D-7 Bean Class: JobsBMPBean D-8 create() and ejbCreate() D-10 Bean Class: JobsBMPBean D-11 Deployment Descriptor D-20 Creating Data Source data-sources.xml D-22 Client Class: JobsBMPClient D-24 Overview of J2EE Connector Architecture D-26 OC4J J2EE Connector Architecture D-27 What Is a Resource Adapter? D-28 Resource Adapter Deployment Descriptors D-29 Deploying Stand-Alone Resource Adapters D-30 Deploying Embedded Resource Adapters D-31 Common Client Interface (CCI) API D-32

xvi

Container-Managed Relationships (CMRs)

Copyright 2005, Oracle. All rights reserved.

Objectives
After completing this lesson, you should be able to do the following: Define relationships between entity beans Determine the cardinality and direction of a relationship Identify various elements of the deployment descriptor that define the relationship Develop CMR entity beans

Copyright 2005, Oracle. All rights reserved.

Objectives In a Java 2, Enterprise Edition (J2EE) application, it is not possible to implement the business logic in a single entity bean. It is practical to identify the smaller tasks and implement them using CMP entity beans. These entity beans may operate on persistent data that is related. You can capture such relationships with Container-Managed Relationships (CMR). This lesson introduces you to the steps of specifying a relationship between CMP entity beans. In this lesson, you create CMP beans that contain relationships of different cardinality and directionality.

Oracle 10g: Build J2EE Applications 15-2

Relationships

Copyright 2005, Oracle. All rights reserved.

Relationships Enterprise applications typically deal with data in multiple tables. These tables are related and together constitute the complete data for the application. It is a challenging task to model the relationship between objects and tables in the database. Enterprise JavaBeans (EJB) 2.0 addresses this by introducing CMR. The slide shows the relationship between two tables: DEPARTMENTS and EMPLOYEES. Though only two tables are involved in the relationship, there can be multiple relationships established between them. Some of the relationships shown in the slide are: Departments may have one Employee Departments may have many Employees Employees may have one Departments

Oracle 10g: Build J2EE Applications 15-3

Implementing Relationships
Data manipulation in the beans may involve a more complex data model, with a relationship between entity beans. The important aspects of a relationship are:
Cardinality: Number of data instances that can participate in a relationship

Direction: Direction in which a relationship is navigated

Copyright 2005, Oracle. All rights reserved.

Implementing Relationships Data manipulation in the beans may involve a more complex data model, with relationships between database tables or between entity beans. For example, more than one employee has the same job ID, or more than one employee works for a department. The relationship is specified through a foreign key in the database tables. How do you represent the data model between two entity beans, each of which represents one object within the relationship? In CMP beans, the container manages the relationship based on the relationship definition that is defined in the deployment descriptor. In BMP beans, the bean provider provides the logic for managing the relationship through callback methods. The important aspects of a relationship are cardinality and direction.

Oracle 10g: Build J2EE Applications 15-4

Cardinality and Direction of Relationships


Cardinality:
One-to-one One-to-many or many-to-one Many-to-many

Directionality:
Unidirectional Bidirectional

Copyright 2005, Oracle. All rights reserved.

Cardinality and Direction of Relationships Cardinality: Cardinality is also referred to as multiplicity. Cardinality is the number of instances of data that can participate in a relationship. It refers to the number of entities on each side of the relationship. Cardinality can be of the following types: One-to-one relationship (1:1): There is exactly one-to-one mapping between the two objects that are involved in the relationship. For example, each employee has only one address and each address maps to only one employee. One-to-many relationship (1:M): This is the most common form of relationship. One row in the first object maps to many rows in the other object. For example, one department can have many employees but one employee can work for only one department. Many-to-many relationship (M:N): Many entities in each side of the relationship take part in an M:N relationship. For example, each employee may work on multiple projects and each project is assigned to many employees.

Oracle 10g: Build J2EE Applications 15-5

Cardinality and Direction of Relationships (continued) Direction: Direction in which to navigate a relationship. Direction applies to all cardinalities of the relationship. Direction can be of two types: Unidirectional: Unidirectional relationship is where you can navigate from entity A to entity B only. Navigation from entity B to A is restricted. Consider the example of browsing through a dictionary. If you have a word, you can look for the meaning or definition. But, you would not want to search for a word with its meaning or definition. If you design your relationship such that employees know their departments but departments do not know all the employees, then it is unidirectional. Bidirectional: Bidirectional relationship is where you can navigate from object A to object B and also in the reverse direction. If you design your relationship such that employees know their departments and the departments too know all the employees, then it is bidirectional. In simple terms, if you can find out the department of an employee with employee information and find the employee with department information, then it is bidirectional.

Oracle 10g: Build J2EE Applications 15-6

One-to-One Relationships

The phone_num column is the foreign key in the EMP entity that is referencing the PHONE entity. Each employee has only one phone number and each phone number belongs to only one employee.
EMP emp_id 100 name Smith phone_num 111 1111

PHONE phone_num 111 1111

area_code 650

service MCI

Copyright 2005, Oracle. All rights reserved.

One-to-One Relationships Assume that each employee has only one mobile phone number and each mobile phone number belongs to only one employee. The diagram in the slide shows this 1:1 relationship between the EMP and PHONE tables. The phone_num column is the foreign key in the EMP table that is referencing the PHONE table. The association table helps in creating a relationship between nonassociated tables. You can create an association table for a relationship with any cardinality. For CMP beans with a one-to-many relationship, the server creates a default association table.

Oracle 10g: Build J2EE Applications 15-7

One-to-Many Relationships
Each department exists in only one location identified by location_id, whereas each location can contain many departments (1:M).
LOCATIONS location_id 1700 DEPARTMENTS department_id 10 30

city Seattle

department_name Administration Purchasing

location_id 1700 1700

Copyright 2005, Oracle. All rights reserved.

One-to-Many Relationships In the example in the slide, each department exists only at one location. But, each location can contain many departments. The diagram in the slide shows this 1:M relationship between the DEPARTMENTS and LOCATIONS tables. The location_id column is the foreign key in the DEPARTMENTS table that is referencing the LOCATIONS table. This column is also the primary key of the LOCATIONS table. For each key value in the LOCATIONS table, there may be more than one matching row in the DEPARTMENTS table.

Oracle 10g: Build J2EE Applications 15-8

Many-to-Many Relationships
Each employee may be assigned many jobs and each job may be assigned to many employees.
EMPLOYEES employee_id 176 ASSIGNMENTS assign_pk A1 JOBS_HISTORY job_id SA_REP Name Jonathon

employee_id 176

job_id SA_REP

... ...

Copyright 2005, Oracle. All rights reserved.

Many-to-Many Relationships In many-to-many relationships, more than one row from entity A maps to more than one row from entity B. For example, one employee can be assigned to more than one job and one job can be assigned to more than one employee. This type of a relationship is the most difficult to manage. In relational database design, the many-to-many relationships are normalized by introducing another table that contains foreign keys to both of the original tables. However, it is not mandatory to define an entity corresponding to the associating table, such as ASSIGNMENTS, when defining a many-to-many relationship between entity beans. The example in the slide shows the additional ASSIGNMENTS table that contains foreign keys that reference the EMPLOYEES table (employee_id column) and the JOBS_HISTORY table (job_id column). To understand this example better, consider an employee with employee_id 176. Check the job_id of this employee from the JOBS_HISTORY table. You will see two job IDs: SA_REP and SA_MAN. Now check the employees who have SA_REP as job_id in the EMPLOYEES table. The query will return 30 rows. Therefore, one employee can be assigned more than one job and each job can be assigned to more than one employee.
Oracle 10g: Build J2EE Applications 15-9

Oracle TopLink
Oracle TopLink run-time framework: Facilitates data integration with enterprise applications Facilitates rapid development, deployment, and execution of all persistence-related aspects of any Java application
SQL TopLink Java application JDBC Rows

Copyright 2005, Oracle. All rights reserved.

Oracle TopLink Oracle TopLink (TopLink) allows Java applications to access data stored in relational databases as objects. Application developers are able to work with relational databases much as they would in any Java application regardless of persistence. With TopLink, developers focus on the application and object model rather than the infrastructure of the database. TopLink can map Java objects to an existing (legacy) database or can suggest a new database schema from an object model (or vice versa). It provides a rich set of features to read, write, delete, and manage objects efficiently. The mature, robust persistence framework provided by TopLink significantly reduces the risk of using a relational database in a Java application.

Oracle 10g: Build J2EE Applications 15-10

TopLink: Integration of J2EE Applications with Data Sources at Run Time

SQL server EIS

J2EE Application Server Servlets/JSPs EJBs

Oracle

XML Data mapping and integration DB2


Copyright 2005, Oracle. All rights reserved.

TopLink: Integration of J2EE Applications with Data Sources at Run Time In general, TopLink works in any architecture. Entity Beans Bean-managed persistence (BMP) in any compliant application server Container-managed persistence (CMP) in WebLogic and WebSphere Java Objects TopLink can manage persistence of Java objects in any J2EE architecture. Moreover, because TopLink is written in Java, it will work in any compliant J2EE application server.

Oracle 10g: Build J2EE Applications 15-11

TopLink: Integrated with Oracle JDeveloper 10g

Copyright 2005, Oracle. All rights reserved.

TopLink: Integrated with Oracle JDeveloper 10g TopLink is integrated with Oracle JDeveloper 10g. The TopLink Mapping Editor enables you to graphically configure TopLink deployment descriptors and map your Java classes and EJBs to database tables. You can create Java objects from tables or TopLink Mapping Descriptor as shown in the slide. You can reverse engineer your CMP EJBs by creating EJBs from tables. You can specify TopLink as the persistence manager while creating EJBs. When you select this option, the TopLink mapping structure is shown. This will help you identify the relationship between the fields of two entity beans.

Oracle 10g: Build J2EE Applications 15-12

Implementing Relationships
Relationship restrictions:
Define only for CMP 2.0 entity beans Declare related CMP beans in one deployment descriptor Use only local interfaces to define the relationship

Define abstract get() and set() accessor methods in the bean class for each relationship field In the deployment descriptor, define:
Name of each relationship Cardinality and direction for each relationship One section for each side of a bidirectional relationship Cascade delete operations on one side of the relationship
Copyright 2005, Oracle. All rights reserved.

Implementing Relationships You can define relationships only for CMP 2.0 entity beans. If you want to define relationship between two entity beans, then the entries for the relationship must be in the same deployment descriptor. The relationship between the CMP 2.0 entity beans is managed by the container. You must define only local interfaces for entity beans that take part in relationships. Defining relationships: You define a relationship in the deployment descriptor of the beans. There is only a single deployment descriptor for entity beans that take part in relationships. The deployment descriptor includes tags for information such as cardinality, direction, field name, field type, and so on. The methods that support the relationship defined in the deployment descriptor are included in the local interface and the bean class. The entity beans that take part in relationships can have only local interfaces. These local interfaces must have setter and getter methods corresponding to name of the fields. For example, consider a unidirectional one-to-one relation: an employee can have only one address. You will design two beans: employee bean and address bean. To define the relationship, the local interface of the employee bean should have the getAddress()and setAddress(Address ad)methods. These methods must be included in the implementation class as abstract methods. These methods are implemented by the container.
Oracle 10g: Build J2EE Applications 15-13

Defining Abstract Accessor Methods

Name:
get<cmrfieldname> and set<cmrfieldname> Example: getDepartment(), setEmployees(EmpLocal emp)

Return type:
Local interface of the target bean for single object retrieval Collection or set of local interface objects for multiple object retrieval

Location where it is defined:


Only in the source bean for unidirectional relationship In both beans for bidirectional relationship
Copyright 2005, Oracle. All rights reserved.

Defining Abstract Accessor Methods Each relationship field must have the abstract accessor methods defined for it. The name of an accessor method for a CMR field starts with get or set and is followed by the CMR field name (with an uppercase initial letter). For example, if a CMR field that represents an entity bean is department, then the get()accessor method would be getDepartments(). If you have defined only get()methods in the local interface, then these fields are considered read-only fields. However, the implementation class should have both set and get methods. In the bean class, the setter and getter methods for the CMP fields are abstract (without implementation) because the EJB container implements them. The bean developer must explicitly code the details to implement the relationship in BMP beans. In a relationship that sets or retrieves only a single entity, the object type that is passed back and forth must be the local interface of the target entity bean. In a relationship that sets or retrieves multiple objects, the object type passed back and forth is a Set or Collection containing local interface objects. For a unidirectional relationship, only the source bean defines the abstract accessor methods for the target bean. In a bidirectional relationship where both beans can access each other, each bean defines the accessor methods for the other bean. For entities in one-to-one and many-to-many relationships, either of the entities can be the source entity. For entities in one-to-many relationships, the entity on the one side is the source. For entities in many-to-one relationships, the entity on the many side is the source.
Oracle 10g: Build J2EE Applications 15-14

Accessor Methods in 1:1 Relationships


For bidirectional relationships, define abstract get() and set() accessor methods for CMR fields in both the abstract bean classes.
public abstract class Emp implements EntityBean { ... public abstract PhoneLocal getPhone_PhoneNo(); public abstract void setPhone_PhoneNo(PhoneLocal p);

...
public abstract class Phone implements EntityBean { ... public abstract EmpLocal getEmp_EmployeeID(); public abstract void setEmp_EmployeeID(EmpLocal e); ...

Copyright 2005, Oracle. All rights reserved.

Implementing 1:1 Relationships The container manages relationships by implementing the abstract accessor methods that are defined in the abstract bean class corresponding to the CMR fields that are specified in the deployment descriptor. The bean developer provides a null implementation for the ejbLoad()and ejbStore()methods, unlike in BMP beans. The code in the slide defines the relationship between the Emp and Phones CMP entity bean classes. Both the Emp and the Phone beans declare the get() and set() accessor methods for each other because they have a bidirectional relationship. If there is a unidirectional one-toone relationship between the beans, then only the bean at the source side of the relationship (Emp) declares the accessor methods. Note: Note that the CMR field names need not be the same as the names of the entity beans.

Oracle 10g: Build J2EE Applications 15-15

Accessor Methods in 1:M Relationships


public abstract class DepartmentsBean implements EntityBean { ... public abstract LocationsLocal getLocations_locationId(); public abstract void setLocations_locationId (LocationsLocal locations_locationId); ... public abstract class LocationsBean implements EntityBean { ... public abstract Collection getDepartments_locationId(); public abstract void setDepartments_locationId(Collection departments_locationId);

...

Copyright 2005, Oracle. All rights reserved.

Accessor Methods in 1:M Relationships The code in the example shows a one-to-many bidirectional relationship between the Departments and the Locations entity beans. Because each department can exist only in one location, the Departments bean uses a single Locations local interface object in its accessor methods on the Locations entity. Because there can be many departments in a location, the Locations entity bean uses a collection of Departments local interface objects in its accessor methods on the Departments entity. You can also use Set instead of Collection. In a many-to-many bidirectional relationship, both the source and the target beans define accessor methods for each other and use a collection of local interface objects.

Oracle 10g: Build J2EE Applications 15-16

Checking Relationship Mappings in JDeveloper

Copyright 2005, Oracle. All rights reserved.

Checking Relationship Mappings in JDeveloper After you have created the entity beans that take part in the relationship, you can check the relationship mappings. Right-click the bean and select Edit CMP mappings. Click the Relationship Mappings tab to see the mappings. The slide shows the relationship mappings of the Departments and Locations entities.

Oracle 10g: Build J2EE Applications 15-17

Accessor Methods in M:N Relationships

public abstract class EmployeesBean implements EntityBean { ... public abstract Collection getJobHistory_employeeId(); public abstract void setJobHistory_employeeId (Collection jobHistory_employeeId); ... } public abstract class JobHistoryBean implements EntityBean { ... public abstract Collection getEmployees_employeeId(); public abstract void setEmployees_employeeId (Collection employees_employeeId); ... }

Copyright 2005, Oracle. All rights reserved.

Accessor Methods in M:N Relationships In the CMP bean implementation, each table involved in the M:N relationship is represented by a CMP entity bean. The partial code example in the slide shows the accessor methods for the Employees and JobHistory many-to-many related entities.

Oracle 10g: Build J2EE Applications 15-18

Implementing a Relationship in the Deployment Descriptor

Copyright 2005, Oracle. All rights reserved.

Implementing a Relationship in the Deployment Descriptor The slide shows key elements in the deployment descriptor to represent the relationship between two entity beans that are participating in the relationship. You define the relationships between entity beans in the same deployment descriptor where the entity beans are declared. <relationships> is the main element. All relationships are defined within this element and, therefore, this element encloses information on multiple relationships. The <ejb-relation> element contains definition of each specific entity-to-entity relationship. <ejb-relation-name> is an optional descriptive tag and holds a short name to identify the relationship. <ejb-relationship-role> declares relationship details for each side of the relationship. Each <ejb-relation> element will have two <ejb-relationship-role> elements: one for each side of the relationship. These elements enclose important details such as multiplicity, cardinality, and CMR fields.

Oracle 10g: Build J2EE Applications 15-19

Implementing a Relationship in the Deployment Descriptor (continued) <ejb-relationship-role-name> is an optional descriptive tag that describes each side of the relationship. Observe the first <ejb-relationship-role-name> element in the slide. It includes the description Employees-owned-by-departments_departmentId. The description clearly indicates that many employees can work in a department or many employees can have a particular department ID entry in the department_id field. <multiplicity> element defines the type of relationship: 1:1, 1:M, or M:N. The value for this tag is either One or Many. Considering the relation discussed above, many employees can work in a department and, therefore, the multiplicity must be Many. The <relationship-role-source> element defines the EJB that the relationship maps to. The <cmr-field> element defines the name and type of the CMR field. The parent entity of the relationship must declare this element. If the child entity also has a <cmr-field> element, then it is a bidirectional relationship. The type of this field can be a Collection or a Set or a single local interface object, depending on the multiplicity of the relationship.

Oracle 10g: Build J2EE Applications 15-20

Implementing 1:1 Relationships


Emp to Phone
... <relationships> <ejb-relation> <ejb-relation-name>EMP-PHONE</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Emp-has-Phone </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>Emp</ejb-name> </ relationship-role-source> <cmr-field> <cmr-field-name>Phone</cmr-field-name> <cmr-field-type>PhoneLocal</cmr-field-type> </cmr-field> </ejb-relationship-role> ...
Copyright 2005, Oracle. All rights reserved.

Implementing 1:1 Relationships The slide shows the partial deployment descriptor that is used to represent the relationship between the Emp and Phone entities, which are defined under one ejb-jar section. The EJB details of both the beans are described under separate <entity> sections of the <enterprise-beans> section. The <ejb-relation> element for these two entities contains two <ejbrelationship-role> sections, one for each of the beans. In a unidirectional relationship, you define this section only from the source bean. The <multiplicity> element in the above example indicates that the cardinality of the relationship from the Emp entity to the Phone entity is one. The <cascade-delete/> tag specifies that if the Emp entity is deleted, then the related Phone entity (a row from the database) also be deleted. The <cmr-field> section defines the name and type of the CMR field, which is the target entity bean. In the example, the CMR field for the Phone entity is of the PhoneLocal type.

Oracle 10g: Build J2EE Applications 15-21

Implementing 1:1 Relationships


Phone to Emp
... <ejb-relationship-role> <ejb-relationship-role-name> Phone-has-Emp </ejb-relationship-role-name> <multiplicity>One</multiplicity> <cascade-delete /> <relationship-role-source> <ejb-name>Phone</ejb-name> </ relationship-role-source> <cmr-field> <cmr-field-name>Emp</cmr-field-name> <cmr-field-type>EmpLocal</cmr-field-type> </cmr-field> </ejb-relationship-role> </ejb-relation> </relationships> ...
Copyright 2005, Oracle. All rights reserved.

Implementing 1:1 Relationships (continued) The deployment descriptor tags in the slide show the EJB relationship role from the Phone entitys side. Multiplicity from the Phone entity side is also one. Thus, this is a bidirectional 1:1 relationship. <cascade-delete/>: In many situations, child data has no meaning without parent data. If a parent is deleted from the system, then the child record should also be deleted. You can specify this behavior by using the <cascade-delete/> tag. The tag can only be assigned to a child entity bean with a multiplicity of one or many that has a parent with a multiplicity of one. The <cascade-delete/> tag in the example clearly indicates that if an EmpBean is removed, then a PhoneBean should also be removed. If an employees details is removed from the emp table, then the employees phone details must be removed from the phone table.

Oracle 10g: Build J2EE Applications 15-22

Implementing 1:M Relationships


Departments to Locations
<relationships> <ejb-relation> <ejb-relation-name>Departments-Locations </ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name>Locations-hasdepartments_locationId </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>Locations</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>departments_locationId </cmr-field-name> <cmr-field-type>java.util.Collection </cmr-field-type> </cmr-field> </ejb-relationship-role>...

Copyright 2005, Oracle. All rights reserved.

Implementing 1:M Relationships The deployment descriptor tags in the slide show a one-to-many relationship between the Departments and Locations entities. This shows the details of one side of the relationship. You can understand the relationship by looking at the <ejbrelationship-role-name> tag. The tag indicates that one department can have only one location ID. That is, a department can exist in only one location and, therefore, the multiplicity is one.

Oracle 10g: Build J2EE Applications 15-23

Implementing 1:M Relationships


Locations to Departments
... <ejb-relationship-role> <ejb-relationship-role-name>Departments-owned-bylocations_locationId </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <relationship-role-source> <ejb-name>Departments</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>locations_locationId </cmr-field-name> </cmr-field> </ejb-relationship-role> ...

Copyright 2005, Oracle. All rights reserved.

Implementing 1:M Relationships (continued) The deployment descriptor tags in the slide show the many side of the relationship between the Locations and Departments entities. The multiplicity specifies that each location can contain many departments.

Oracle 10g: Build J2EE Applications 15-24

Implementing M:N Relationships


... <ejb-relation> <ejb-relation-name>JobHistory Employees </ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> JobHistory-has-employees_employeeId </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <relationship-role-source> <ejb-name>JobHistory</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>employees_employeeId </cmr-field-name> <cmr-field-type>java.util.Collection </cmr-field-type> </cmr-field> </ejb-relationship-role> ...

Copyright 2005, Oracle. All rights reserved.

Implementing M:N Relationships The deployment descriptor tags in the slide show the relationship between the JobHistory and Employees entities. The multiplicity specifies that many employees can be assigned many jobs. Looking at the <ejb-relationship-role-name> and <multiplicity> tags, you can interpret the relation as the JobHistory entity can have multiple occurrences of employee ID. Because many employees can be assigned to a job, the result of the CMR get() accessor method would be a Collection of EmployeesLocal local interface objects. Note: You cannot specify <cascade-delete/> with many-to-many relationships because there is no single row on which another row is dependent. For example, in a one-tomany relationship between Departments and Locations, for one location, there are many departments. If you delete one master location, you can choose to delete all the child department rows. In a many-to-many relationship between Employees and JobHistory, if you delete one job you cannot delete employees working on that project, because the employees can work on more than one project and, thus, should be retained in the table.

Oracle 10g: Build J2EE Applications 15-25

Implementing M:N Relationships

<ejb-relationship-role> <ejb-relationship-role-name> Employees-has-jobHistory_employeeId </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <relationship-role-source> <ejb-name>Employees</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>jobHistory_employeeId </cmr-field-name> <cmr-field-type>java.util.Collection </cmr-field-type> </cmr-field> </ejb-relationship-role>

Copyright 2005, Oracle. All rights reserved.

Implementing M:N Relationships (continued) The tags in the slide show the other side of the relationship between the JobHistory and Employees entities.

Oracle 10g: Build J2EE Applications 15-26

Mapping Relationship Fields to Database


Accept default mapping provided by container (specify relationship fields in ejb-jar.xml) Explicitly map the fields to existing table columns in orion-ejb-jar.xml

Copyright 2005, Oracle. All rights reserved.

Mapping Relationship Fields to Database Each entity bean maps to a table in the database. Each of its persistent and relationship fields are saved within a database table in columns. To map these fields to a database, you must either: Accept the defaults for these fields and avoid more deployment descriptor configuration, (The default mapping for relationship fields is similar to the mapping for CMP fields, discussed in the lesson titled Achieving State Management in the Business Tier.) or Map the fields to the columns in a table that already exists in a designated database. Persistent data mapping is configured within the orion-ejb-jar.xml file.

Oracle 10g: Build J2EE Applications 15-27

Default Mapping of Relationship Fields


Database: Specified in data-sources.xml Each table in relationship: Same as for CMP entity Columns in each table: Based on <cmr-field>, which represents a bean in the relationship For each <cmr-field> of an entity, the container creates a foreign key to the primary key of the related entity:
In the source bean table for one-to-one mapping In a container-generated association table for oneto-many and many-to-many relationships

User-defined or automatically generated primary key


Copyright 2005, Oracle. All rights reserved.

Default Mapping of Relationship Fields The database is specified in the data-sources.xml file. One table is created for each entity in the relationship. Similar to the CMP bean table, the table name is a unique combination of EJB name, Java Archive (JAR) file, application name, an underscore, and a five-character hash code. The container generates columns in each table based on the <cmp-field> and <cmrfield> elements. Each <cmp-field> is a column that relates to the entity bean data. Each <cmr-field> element represents a relationship (entity). For each <cmr-field> element, the container creates a foreign key that points to the primary key of the related entity object, as follows: In a one-to-one relationship, the foreign key is created in the database table for the source EJB and is directed to the primary key of the target database table. In one-to-many, many-to-one, and many-to-many relationships, an association table (third table) is created. The association table contains two foreign keys, each pointing to the primary key of one of the entity tables. The translation rules for converting Java data types to database data types are defined in the specific database XML file, such as oracle.xml, located in j2ee/home/config/database-schemas.
Oracle 10g: Build J2EE Applications 15-28

Default Mapping of Relationship Fields (continued) Both entity tables contain primary keys. The primary key can be defined or automatically generated. A defined primary key is generated as designated in the primary key class or as a simple data type. If you specify java.lang.Object as the primary key class type in <prim-key-class>, but do not specify the primary key name in <primkey-field>, then the primary key is automatically generated by the container.

Oracle 10g: Build J2EE Applications 15-29

Explicit Mapping of Relationship Fields


1. Deploy your application with only the ejbjar.xml elements configured. 2. Copy the container-created orion-ejb-jar.xml file to your development environment. 3. Modify the <entity-deployment> element in the orion-ejb-jar.xml file to use the database table and columns that you specify. 4. Rearchive and redeploy your application.

Copyright 2005, Oracle. All rights reserved.

Explicit Mapping of Relationship Fields You can explicitly map the relationships between entity beans within an existing database table and its columns in the orion-ejb-jar.xml file. The process is similar for CMP field mapping. The steps for explicit mapping are listed in the slide. Note: The above-mentioned method is simple and is a common practice for specifying explicit mapping. You need not deploy your application first to obtain the orion-ejbjar.xml file. You can create an orion-ejb-jar.xml file from the beginning along with other files in your application and deploy the files together. For more information about default mapping and explicit mapping, see the OC4J Enterprise JavaBeans Developers Guide.

Oracle 10g: Build J2EE Applications 15-30

Using JDeveloper to Create CMR Beans


Using JDeveloper, you can create a containermanaged relationship between entity beans in the following ways: Create CMP beans from tables and generate default relationships between entities. Use the EJB Module Editor to specify the relationship or use TopLink Mapping Editor. Create an EJB Diagram for CMP beans and generate default relationships.

Copyright 2005, Oracle. All rights reserved.

Using JDeveloper to Create CMR Beans Using JDeveloper, you can create relationships between entity beans while creating the entities. You can also create relationships by using the EJB Module Editor or TopLink Mapping Editor. You can create an EJB Diagram and drag database tables to the diagram. The default relationships are generated.

Oracle 10g: Build J2EE Applications 15-31

Summary
In this lesson, you should have learned how to: Determine the cardinality and direction of a relationship Define and implement relationships between CMR entity beans

Copyright 2005, Oracle. All rights reserved.

Summary In this lesson, you should have learned about the different types of relationships that can be established between entity beans. You have also learned about the various tags of the deployment descriptor that determine the relationship.

Oracle 10g: Build J2EE Applications 15-32

Practice 15: Overview


This practice covers creating a one-to-many relationship between the Employees and Departments entity beans.

Copyright 2005, Oracle. All rights reserved.

Practice 15: Overview In this practice, you will use Oracle JDeveloper 10g to create Employees and Departments entity beans with a one-to-many relationship.

Oracle 10g: Build J2EE Applications 15-33

Practice 15-1 The purpose of this practice is to create Employees and Departments entity beans with a one-to-many relationship. The workspace for this practice is practice15ske.jws. Open the empdeptCMR project. This project contains the two entity beans: Employees and Departments. Note: You will use the database connection hr, which you have used for the lesson 14 practice. 1. Expand the empdeptCMR project and double click DepartmentsBean.java in the Structure Pane to open it in the editor. Examine the various methods in this class and observe that all the set() and get() methods are abstract methods. You will use the following method in your application:
public abstract Collection getEmployees_departmentId();

2. Similarly, observe the methods in EmployeesBean.java. You will use the following method in your application:
public abstract DepartmentsLocal getDepartments_departmentId();

3. Create a session bean named EmpdeptSession containing a remote interface. Enter EmpdeptSession for the EJB Name and accept all other defaults. 4. Add EJB Local References of Employees bean and Departments bean to the session bean by following these steps: a. Double-click EmpdeptSession to open the EJB Module Editor. b. Select EJB Local References and click Add. c. Select Departments from the Auto-create Reference to EJB drop-down menu and click OK. d. Click Add again and select Employees from the Auto-create Reference to EJB drop-down menu and click OK. e. Click OK to close the EJB Module Editor. f. Double-click EmpdeptSessionBean.java and see the lookup code that is added as a result of adding EJB Local References to EmpdeptSession. 5. Create Data Transfer Object (DTO) for both Employees and Departments entity bean by right-clicking the bean and selecting Generate Data Transfer Object. Note: Refer to the last page of this lesson to learn about DTOs. 6. Edit the remote interface, EmpdeptSession.java, of the session bean. Import the following: java.rmi.RemoteException and java.util.Collection. Add a method called getEmployeesInDept()that takes a Long value as argument and returns a Collection. 7. Include another method getDepartmentID()that takes a Long value as argument and returns an object of Long.

Oracle 10g: Build J2EE Applications 15-34

Practice 15-1 (continued) 8. Edit the EmpdeptSessionBean.java session bean. Import java.util.*. Implement the getEmployeesInDept() method as follows:
import java.util.*; ... public Collection getEmployeesInDept(Long deptno) { Collection returnColl = new ArrayList(); try { DepartmentsLocal dept = this. getDepartmentsLocalHome().findByPrimaryKey(deptno); // get all the employees in the particular department. // Note that you are invoking the method // getEmployees_departmentId() of the Departments bean Collection empColl = dept.getEmployees_departmentId(); // create an iterator for the collection that is returned Iterator empIter = empColl.iterator(); while(empIter.hasNext()) { // create the DTO object, get the necessary values from // the bean and populate the DTO object with those values // using the set methods. EmployeesLocalDTO empDTO = new EmployeesLocalDTO(); EmployeesLocal empBean = (EmployeesLocal)empIter.next(); empDTO.setEmployeeId(empBean.getEmployeeId()); empDTO.setFirstName(empBean.getFirstName()); empDTO.setLastName(empBean.getLastName()); // add the DTO object to the collection returnColl.add(empDTO); } } catch(Exception ex) { System.out.println(" Error getting employees in dept : "+deptno+" "+ex); } // return the collection to the client return returnColl; } Oracle 10g: Build J2EE Applications 15-35

Practice 15-1 (continued) 9. Implement the getDepartmentID()method as follows:


public Long getDepartmentID(Long empno) { Long deptno=new Long(0); try { EmployeesLocal emp =this.getEmployeesLocalHome(). findByPrimaryKey(empno); deptno = emp.getDepartments_departmentId(). getDepartmentId(); } catch(Exception ex) { System.out.println(" Error getting the department_id of employee "); } return deptno; }

10. Create the client application. Right-click the session bean and select New Sample Java Client. Select Connect to OC4J Embedded in JDeveloper and click OK. a. Edit the client and import java.util.*. b. In the main()method, use the session bean instance to invoke the getEmployeesInDept()to get the information of all employees working in department 50. Note that this method in turn invokes the getEmployees_departmentId()method of the Departments bean. c. Create an Iterator to iterate through the collection that is returned by the session bean. Typecast the object in the Iterator to EmployeesLocalDTO, retrieve the values, and print the values. Repeat this for all the objects in the collection. d. Invoke the getDepartmentID()method to get the department ID of the employee with employee_id 118. Note that this method in turn invokes the getDepartments_departmentId() method of the Employees bean. 11. Right-click EmpdeptSession and select Run. 12. Right-click EmpdeptSessionClient and select Run.

Oracle 10g: Build J2EE Applications 15-36

Practice 15-1 (continued) Sample Output: PRINTING EMPLOYEE_ID, FIRST_NAME, LAST_NAME OF EMPLOYEES IN THE DEPARTMENT 120 Matthew Weiss 121 Adam Fripp 122 Payam Kaufling 123 Shanta Vollman 124 Kevin Mourgos ...... PRINTING DEPTNO OF THE EMPLOYEE: 30 Data Transfer Object (DTO) Session beans and entity beans are categorized as server-side business components. When a client invokes a method of an entity bean through a session bean, certainly the method returns data to the client. The client may invoke multiple methods to get all the required values. The client usually is a remote client and, therefore, the question of efficient data transfer across the network comes up. You can design your business component in such a way that it returns a collection of primitive types, but this is not practical and will not serve the business needs. So it is better to use a serializable object that encapsulates all the business data that has to be passed to the client. This object will have the set() and get() methods for all the variables associated with a bean. A single method call is required to transfer the object to the client. This object is called a Data Transfer Object. The client invokes a single method of the bean (typically, session bean) instead of invoking multiple methods to get values. The bean constructs a new DTO, populates the object with all the values, and returns it to the client. The client receives the object and invokes the get() methods to retrieve the values. The advantage here is that the object is now available with the client and, therefore, all calls to the object are local calls instead of remote method invocations.

Oracle 10g: Build J2EE Applications 15-37

Developing Message-Driven Beans

Copyright 2005, Oracle. All rights reserved.

Objectives
After completing this lesson, you should be able to do the following: Describe the need for a message-oriented middleware (MOM) type Define Java Message Service (JMS) Describe and create a message-driven bean (MDB) Differentiate between a stateless session Enterprise JavaBean and a message-driven bean Configure JMS resource provider

Copyright 2005, Oracle. All rights reserved.

Objectives This lesson explains the necessity of asynchronous message delivery, and shows how a message-driven EJB can be developed, deployed, and used to process asynchronous messages. This lesson also provides an introduction of JMS and different MOM types to make the concept of message-driven beans more clear.

Oracle 10g: Build J2EE Applications 16-2

Overview of Messaging Systems


Messaging is a way for software components and/or applications to communicate. Messaging systems are peer-to-peer in nature. Clients can send or receive messages from other clients. JMS was designed to allow applications to create, send, and receive messages synchronously or asynchronously. Java Message Service allows access to existing MOM services, such as the OC4J in-memory JMS server.

Copyright 2005, Oracle. All rights reserved.

Overview of Messaging Systems Messaging systems have been around for many years in various forms. For example, an e-mail system is a form of messaging system. However, e-mail messaging is used for communication between a human user and a software system. In the J2EE world, messaging systems are used for communication between different software components or applications. They are a way for programmatically generating messages to be sent to another program. The JMS API was designed to facilitate communication between applications, and supports the creation, sending, and receiving of synchronous and asynchronous messages. To enable messages to be communicated between JMS clients, middleware is required to register destinations for messages that are published by clients, and from which a message can be received by other client applications. Typically, existing MOM services, such as the OC4J JMS server, or IBMs MQSeries software, can be used for such purposes. The JMS API was designed to be independent of vendor-specific MOM services. MOM services are usually used as JMS providers.

Oracle 10g: Build J2EE Applications 16-3

Types of Message Consumption


Messaging systems are inherently asynchronous, but JMS allows messages to be consumed in two ways: Synchronously
Receiver thread blocks until a message can be consumed or times out. Receiver acknowledges message receipt. There is tightly coupled interaction.

Asynchronously
Receiver listens for messages. When a message is delivered, the listener message handler is invoked. Receiver thread does not block. There is loosely coupled interaction.
Copyright 2005, Oracle. All rights reserved.

Types of Message Consumption Messaging systems are typically asynchronous, thereby allowing message delivery and receipt, which are independent of each other. JMS provides for synchronous or asynchronous message consumption. Synchronous Message Consumption Clients (receivers) explicitly read messages from a destination. The receiving process blocks until a message arrives or a time out occurs. This model is similar to an EJB using RMI, where the client invokes a bean method; the bean processes the request and sends the result back to the client. If the bean and its interfaces are not available (for example, the server is down), then the client is unable to complete its operation. Synchronous messaging has the sender waiting for acknowledgment of receipt from the receiver. This model has a producer send only one message to one receiver at a time, and there is a tight coupling between the sender and the receiver.

Oracle 10g: Build J2EE Applications 16-4

Types of Message Consumption (continued) Asynchronous Message Consumption In asynchronous messaging, senders do not wait for acknowledgement of receipt from the receiver. A receiver registers itself to listen for a message and is notified by an event when it is delivered. The receivers listener invokes a handler process on the arrival of the message. For example, a stock ticker need not wait for an acknowledgement from its receivers before broadcasting the stock quotes. In the asynchronous model, messages can be produced for more than one receiver at a time (that is, the sender and the receiver are not directly connected). Therefore, there is no blocking of threads in an asynchronous messaging system. This produces a loose coupling between the sender and the receiver.

Oracle 10g: Build J2EE Applications 16-5

Java Message Service (JMS)


Is a J2EE standard messaging system Can guarantee message delivery Supports messaging across multiple platforms Supports two models of communication
Point-to-point model Publish-and-subscribe model
Client application Messaging API JMS client MOM JMS client

Copyright 2005, Oracle. All rights reserved.

Java Message Service (JMS) JMS is a Java 2, Enterprise Edition (J2EE) API that is used to access enterprise-messaging systems and send asynchronous messages. The enterprise messaging system (messageoriented middleware, or MOM) enables transfer of messages among different applications over the network. By using MOM, you can send a message from one platform and receive it on a different platform. This model also supports guaranteed message delivery. Client applications communicate with each other using messaging APIs. Messaging clients send and receive messages through MOM. JMS supports two models for the communication of messages: The point-to-point model, also known as the PTP model, is based on a queue structure. This model is popular where there is one message consumer for a message. The publish-and-subscribe model, also known as the pub/sub model, is based on a topic structure. This model is popular when a message is to be delivered to more than one consumer, such as when broadcasting a message to multiple clients.

Oracle 10g: Build J2EE Applications 16-6

JMS Application Architecture


The main components of a JMS application are: JMS clients JMS provider Administered objects (in the Java Naming and Directory Interface [JNDI] namespace)
Connection factories Destinations (queues or topics)
Producer Application JMS Queue/Topic JMS client JMS provider JMS client Consumer JMS Application

Copyright 2005, Oracle. All rights reserved.

JMS Application Architecture There are different participants or components of a JMS application. A JMS client is any Java application that participates in a JMS environment. A JMS client can receive and produce messages. A JMS producer produces (sends) messages and is also known as a publisher. A JMS consumer receives (requests) messages and is also known as a subscriber. A JMS provider handles the routing and delivery of messages. Oracle provides a JMS provider in its application server and database server. Administered objects, stored in the JNDI namespace of a J2EE container, consist of: Connection factories: Used by a client to create a connection with a provider Destinations: Targets of messages that are produced, or sources of messages that are consumed by client applications, such as queues for the JMS PTP model and topics for the JMS pub/sub model A JMS application generally contains one JMS provider and more than one JMS client. The messages are sent through a messaging system called the message broker, or MOM services. The OC4J JMS, Oracle JMS, BEAs WebLogic JMS, Sun Microsystems iPlanet Message Queue, and IBMs MQSeries are some examples of JMS providers.
Oracle 10g: Build J2EE Applications 16-7

Point-to-Point Model
Senders send messages to virtual destinations. There is only one receiver for a message from a queue.
S1 M1 M2 M3 Queue2 Messaging server Queue sender M* - Message Queues (virtual destinations) M3 R3 Queue1 M1 M2 R1

S2

R2

Queue receiver

Copyright 2005, Oracle. All rights reserved.

Point-to-Point Model In the PTP model of communication, a sender sends messages to virtual destinations known as queues. A sender can send one or more messages. JMS clients who are interested in receiving the messages subscribe to queues of interest and receive messages from those queues. The sender does not wait for acknowledgment from the receiver after sending its messages. One queue can have more than one sender sending the messages and more than one receiver receiving the messages. However, one message can be delivered to only one receiver from the queue. The receiver has to pull the message that arrived at this queue. Note: The JMS specification does not define the method of distribution of messages among the receivers for a queue. It only requires the guarantee of the message delivery. Therefore, it is important to ensure that only eligible clients subscribe and receive messages from a particular queue. MDBs can make use of the PTP model of communication. However, they are more commonly designed to use the publish-and-subscribe model that is discussed in subsequent slides.

Oracle 10g: Build J2EE Applications 16-8

Publish-and-Subscribe Model
Publishers send messages to virtual destinations. One or more subscribers receive the messages.
M1 P1 M1 Topic1

S1 S2

P2

M2

Topic2 Messaging server

M2 S3 Topic subscriber

Topic publisher M* - Message

Topics (virtual destinations)

Copyright 2005, Oracle. All rights reserved.

Publish-and-Subscribe Model In the publish-and-subscribe (pub/sub) model of communication, a publisher sends messages to virtual destinations known as topics. A publisher can send one or more messages to a topic. JMS clients who are interested in receiving the messages subscribe to the topics of interest and receive messages from those topics. The publisher need not wait for acknowledgment from the subscribers to publish its messages. One topic can have more than one publisher and more than one subscriber. The messages that arrive to this topic are automatically sent to the subscribers. The publisher is not concerned whether there are any subscribers receiving the messages. A subscriber for a topic can specify a filter (for example, to receive only messages of priority 1). A topic subscriber may request either a durable or nondurable subscription. A durable subscription ensures that the message is delivered to the subscriber whenever it is active. That is, if a subscriber is not connected to the system when the message was broadcast, the message broker ensures that the subscriber receives the message whenever it is active. Examples for pub/sub model communication are stock quote broadcasting and airline arrival and departure information.

Oracle 10g: Build J2EE Applications 16-9

Using JMS Interfaces


The JMS API service uses the following objects and interfaces that are located in the javax.jms package: JMS-administered objects:
Connection Factory: Creates connections Destination: Target/source of messages

Connection: Creates sessions Session: Creates a message producer or consumer Message Producer: Sends to a destination Message Consumer: Receives from a destination Message: The body of the information to be communicated
Copyright 2005, Oracle. All rights reserved.

Using JMS Interfaces The JMS API provides interfaces for the production and consumption of messages. The message provider (or infrastructure) must be first configured to hold connection factories and destinations, as created by server administrators, by specifying them in XML deployment descriptors. An application uses the connection factory interfaces to open a connection to the JMS provider, through one of the following two types of connection factory interfaces: javax.jms.QueueConnectionFactory (for the point-to-point model) javax.jms.TopicConnectionFactory (for the publish/subscribe model) The queue interfaces in the javax.jms package are: QueueConnection: Created from a QueueConnectionFactory QueueSession: Created from a connection for producers and consumers to interact QueueSender: Created from a session to produce messages on a Queue QueueReceiver: Created from a session to consume messages from a Queue Queue: Is the destination for messages

Oracle 10g: Build J2EE Applications 16-10

Using JMS Interfaces (continued) The topic interfaces in the javax.jms package are: TopicConnection: Created from a TopicConnectionFactory TopicSession: Created from a connection to publish and subscribe to a Topic TopicPublisher: Created from a session to publish messages to a Topic TopicSubscriber: To subscribe to a session and consume messages from a Topic Topic: Is the destination of messages A Message object can be sent to a queue, or published to a topic, and received by the consumer. Choosing Between the Two Models A JMS application can use both models: PTP for some messages and pub/sub for other messages. The JMS 1.0.2 specification does not require a JMS provider to support both the models. The EJB 2.0 specification requires the EJB server vendor to support both the models. Generally, you use the pub/sub model when your message needs to be broadcast to more than one subscriber. Using this model allows subscribers to filter the messages that they receive. Use the PTP model when your message needs to be processed by only one receiver.

Oracle 10g: Build J2EE Applications 16-11

JMS Message Structure


JMS messages are composed of the following parts: A header containing a common set of header fields
Field examples: JMSMessageID and JMSDestination Field values are used by clients and providers for identification and routing information.

Properties for application-defined property values, which can be used for message filtering purposes A body for the contents of the message, whose contents can be structured as a StreamMessage, MapMessage, TextMessage, ObjectMessage, or ByteMessage
Copyright 2005, Oracle. All rights reserved.

JMS Message Structure A message structure has the following components: A header that has standard fields such as JMSMessageID and JMSDestination for the destination, priority of the message, and so on Properties of the message such as any user-defined name-value pairs of properties Message body, which contains the actual message. The five types of messages are: - TextMessage for a simple string. Methods: getText() and setText() - MapMessage for an unordered set of name string and values pairs. Values can be primitive types. Methods: get() and set() methods for different Java types. - BytesMessage for a stream of bytes (uninterpreted) - StreamMessage for a stream of primitive values serially processed - ObjectMessage for a serialized Java object. Methods: getObject() and setObject() The javax.jms.Message interfacea superinterface for the five message typescan be used to send a message with an empty body. The Message interface defines the get() and set() methods to manage message contents. For more information, refer to the JMS API documentation. A JMS client can filter the message that it receives by specifying conditional expressions in the message selector, using standard header fields or application-defined property values.
Oracle 10g: Build J2EE Applications 16-12

Sending a Message to a Queue


The code steps to send a message to a JMS queue are: 1. Connect to the naming server using JNDI. 2. Obtain a QueueConnectionFactory. 3. Obtain the name and location of Queue. 4. Open a QueueConnection and start it. 5. Create a QueueSession. 6. Create a QueueSender from the session. 7. Create the Message and set the header, body, and properties. 8. Send the message and close resources.
Copyright 2005, Oracle. All rights reserved.

Sending a Message to a Queue The slide shows the sequence of steps involved in sending a message to a JMS queue. The code example listed here demonstrates these steps:
Context ctx = new InitialContext(); QueueConnectionFactory cf = (QueueConnectionFactory) ctx.lookup( "java:comp/env/jms/QueueConnectionFactory"); QueueConnection conn = cf.createQueueConnection(); conn.start(); QueueSession sess = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) ctx.lookup("java:comp/env/jms/demoQueue"); QueueSender sender = sess.createSender(queue); TextMessage message = sess.createTextMessage(); message.setLongProperty("msgid", msgId); message.setText("Hello World"); sender.send(message); sender.close(); sess.close(); conn.close();

Note: The code should be enclosed in an appropriate try/catch block.


Oracle 10g: Build J2EE Applications 16-13

Sending a Message to a Queue (continued) Sending a Message to a Topic The following are the steps for publishing a message to a JMS topic, which are similar to those for sending a message to a queue: 1. Connect to the naming server by using JNDI. 2. Obtain a connection factory for the JMS provider that hosts the desired topic. 3. Obtain the name and location of the topic. 4. Open a connection to the JMS provider by using the connection factory. 5. Create a JMS session and obtain a topic object by using the JMS session. 6. Create a topic publisher that is used to publish messages. 7. Create the message that is to be published. 8. Publish the message to the topic. Here is a code snippet of publishing a message to an OC4J JMS topic:
Context ctx = null; TopicConnectionFactory cf = null; TopicConnection conn = null; TopicSession sess = null; Topic topic = null; TopicPublisher publisher = null; TextMessage message = null; ctx = new InitialContext(); cf = (TopicConnectionFactory) ctx.lookup( "java:comp/env/jms/TopicConnectionFactory"); topic = (Topic) ctx.lookup("java:comp/env/jms/demoTopic/topic1"); conn = cf.createTopicConnection(); sess = conn.createTopicSession(true, Session.AUTO_ACKNOWLEDGE); publisher = topicSess.createPublisher(topic); message = sess.createTextMessage(); message.setText("Hello World"); publisher.publish(message);

Oracle 10g: Build J2EE Applications 16-14

Receiving Messages
The following are the steps to receive a message from a topic for non-MDB applications: 1. Connect to the JNDI naming service. 2. Look up for the connection factory and the source of the message. 3. Create a TopicConnection object. 4. Create a TopicSession object. 5. Create a TopicSubscriber (or queue receiver) to receive a message. 6. Subscribe (or receive) a message. 7. Write code to process the message contents.
Copyright 2005, Oracle. All rights reserved.

Receiving Messages The slide indicates the sequence of steps involved in receiving a message. The following are the code lines for each step: 1. Context ctx = new InitialContext(); 2. TopicConnectionFactory tcf = (TopicConnectionFactory) ctx.lookup("..."); Topic t = (Topic) ctx.lookup("..."); 3. TopicConnection tc = tcf.createTopicConnection(); 4. TopicSession tsess = tc.createTopicSession( false, Session.AUTO_ACKNOWLEDGE); 5. TopicSubscriber tsub = tsess.createSubscriber(t); 6. TextListener tl = new TextListener(); // TextListener implements MessageListener tsub.setMessageListener(tl); 7. Write the code to process the message contents in the onMessage() method of the TextListener class.

Oracle 10g: Build J2EE Applications 16-15

Asynchronous Message Delivery


In an asynchronous messaging model, the consumer implements a MessageListener interface. The MessageListener interface declares an onMessage() method and notifies the consumer of the arrival of messages. MDBs are J2EE implementations for message listeners. A sender is not notified when the MDB processes the message.

Copyright 2005, Oracle. All rights reserved.

Asynchronous Message Delivery The publish-and-subscribe or point-to-point communication models (discussed earlier in this lesson) can deliver the messages either synchronously or asynchronously. In a synchronous message delivery model, the consumer registers for a publisher (topic or queue) of interest and waits to receive a message from the message server. Therefore, the publisher is blocked until the consumer receives the message, the connection is timed out, or the consumer closes the connection. In an asynchronous message delivery model, a consumer registers for a publisher but may not wait for a message from the message server. The consumer implements a MessageListener interface. This interface defines an onMessage() method, which takes the incoming message from a publisher as a parameter and processes the message. The message server invokes this callback method when a message arrives from the publisher with which the consumer is registered. The message server informs the consumer of the arrival of the message. The asynchronous message delivery model is used by an MDB in a J2EE environment. A message-driven bean is a type of message listener object. When the onMessage() method of the MDB is invoked asynchronously, a sender is not automatically notified that the message has been processed. However, the MDB can send an acknowledgement message to a JMS Destination if the sender is designed to receive it.
Oracle 10g: Build J2EE Applications 16-16

Message-Driven Beans
MDBs: Are programmed for receiving and processing asynchronous messages through the JMS Destination Are stateless, server-side, transaction-aware components Are not accessible directly by any client Do not contain home and component interfaces Are triggered by a container when a message arrives Implement the javax.ejb.MessageDrivenBean and javax.jms.MessageListener interfaces
Copyright 2005, Oracle. All rights reserved.

Message-Driven Beans You have learned that any Java application can be a consumer for the messages that arrive from the JMS publishers. Web applications are accessible through HTTP, and session or entity EJBs are accessible through RMI/IIOP. If a Web application or a session bean contains a method that listens for a message from a topic (or queue), the method looks up the connection factory and creates a connection, a session, and a subscriber. The method then waits to receive the message from the publisher. If there are no messages to be received, then the methods thread is blocked and the client has to wait until the message is received, and the wait may never end. Therefore, it is not good practice to block a thread while listening for JMS messages in a Web application, or a session or an entity EJB. A solution to avoid infinite waiting in the message listener is to call the receive() message method with a timeout, or to implement the receiveNoWait() method. The EJB 2.0 specification defines the MDB as a new EJB type designed to receive and process messages delivered asynchronously through the JMS architecture. MDBs are stateless. They reside in the server and can participate in transactions. MDBs are invoked through JMS and not RMI/IIOP, and they are never directly accessed from any client application. Therefore, MDBs do not contain home and remote interfaces. They are triggered by the container when a message is received at its destination.
Oracle 10g: Build J2EE Applications 16-17

MDB Architecture

OC4J

Client

MDB

JMS resource provider

Queue/Topic

Copyright 2005, Oracle. All rights reserved.

MDB Architecture The diagram in the slide shows an overview of MDBs with the OC4J JMS resource provider. MDBs can use OC4J JMS or Oracle JMS as resource providers. To configure OC4J JMS as a resource provider, specify the following in the jms.xml file: <queue>: The JNDI location of the queue <topic>: The provider-specific name and location for the topic <queue-connection-factory>: The JNDI path for the connection factory <topic-connection-factory>: The JNDI path for the topic connection factory <xa-queue-connection-factory>: The provider name and location for the XA queue <xa-topic-connection-factory>: The provider name and location for the XA topic connection factory <log>: The file name or e-mail address to send log messages for the OC4J queue The MDB is declaratively associated with the OC4J JMS provider destination in the J2EE and OC4J deployment descriptors. A JMS session is established to receive messages from the destination in the onMessage() method of the MDB.

Oracle 10g: Build J2EE Applications 16-18

Associating JMS Resources with an MDB


Use the J2EE and OC4J deployment descriptors to specify the JMS resources associated with an MDB. ejb-jar.xml:
<message-driven> ... <ejb-name>MessageProcessor</ejb-name> ... <message-driven-destination> <destination-type>javax.jms.Queue</destination-type> </message-driven-destination> </message-driven>

orion-ejb-jar.xml:
<enterprise-beans> <message-driven-deployment max-instances="-1" name="MessageProcessor" connection-factorylocation="jms/QueueConnectionFactory" destinationlocation="jms/demoQueue" min-instances="0"/> </enterprise-beans>
Copyright 2005, Oracle. All rights reserved.

Associating JMS Resources with an MDB The JMS resource type is specified in the J2EE deployment descriptor (ejb-jar.xml). The <message-driven-destination> child element of the <message-driven> element contains a <destination-type> element whose value can be either javax.jms.Queue or javax.jms.Topic. The <destination-type> value chosen must be consistent with the JMS element type, such as <queue> or <topic> in jms.xml, whose JNDI location name is used as the value for the MDBs destination-location attribute in the orion-ejb-jar.xml file. Setting the actual resources used by the MDB is done in the OC4J-specific deployment descriptor, orion-ejb-jar.xml. The two JMS resources that must be specified are: A location for a topic or queue connection factory A location for a topic or queue destination These resources are set in the connection-factory-location and destination-location attributes of the beans <message-driven-deployment> element, respectively.

Oracle 10g: Build J2EE Applications 16-19

State Diagram of an MDB

Does not exist Container invokes Class.newInstance, setMessageDrivenContext(context) and ejbCreate()

Container invokes ejbRemove()

Method-ready pool

Container invokes onMessage()

Copyright 2005, Oracle. All rights reserved.

State Diagram of an MDB The state diagram of an MDB is identical to that of a stateless session bean. The container invokes the newInstance() method on the bean class to create a new instance. Then the container invokes the setMessageDrivenContext(sessCtx) and ejbCreate() methods on the bean instance. A bean instance is ready in the methodready pool. When a client publishes a message, the container assigns one of the bean instances from the pool to the consumer and invokes the onMessage() method on the bean instance. This method performs the logic to process received messages. The life of an MDB ends when the container invokes the ejbRemove() method on the bean instance. The container removes a bean instance from the available pool when the instance is no longer required.

Oracle 10g: Build J2EE Applications 16-20

State Diagram of an MDB (continued) Because MDBs do not maintain a conversational state, a pool of instances can be created by the container so that each MDB instance can receive one message at a time. Therefore, the container can use additional MDB instances in the pool to receive and process other messages concurrently. One MDB can listen to more than one publisher. But an MDB is specific to one topic or queue from which it receives messages. These details are specified in the deployment descriptor of the bean. The container takes care of the environment settings such as transactions, security, concurrency, message acknowledgement, and so on. MDBs implement two interfaces: javax.ejb.MessageDrivenBean and javax.jms.MessageListener. Why does it implement two interfaces? The MessageDrivenBean interface is similar to the SessionBean and EntityBean interfaces of session and entity beans. The MessageListener interface is specific to JMS. Currently, MDBs can listen only to JMS messages. The MessageListener interface contains an onMessage() method that is specific to JMS. This method processes the messages that it receives.

Oracle 10g: Build J2EE Applications 16-21

Developing MDBs
1. Configure Oracle Application Server 10g Containers for J2EE (OC4J) with the JMS provider details. 2. Implement the bean class. 3. Configure deployment descriptors:
a. Destination type for the bean in ejb-jar.xml b. Connection factory and destination JNDI locations in orion-ejb-jar.xml

4. Create the EJB JAR file that contains the bean and the deployment descriptors. 5. Create the .ear file and deploy the bean.

Copyright 2005, Oracle. All rights reserved.

Developing MDBs The slide lists the sequence of steps that are involved in creating an MDB. To configure OC4J with the JMS provider details, configure the jms.xml file with the destination object information. Implement the bean class for an MDB, where you define how the message received by the bean should be processed. Configure the deployment descriptors for the JMS Destination: Specify the destination type used for the MDB in the EJB deployment descriptor (ejb-jar.xml). Specify the details of the destination used for the MDB in the OC4J-specific deployment descriptor (orion-ejb-jar.xml). Some of the details about destination are located in the application.xml configuration file. Package the message-driven bean with its deployment descriptor and other supporting files. Create an Enterprise Archive file and deploy the bean to the OC4J instance. These steps are discussed in detail in the following pages.

Oracle 10g: Build J2EE Applications 16-22

Interfaces to Be Implemented for MDBs


MessageDrivenBean interface:

package javax.ejb; public interface MessageDrivenBean extends javax.ejb.EnterpriseBean { public void setMessageDrivenContext (MessageDrivenContext context) throws EJBException; public void ejbRemove() throws EJBException;

MessageListener interface:

package javax.jms; public interface MessageListener { public void onMessage(Message message); }

Copyright 2005, Oracle. All rights reserved.

Interfaces to Be Implemented for MDBs The onMessage() method in the MessageListener interface is invoked by the container each time its subscribers topic receives a message. This makes the MDB a subscriber that can receive messages asynchronously from a queue or topic. Messages are processed inside the onMessage() method.

Oracle 10g: Build J2EE Applications 16-23

Implementing an MDB Class

The MessageLogger MDB example:


package com.evermind.logger; import javax.ejb.*; import javax.jms.*; public class MessageLogger implements MessageDrivenBean, MessageListener { private MessageDrivenContext messageContext; public void ejbCreate() { } public void ejbRemove() { } public void setMessageDrivenContext( MessageDrivenContext context) { this.messageContext = context; }
Copyright 2005, Oracle. All rights reserved.

Implementing an MDB Class In addition to the MDB class implementing the MessageDrivenBean and MessageListener interfaces, the bean class should define the ejbCreate() method. The ejbCreate() and ejbRemove() methods have the same functionality as in the session and entity EJBs. MDBs do not maintain state and, therefore, the ejbCreate() method does not take parameters. The resources that are needed by the MDB, such as a database connection, can be obtained in the the ejbCreate() method and closed and released in the ejbRemove() method when the bean instance is removed. The sample MDB, called MessageLogger, is triggered by the bean container when a message is published at the destination of the MDB (a topic in this example). The bean then prints the received message. The MessageLogger MDB shown in the slide implements the two required interfaces. Note that the javax.ejb package and the javax.jms package are imported for an MDB. No implementation is required for the ejbCreate() and ejbRemove() methods of an MDB. The setMessageDrivenContext() method is invoked by the container at the beginning of the beans life cycle. The context of the bean instance can be stored in this method, which can be reused every time the bean processes a message.
Oracle 10g: Build J2EE Applications 16-24

Receiving Messages in an MDB Class


The onMessage() method processes the received message.
public void onMessage(Message msg){ TextMessage msgText=null; try { msgText = (TextMessage) msg; String txt = (msgText).getText(); System.out.println("Message received=" + txt); } catch (Exception e) { throw new RuntimeException("onMessage error"); } }

Copyright 2005, Oracle. All rights reserved.

Receiving an OC4J JMS Message in an MDB Class The onMessage() method is invoked by the container when a message is received at the destination of the MDB. The onMessage() method in the example receives a message that was created as a JMS ByteMessage. The message is then converted into printable text and printed. In the example in the slide, a message is received from a JMS topic, but it could also be from a JMS queue depending on how the deployment descriptor resources are mapped to the OC4J JMS resources.

Oracle 10g: Build J2EE Applications 16-25

Creating the Deployment Descriptor


MDB-related elements in the ejb-jar.xml file:
<message-driven> <ejb-name>...</ejb-name> <ejb-class>...</ejb-class> <transaction-type>...</transaction-type> <message-selector>...</message-selector> <acknowledge-mode>...</acknowledge-mode> <message-driven-destination> <destination-type>...</destination-type> </message-driven-destination> <ejb-ref> ... </ejb-ref> <security-identity> ... </ security-identity> <resource-ref> ... </resource-ref> </message-driven>
Copyright 2005, Oracle. All rights reserved.

Creating the Deployment Descriptor The general components associated with an MDB are listed in the slide. The <messagedriven> element defines the following information in the deployment descriptor ejbjar.xml: MDB name in the <ejb-name> element MDB class in the <ejb-class> element JNDI reference JMS Destination type (queue or topic) Transaction type of the MDB in the <transaction-type> element These details are listed in the <enterprise-beans> element of the deployment descriptor. Note: There are no component interfaces defined for an MDB. The <message-selector> element indicates the message selection criteria for an MDB. Message selectors are conditional expressions based on the message header fields and properties of a message. Using a message selector, a consumer can filter the messages that it wants to receive from a message destination.

Oracle 10g: Build J2EE Applications 16-26

Creating the Deployment Descriptor (continued) Message selectors are based on SQL92 conditional expressions that can be used in the WHERE clause of a SQL statement. For example, the conditional expression for a message selector can be JMSPriority > 1, which filters only the messages with a priority equal to one. The following example for a message selector filters messages where order_status is pending for customer 123:
<message-selector> <![CDATA[ order_status = 'PENDING' AND customer_id = 123 ]]> </message-selector>

The element <acknowledge-mode> is used by the container to acknowledge the receipt of the message from the destination. Without acknowledgement, the message broker tries to redeliver the message until it receives an acknowledgement. When an MDB involves transactions, the acknowledgement in the middle of a transaction is ignored to maintain the atomic, consistent, isolated, and durable (ACID) properties of a transaction. The receipt is acknowledged only when the transaction is complete. The element can take the values Auto-acknowledge or Dups-ok-acknowledge. When the value is set to Autoacknowledge, the container sends an acknowledgement immediately after receiving the message. When the value is set to Dups-ok-acknowledge, the container can acknowledge the receipt any time after receiving the message. In the latter case, the message broker can send a message more than once to a consumer, creating duplicate messages. The <message-driven-destination> element indicates the type of destination from which the MDB receives a message. The possible values for the <destinationtype> element are javax.jms.Topic and javax.jms.Queue. If the destination is Topic, then the durability of the subscription should be indicated in the <subscriptiondurability> element in the <message-driven-destination> element. If a subscription is specified to be nondurable, then the consumer is not able to receive messages that were delivered when the consumer was disconnected from the server. If a subscription is specified to be Durable, then the JMS provider delivers a message that could not reach a consumer (for example, because the consumer was not connected to the server when the message was delivered), when the consumer reestablishes its connection to the server. Similar to the session and entity beans, the MDB can specify the references to other EJBs, resources, and security identities.

Oracle 10g: Build J2EE Applications 16-27

ejb-jar.xml: Example
... <enterprise-beans> <message-driven> <ejb-name>MessageLogger</ejb-name> <ejb-class>btier.impl.MessageLogger</ejb-class> <acknowledge-mode>Auto-acknowledge </acknowledge-mode> <message-driven-destination> <destination-type> javax.jms.Queue </destination-type> <subscription-durability>Durable </subscription-durability> </message-driven-destination> </message-driven> ...
Copyright 2005, Oracle. All rights reserved.

ejb-jar.xml: Example The slide shows the <message-driven> element of the ejb-jar.xml file for the sample MDB. The MDB specifies its destination type as Topic and a durable subscription for the messages. The following code shows the complete deployment descriptor:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE ejb-jar PUBLIC '//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN' 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'> <ejb-jar><enterprise-beans><message-driven> <ejb-name>MessageLogger</ejb-name> <ejb-class>btier.impl.MessageLogger</ejb-class> <acknowledge-mode>Auto-acknowledge</acknowledge-mode> <message-driven-destination> <destination-type>javax.jms.Queue</destination-type> <subscription-durability>Durable</subscription-durability> </message-driven-destination> </message-driven></enterprise-beans></ejb-jar>

Oracle 10g: Build J2EE Applications 16-28

Mapping in OC4J-Specific Deployment Descriptor


In the orion-ejb-jar.xml file, associate a JMS Destination with the MDB in the <message-drivendeployment> element by using the following attributes: Name: MDB name as defined in the <ejb-name> connection-factory-location: JMS Destination Connection Factory destination-location: JMS Destination subscription-name: Subscription name (required only if the JMS Destination is a topic)

Copyright 2005, Oracle. All rights reserved.

Mapping in OC4J-Specific Deployment Descriptor After you have configured the MDB and the JMS Destination type, you must inform the container which JMS Destination to associate with the MDB. You could have several topics and queues defined in the jms.xml file for OC4J JMS. To identify the destination that is to be associated with the MDB, you map the connection factory and destination names to their JNDI locations through the <message-drivendeployment> element in the orion-ejb-jar.xml file. These details are dependent on the JMS provider. If you use a topic as a destination for your MDB, then you also specify the subscriber name of the topic from which your MDB receives a message. This is required because a topic can have more than one subscriber. For information about defining these JMS Destination types in jms.xml, see the Oracle Application Server Containers for J2EE Services Guide.

Oracle 10g: Build J2EE Applications 16-29

orion-ejb-jar.xml: Example

<enterprise-beans> <message-driven-deployment name="MessageLogger" connection-factory-location= "jms/QueueConnectionFactory"> destination-location= "jms/demoQueue" </message-driven-deployment> ... </enterprise-beans>

Copyright 2005, Oracle. All rights reserved.

orion-ejb-jar.xml: Example The code in the slide is the orion-ejb-jar.xml deployment descriptor for the MessageLogger example. It maps a JMS Queue to the MessageLogger MDB, providing information in the following attributes: The name of the MDB is MessageLogger as defined in the ejb-jar.xml file. The connection-factory-location attribute specifies the name of the OC4J JMS Destination connection factory location. The destination-location attribute sets the OC4J JMS Destination location. After these attributes are specified in the <message-driven-deployment> element, the container associates the MDB with the OC4J JMS Destination, based on how the attribute values are mapped to the JMS resources.

Oracle 10g: Build J2EE Applications 16-30

Creating an MDB with JDeveloper


2

Copyright 2005, Oracle. All rights reserved.

Creating an MDB with JDeveloper The process of creating an MDB with JDeveloper is the same as creating any other EJB. In the EJB module editor, select the Business Tier category, and then select Message-Driven Bean from the Enterprise JavaBeans section. Specify the name of the MDB to be created. Note: No interfaces are created for this bean. The slide also shows the MDB node and the code associated with the bean. Note that only a bean class is created for an MDB, and the bean class contains an onMessage() method.

Oracle 10g: Build J2EE Applications 16-31

Creating an MDB with JDeveloper

ejb-jar.xml
Copyright 2005, Oracle. All rights reserved.

Creating an MDB with JDeveloper (continued) In the EJB module editor, expand the MDB node and click Destination. On the right of the frame, select a destination type for the MDB. The destination type can be either a javax.jms.Queue type or a javax.jms.Topic type. In this example, the destination type is a topic. For a topic, you also have to select whether the subscription is durable or nondurable. After you make these selections, JDeveloper adds the necessary code in the ejb-jar.xml file as shown in the slide.

Oracle 10g: Build J2EE Applications 16-32

Creating an MDB with JDeveloper


Map the destination details in orion-ejb-jar.xml.

orion-ejb-jar.xml
Copyright 2005, Oracle. All rights reserved.

Creating an MDB with JDeveloper (continued) Map the destination details to JNDI locations in the orion-ejb-jar.xml file.

Oracle 10g: Build J2EE Applications 16-33

Testing the MDB


1. Deploy the session and the MDBs. 2. Create a client to invoke the message-sending functionality. 3. Run the client application to send the message to the JMS Destination. 4. Observe the output in the run-time environment.

Copyright 2005, Oracle. All rights reserved.

Testing the MDB Create a deployment profile for the MDB and deploy it to a stand-alone OC4J container or an OC4J instance in Oracle Application Server 10g. After deploying the MDB, you must create a client application that has the functionality to send a message to the required JMS Destination. The client application could be a standalone GUI, command line, Web, or EJB implementation. When you execute a client, you can observe the operation of the message delivery process, depending on the run-time environment of the MDB and depending on whether the developer of the MDB has provided visual confirmation of message processing. The example in the slide shows the output of an MDB that is running in a stand-alone OC4J container started in a command-line window.

Oracle 10g: Build J2EE Applications 16-34

Summary
In this lesson, you should have learned how to: Describe the different types of MOM:
Point-to-point Publish-and-subcribe (pub/sub)

Create an MDB Compare a stateless session EJB and an MDB Describe JMS Configure a JMS resource provider in the OC4J jms.xml file

Copyright 2005, Oracle. All rights reserved.

Summary In this lesson, you should have learned the concepts of JMS. You should have also learned how to create and access MDBs.

Oracle 10g: Build J2EE Applications 16-35

Practice 16-1: Overview


This practice covers the following topics: Creating a simple MDB to accept a message from an OC4J JMS queue, and writing the message to a log table by using an entity bean Configuring the message-bean deployment descriptor to use an OC4J JMS resource Writing and configuring a JavaServer Pages (JSP) application to send a message from an HTML form to the OC4J JMS queue

Copyright 2005, Oracle. All rights reserved.

Practice 16-1: Overview In this practice, you create an MDB to read a message from an OC4J JMS queue. The MDB uses a supplied entity bean to write the message to a record in a log table. You are required to modify the message-bean deployment descriptor to associate the MDB with the OC4J JMS connection factory. You then modify an existing JSP that is invoked by an HTML form. The JSP accepts an employee id, a job id, and a text message that is used to create a message that is sent to the OC4J JMS queue.

Oracle 10g: Build J2EE Applications 16-36

Practice 16-1 In this practice, you create a simple message-driven bean to receive messages from an OC4J JMS queue, and modify a JSP to send messages to the EJB. Open the practice16.jws workspace in the practice16 directory. The workspace contains the two projects webtier and businesstier, along with their respective solution projects webtiersoln and businesstiersoln. 1. Create the log message table used by the Logmessages entity to store messages that are sent to the MDB that you create. Use SQL*Plus to execute logmessages.sql from the directory: <JDEV_HOME>\jdev\mywork\practice16 2. Now modify some OC4J configuration files to use OC4J JMS. a. Create a new queue and data source reference. Open a browser and navigate to http://localhost:1810. Enter the username ias_admin and the password welcome1. Click on the home instance page. b. Click the Administration tab and the Advanced Properties link. Click the jms.xml link to add a queue and queue connection factory. c. Create a new queue named "jms/Queue/Queue1" with a location of "jms/Queue/Queue1". Provide the queue connection factory location as "jms/Queue/QCF". It is important that you type these entries and do not copy and paste from another location. Click Apply and then click OK. When prompted to restart OC4J, click Yes. d. Next create a new data source. From the home instance page, click the Data Sources link. Click Create and enter these details: Name: LogDS Description: log Data Source Class: com.evermind.sql.DriverManagerDataSource JDBC URL: The URL provided to you by your instructor JDBC Driver: oracle.jdbc.driver.OracleDriver In Datasource Username: Username: oraxx (as provided to you by your instructor) Use a cleartext password of oracle In JNDI Locations: Location: jdbc/LogCoreDS Transactional location: jdbc/xa/LogXADS EJB location: jdbc/LogDS Leave all other fields blank or set to the default. e. Click Create and restart the server when prompted. 3. Create a simple MDB to accept a message from an OC4J JMS queue, and store the message text as a record in a log table by using the Logmessages entity bean provided. a. In the businesstier project, create a new Enterprise JavaBean of the MDB type. Define the bean name as MessageLogger.

Oracle 10g: Build J2EE Applications 16-37

Practice 16-1 (continued) b. In the onMessage() method of the bean, process only the TextMessage objects from the queue, and ignore other message type objects. Get the message string by using the getText() method of the TextMessage object, and use the getLongProperty() method of the TextMessage object to get the value of a property named msgid in a Long object variable. Note: Be sure to import javax.jms.TextMessage. 4. Associate the MDB with the OC4J JMS resource provider, the JMS queue from which it receives messages, and the entity bean used to save the message to the log table. a. Open the EJB Module Editor, expand the MessageLogger bean node, select the EJB Local References section, and click the Add button. Select Logmessages from the "Auto-create Reference to the EJB" drop-down menu. Note: This action adds a getLogmessagesLocalHome() method in the MessageLoggerBean class to access the entity beans local home interface, and a <ejb-local-ref> element to the ejb-jar.xml file. b. Select the Destination node and check "Specify Message Driven Destination". Set the Destination Type to javax.jms.Queue and the Subscription Durability to Durable. Click OK to close the window. c. Copy the contents of the addLogMessage.txt file in the <JDEV_HOME>\jdev\mywork\practice16 directory into the MessageLoggerBean class. This code provides the method to save the text message in the database table by creating an instance of the Logmessages entity bean. Note: Import the following packages: java.sql.Timestamp, java.util.Date, and javax.ejb.CreateException.\ d. In the MessageLoggerBean onMessage() method, call the addLogMessages() method as the last line of the try block. Supply the long msgid property value obtained from the message and the text message string as arguments. e. Define the OC4J JMS resources used by the MDB, and map the logical JMS resource to the OC4J JMS resources. Right-click orion-ejb-jar.xml and select Properties. In the OC4J EJB Deployment Descriptor window, select the MessageLogger section under Enterprise JavaBeans. In the Connection Factory Location field, enter jms/Queue/QCF. In the Destination Location, enter jms/Queue/Queue1. These are OC4J JMS queue connection factories and queue resources you defined in step 2b. 5. Compile the files in the businesstier project and correct any syntax errors. Rightclick ejb-jar.xml and select Create EJB JAR Deployment Profile from the menu, and enter MessageLoggerEJB.deploy as the filename. Click OK, then click OK again to close the window.

Oracle 10g: Build J2EE Applications 16-38

Practice 16-1 (continued) 6. Expand the webtier project and open the SendMessage.jsp in the code editor. You now add the code to send a message to the OC4J JMS queue. a. SendMessage.jsp is invoked from an HTML form action that is generated by the LoginServlet. In SendMessage.jsp, you should construct the string message to contain the request parameter values (obtained from the form fields) for empid, jobid, and msg, concatenated into a space-separated list. b. Write code to create a QueueConnectionFactory object by using the JNDI name of jms/Queue/QCF, and a Queue object using the JNDI name of jms/Queue/Queue1. Create a QueueConnection, QueueSession and TextMessage object, setting the text of the TextMessage object to the string formatted in the previous step. Prior to sending the message, use the message object setLongProperty() method to set a property named msgid to the value of msgId variable, which holds a unique message ID obtained from an Oracle sequence. Finally, write the code to send the TextMessage to the queue. c. Change the username and password in the doPost() method of LoginServlet.java and in the database tags in SendMessage.jsp to utilize your username and password. 7. Create the logical JMS resources used in the JSP in the J2EE deployment descriptor. a. Right-click web.xml and select Properties. Select the Resource References section to create logical resources by clicking the Add button. Create a reference with a name field jms/Queue/QCF and a Resource Type field javax.jms.QueueConnectionFactory. b. Click the Add button again to create a second reference with a jms/Queue/Queue1 name field and a javax.jms.Queue Resource Type field. 8. Compile the files in the webtier project and correct any syntax errors. Right-click web.xml and select Create WAR Deployment Profile, and then enter the file name LogMessageApp.deploy. Click OK. In the Profile Dependencies section, select the box next to the MessageLoggerEJB.deploy entry. Then click the OK button to close the window. 9. Right-click LogMessageApp.deploy and deploy the application (including the dependent MessageLoggerEJB) to the OracleAS10g connection. Note that it could take several minutes to deploy the application.

Oracle 10g: Build J2EE Applications 16-39

Practice 16-1 (continued) 10. Run the Web application to test the logic by entering one of the following URLs in our Web browser: http://localhost/logmessage/ or http://localhost/logmessage/loginservlet. Usernames and passwords are listed below. Hint: Use the Show Messages hypertext link in the application window to view messages written to the LOGMESSAGES table by the MDB. 100 102 203 King De Haan Mavris

Oracle 10g: Build J2EE Applications 16-40

Integrating J2EE Components

Copyright 2005, Oracle. All rights reserved.

Objectives
After completing this lesson, you should be able to do the following: Create JavaServer Pages (JSP) clients for EJBs Use Enterprise JavaBeans (EJB) tags in JSPs Modify the configuration files in OracleAS 10g Containers for J2EE (OC4J)

Copyright 2005, Oracle. All rights reserved.

Oracle 10g: Build J2EE Applications 17-2

Overview
Web tier EJB tier

JSP

HttpServlet Request

Controller servlet To EIS Employees JSP Employees EJB

HttpServlet Response

Copyright 2005, Oracle. All rights reserved.

Overview The slide shows a sample application that adheres to the Model-View-Controller (MVC) framework. In this application, a JSP accesses EJBs through a Controller servlet, which forwards the users request to the appropriate JSP. The Employees JSP acts as a client to the EJB. This lesson teaches you how to access EJBs from JSP, and how to deploy an application such as the one shown in the slide.

Oracle 10g: Build J2EE Applications 17-3

Creating Remote Clients for EJBs


To create a remote JSP client for an Enterprise JavaBean, perform the following steps: 1. Import the EJB home interface. 2. Override the jspInit() method.
Use the lookup() method to create a reference to the EJB. Create the EJB remote object.

3. Retrieve the necessary parameters from the request object and pass the parameters to the EJB method. 4. Define a reference to the EJB in the web.xml file.

Copyright 2005, Oracle. All rights reserved.

Creating Remote Clients for EJBs To create a remote client by using a JSP, first import the EJB Home interface. Use the jspInit() method to retrieve a reference to the EJB by using the lookup() method of the InitialContext object. Request object parameters can then be retrieved as usual in a JSP (by using the request.getParameter() method), and passed to the EJB methods. Lastly, a reference to the EJB is created in the web.xml file so that the JSP client can find the required interfaces.

Oracle 10g: Build J2EE Applications 17-4

Importing the EJB Home Interface

Use the page directive to import the naming package and the home interface for the EJB:
<%@ page import="mypackage.Employees, mypackage.EmployeesHome, javax.ejb.*, javax.naming.*, javax.rmi.PortableRemoteObject, java.rmi.RemoteException" %>

Copyright 2005, Oracle. All rights reserved.

Importing the EJB Home Interface By using a page directive in the JSP, import the home and remote interfaces for the EJB, as well as the PortableRemoteObject, RemoteException, and the javax.naming package for the InitialContext lookup. Import these packages as usual for a Java file in a servlet:
import import import import import public { } mypackage.Employees.*; java.io.*; javax.servlet.*; javax.servlet.http.*; javax.naming.*; class EJBClientServlet extends HttpServlet

Oracle 10g: Build J2EE Applications 17-5

Create a Reference to the EJB

To create an EJB reference, use the lookup method. Override the jspInit() method as follows:
<%! Employees employees = null; public void jspInit() { try { InitialContext ic = new InitialContext(); EmployeesHome employeesHome = (EmployeesHome) PortableRemoteObject.narrow (ic.lookup("java:comp/env/Employees"), EmployeesHome.class); employees = employeesHome.create(); } catch (RemoteException ex) { ex.printStackTrace(); } } %>
Copyright 2005, Oracle. All rights reserved.

Create a Reference to the EJB Because locating the home interface and creating the EJB are performed only once, they should be performed in the jspInit() method within a declaration. In a servlet, this can be performed in the init() method.

Oracle 10g: Build J2EE Applications 17-6

Passing Arguments to the EJB Method


Calling an EJB method from a JSP expression evaluates the return value of the EJB method and displays it, as follows:
<html><body><h1>Insert an Employee Number:</h1> <form method="get"> <p><input type="text" name="empno"> <p><input type="Submit" value="Submit"> </form> <% String empno = request.getParameter("empno"); if (empno != null && empno.length() >0) { int i = Integer.parseInt(empno);%> <%= employees.getDetails(i) %> <% } %> </body></html>

Copyright 2005, Oracle. All rights reserved.

Passing Arguments to the EJB Method Use expressions to evaluate the return value of the EJB business method at run time. In a servlet, the code seen above would be performed by wrapping the return value of getDetails() in an out.println() method.

Oracle 10g: Build J2EE Applications 17-7

Creating an EJB Reference


To obtain an EJB reference for the Web tier components, create an <ejb-ref> element for the EJB in the web.xml file:

Copyright 2005, Oracle. All rights reserved.

Creating an EJB Reference To create an EJB reference in the web.xml file, right-click the file in JDeveloper and select Properties. After clicking the Add button from the EJB references category, you can give the details of the reference as shown in the screenshot below:

Oracle 10g: Build J2EE Applications 17-8

Creating Local Clients for EJBs


Creating JSP clients for local EJBs is similar to creating remote clients, with the following exceptions: The EJB object does not have to be cast to a PortableRemoteObject. Because the create() method does not throw a RemoteException exception, this does not have to be caught in the client. Instead of <ejb-ref>, an <ejb-local-ref> element is created in the client web.xml file.

Copyright 2005, Oracle. All rights reserved.

Creating Local Clients for EJBs There are three differences between using remote EJBs and local EJBs. An example of a web.xml file that references a local EJB is as follows:
<ejb-local-ref> <description>Reference to Local Bean</description> <ejb-ref-name>Employees</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <local-home>package1.EmployeesLocalHome</local-home> <local>package1.EmployeesLocal</local> </ejb-local-ref>

Oracle 10g: Build J2EE Applications 17-9

ejb-local-ref Element

Right-click web.xml to create an EJB local reference.

Copyright 2005, Oracle. All rights reserved.

ejb-local-ref Element Instead of creating an ejb-ref element for remote EJBs, create an ejb-local-ref element in the web.xml file by right-clicking it. Select EJB Local References, and then add a reference as shown in the slide.

Oracle 10g: Build J2EE Applications 17-10

EJB Tags
Oracle Application Server 10g provides a tag library that contains custom tags for referencing EJBs in JSPs:
EJB Tag useHome useBean createBean iterate Purpose Looks up the home interface for the EJB and creates an instance of it Instantiates the EJB Nests an EJB createBean tag within the useBean tag to create the EJB instance Iterates through a collection of EJB instances

Copyright 2005, Oracle. All rights reserved.

EJB Tags You can retrieve references to EJBs by using the EJB tags that are provided in the OJSP (OC4J JSP) library. Use the useHome bean to look up a home interface for the EJB. The useBean tag instantiates the EJB. You can specify either the value attribute or a nested createBean tag to create the EJB instance. The iterate tag iterates through EJB instances. This is commonly used for entity beans, because standard finder methods for entity beans return collections.

Oracle 10g: Build J2EE Applications 17-11

useHome Tag
The useHome tag has no body. The attributes are: id (required) type (required) location (required)
<EJB:useHome id="empHome" type="mypackage.EmployeesHome" location="java:comp/env/ejb/Employees" local="false" />

Copyright 2005, Oracle. All rights reserved.

useHome Tag Define three attributes in the useHome tag. First, specify the id, which is a name for the home interface instance. Next, specify the name of the home interface in the type attribute. Lastly, provide the Java Naming and Directory Interface (JNDI) location that is used to look up the home interface of the EJB. This should correspond to your <ejb-ref> element entry in the web.xml file. The local attribute should be false when the type class name refers to the remote home interface of the bean, and true when using the Local Home interface.

Oracle 10g: Build J2EE Applications 17-12

useBean Tag
The attributes of the useBean tag include: id (required) type (required) value scope
<EJB:useBean id="bean" type="mypackage.EmployeesBean" scope="session" />

Copyright 2005, Oracle. All rights reserved.

useBean Tag First, specify an instance name for the EJB in the id attribute. Next, specify the class name of the EJB in the type attribute. You can use the value attribute or a nested createBean tag to create the instance, as shown below. Lastly, specify the scope of the instance. This can be page, session, request, or application, similar to specifying the scope in JSPs for JavaBeans.
<EJB:useBean id="bean" type="mypackage.EmployeesBean" scope="session"> <EJB:createBean instance="<%=empHome.create()%>" /> </EJB:useBean>

Oracle 10g: Build J2EE Applications 17-13

createBean Tag
The createBean tag contains only one required attribute named instance.
<EJB:useBean id="bean" type="mypackage.EmployeesBean" scope="session"> <EJB:createBean instance="<%=EmployeesHome.create()%>" /> </EJB:useBean>

Copyright 2005, Oracle. All rights reserved.

createBean Tag instance is a required attribute of createBean, which returns the EJBObject instance. In the example given in the slide, the create() method of the EJB home interface creates the instance.

Oracle 10g: Build J2EE Applications 17-14

iterate Tag
The following are the attributes of the iterate tag: id (required) type (required) collection (required) max
<EJB:iterate id="empdetails" type="mypackage.Employees" collection="<%=bean.getDetails(pk)%>" max="100"> <jsp:getProperty name="empdetails" property="id" /> </EJB:iterate>

Copyright 2005, Oracle. All rights reserved.

Oracle 10g: Build J2EE Applications 17-15

Using the EJB Tags


To use the EJB tags, perform the following steps: 1. Add the Oracle9iAS library to your project in JDeveloper.
a. Double-click the project and select libraries. b. Make sure that Oracle9iAS is included in your project.

2. Use the OJSP EJB Library provided in the component palette to add the necessary tags to your JSP file. (This adds the bean as well as the taglib directive to the JSP.)

Copyright 2005, Oracle. All rights reserved.

Using the EJB Tags When you include the Oracle9iAS library in your project in JDeveloper, you can easily incorporate the EJB tags in your JSP. The component palette contains a list of different tags to be used. Select the OJSP EJB category in the component palette. You can then add any of the tags discussed previously by placing your cursor in the JSP and selecting the tag. Adding a tag in this way also adds the tag library directive to your JSP, as shown below:
<%@ taglib uri="http://xmlns.oracle.com/j2ee/jsp/tld/ojsp/ ejbtaglib.tld" prefix="EJB" %>

Note that although you can specify any prefix value, EJB is conventionally used.

Oracle 10g: Build J2EE Applications 17-16

Deploying an Application: Web Tier


To deploy the Web tier components of a Java 2, Enterprise Edition (J2EE) application, perform the following steps: 1. Make sure that the ejb-ref or ejb-local-ref elements exist in the web.xml file. 2. Create a WAR deployment profile (.deploy) in JDeveloper. 3. Right-click the .deploy file and select either of the following:
Deploy to WAR file Deploy to OracleAS10g (where OracleAS10g is the name of your application server connection)
Copyright 2005, Oracle. All rights reserved.

Deploying an Application: Web Tier After you have added the EJB client access to a JSP application and have ensured that the proper ejb-ref or ejb-local-ref elements exist in the web.xml file, you can deploy the application. Create a WAR deployment profile in JDeveloper, and right-click the file to deploy it. You can either deploy the application directly to Oracle Application Server 10g, or create a Web Archive (WAR) file.

Oracle 10g: Build J2EE Applications 17-17

Deploying an Application: EJB Tier


1. Make sure that the ejb-jar.xml file contains unique mappings for each EJB in the application. 2. Create a JAR deployment profile (.deploy) in JDeveloper. 3. Right-click the .deploy file and select either of the following:
Deploy to JAR file Deploy to OracleAS10g

Copyright 2005, Oracle. All rights reserved.

Deploying an Application: EJB Tier In the same way as you deployed a WAR file, create a deployment profile for the EJB components. When this deployment profile is deployed to a Java Archive (JAR) file, it can then be included in an Enterprise Archive (EAR) file with the WAR file for the application. This is shown in the next slide.

Oracle 10g: Build J2EE Applications 17-18

Deploying an Application: EAR File


1. Create an EAR file in JDeveloper. 2. Specify the EJB JAR and WAR files that are to be included in this EAR file. 3. Right-click the .deploy file and select either of the following:
Deploy to EAR file Deploy to OracleAS10g

Copyright 2005, Oracle. All rights reserved.

Deploying an Application: EAR File After you have deployed an EJB JAR file and a WAR file, create an EAR file for the application. Specify the JAR and WAR files that are to be included in this deployment profile, as shown below. Right-click the .deploy file for the EAR deployment profile to deploy it either directly to Oracle Application Server 10g or to an EAR file for deployment via command line or Oracle Enterprise Manager Application Server Control Console.

Oracle 10g: Build J2EE Applications 17-19

Deploying from Oracle Enterprise Manager


From the Enterprise Manager home page, click Home, then Applications, and then select Deploy EAR file:

Copyright 2005, Oracle. All rights reserved.

Deploying from Oracle Enterprise Manager You see the Deploy Application page in which you specify the location of the EAR file that you generated from the .deploy file and the application details.

Oracle 10g: Build J2EE Applications 17-20

Summary
In this lesson, you should have learned how to: Create JSP clients for EJBs Modify deployment descriptors for looking up an EJB client Deploy a J2EE application to Oracle Application Server 10g

Copyright 2005, Oracle. All rights reserved.

Oracle 10g: Build J2EE Applications 17-21

Practice 17-1 and 17-2: Overview


These practices cover the following topics: Creating JSP clients that access EJBs Deploying a Web application to Oracle Application Server 10g

Copyright 2005, Oracle. All rights reserved.

Oracle 10g: Build J2EE Applications 17-22

Practice 17-1 The purpose of this practice is to create JSP clients for the EJBs that you have written in previous practices. Within practice17ske.jws, there are two projects, businesstier.jpr and webtier.jpr (the solution files are contained in practice17soln.jws). businesstier.jpr contains the Employee session EJB that you developed in practice 12, as well as the UpdateEmployee entity EJB that you created in practice 14. The webtier project contains the LoginServlet that you created in practice 5. In this practice, you put together all the knowledge to create a complete J2EE application. 1. Modify LoginServlet to test a user who logs in. In this practice, because company employees are using the application, change the LoginServlet to verify the login for an employee, rather than for a customer. a. In the init() method, change the data source lookup to jdbc/hrDS. b. In the doGet() method, change the heading for the human resources application and change the forms fields to accept the employee ID and employee name. 2. Modify the verifyCustomer() and getOrders() methods to verifyEmployee() and getRoles(). Only employees who have a valid login will be accepted, and only employees who have an administrator role will be allowed to insert new employees (who will be added later). a. Change verifyCustomer() to verifyEmployee(), and return a jobid from this method. Pass in a connection, employee_id, and employee_name as arguments to this method. The jobid will be used to check for the administrator roles in the getRoles() method. b. Change the statement to select the employee_id, last_name, and job_id from the EMPLOYEES table where the last_name is the employee_name that is passed to this method, and where employee_id is the employee ID that is passed to this method. c. In the while loop, set the value of jobid to the job_id from the query. Remove the code for checking the custid value. d. Change getOrders() to getRoles(). This method will return a Boolean value, indicating whether the employee is an administrator. It will accept the connection and the jobid from the verifyEmployee() method. e. Create a variable for this method, initialized to null, to store the value of the string that is returned from the query. f. Change the prepareStatement() method (in the init() method) to select job_id from the JOBS table where job_id is equal to the argument passed to the method. In the getRoles() method, use the setString() method to pass in the argument. g. In the while loop, set the value of the variable created in step e. to the jobid that is returned from the query. h. If the value equals HR_REP, AD_PRES, or AD_VP, return true. Otherwise, return false. 3. Create a new method to forward the request to a JSP in the application. a. Name the method gotoPage(). It should accept an address (as string) and the HttpServletRequest and HttpServletResponse objects, and then throw the ServletException and IOException exceptions.
Oracle 10g: Build J2EE Applications 17-23

Practice 17-1 (continued) b. Create a variable of type RequestDispatcher and use getServletContext().getRequestDispatcher() to assign the value of the address passed to the method. c. Forward the request and response by using the forward method of the RequestDispatcher variable. 4. Modify the doPost() method to include the new functionality. a. Modify the id and name variables to retrieve the value of the parameters from the doGet() methods form. b. Create a string variable initialized to false to store a flag if the employee is an administrator. c. In the try/catch block, store the return value of verifyEmployee(conn, id, name) in a string variable. d. If this variable is not null, then verify that the getRoles() method returns true. e. If getRoles() returns true, then set the variable that you created in step b to true and use the setAttribute() method of the request object to create an attribute named adminflag with a value of the variable. f. Whether or not getRoles() returns true, the user will be able to see a list of employees. Set a request attribute to store the value of the id variable to an attribute named empid. g. Call the gotoPage() method by passing in ViewEmployees.jsp as the address, and the request and response objects. h. If the variable created in step c is null, the employees login is invalid. i. Eliminate the code in the method for viewing the orders, because this functionality is no longer required. j. Compile LoginServlet.java. 5. Create an EJB reference for the Employee EJB that you created in practice 12. a. Right-click web.xml in the WEB-INF folder of the webtier project and select Properties. b. Select EJB references and add a new reference. c. Supply the name as Employee, the home interface as businesstier.EmployeeHome, the remote interface as businesstier.Employee, and make sure that the type is session. Click OK. d. Open web.xml in the editor to view this reference. You can now access the EJB by using the java:comp/env/Employee reference. 6. Create a client for the Employee EJB. a. Navigate to EmployeeBean.java in the businesstier project. A method called getEmployeesInDept() has been added to this EJB to retrieve a vector of the employees in a given department. Note that the EmployeeDetails class has been modified to retrieve the values of the id, fname, lname, email, hiredate, and jobid arguments. b. Create a new JSP in the webtier project named ViewEmployees. c. Rename the title for the JSP.
Oracle 10g: Build J2EE Applications 17-24

Practice 17-1 (continued) d. Import the following: businesstier.Employee, businesstier.EmployeeHome, javax.naming.*, javax.ejb.CreateException, javax.rmi.PortableRemoteObject, java.rmi.RemoteException, java.util.*, businesstier.EmployeeDetails e. In a declaration, create an instance variable to hold an object of Employee type. f. Still in the declaration, override the jspInit() method. Use a try/catch block to look up the Employee EJB by using the reference that you created in step 5.d. by catching the CreateException, NamingException, and RemoteException exceptions. Hint: Use page 6 of this lesson as an example. g. Outside the declaration, create a variable to retrieve the value of the employee ID that is stored in the request object. h. Retrieve the value of the employee ID that you set in step 4.f. by using request.getAttribute(). Assign it to an int variable. You must cast this String value to an Integer. i. Initialize an object of EmployeeDetails type to null. j. Create a 3 row, 4 column HTML table and insert headers in the first row to display the employee id, first name, last name, and e-mail. k. In the source code editor, add a scriptlet to create an Enumeration of the getEmployeesInDept() methods elements. l. While there are more elements in the enumeration, advance through the EmployeeDetails object that you created in step d by using the nextElement() method. Cast the return to the object you created in step h. m. Navigate to the second row of the HTML table and between <td> elements, retrieve the values of the id, first name, last name, and e-mail by using the methods from the EmployeeDetails object. n. Close the while loop. o. Verify whether the employee is an administrator. Use request.getAttribute() to retrieve the value of adminflag. If this attribute is not equal to null, check if the value is true. If the value is true, then create an href link in the third table row to AddEmployees.jsp. You create AddEmployees.jsp in the next step. p. Compile the businesstier project and ViewEmployees.jsp. 7. Create AddEmployees.jsp. This JSP allows an administrator to insert a new employee by using the entity bean that you created in practice 14. a. Create AddEmployees.jsp in the webtier project. b. Rename the title for the JSP. c. This JSP provides a form for completing employee details and submits to itself. Verify that the insert parameter is null. If it is null, then create a form as follows: i. The action for the form returns the request to this JSP.
Oracle 10g: Build J2EE Applications 17-25

Practice 17-1 (continued) ii. Create an HTML table containing seven rows and two columns. iii. In the first column, create a text label to describe the data entered, such as Enter an Employee Id:. The second column must be a text field, with the name attribute set to empid, fname, lname, email, hdate, and jobid. These text fields do not contain any values. iv. Create the Insert button in the last row. v. After the last row, create a hidden value to provide the insert parameter as true. Hint: Use the HTML tags in the component palette for easy table and form object creation. d. If the insert parameter is not null, and if it is true, then the user has entered data into the form. Thus, you need to insert this data using the UpdateEmployees EJB. This time, use the OJSP EJB tag library to access the bean. Check for the insert parameter condition and retrieve the values of each of the text items from the form. You will need to use Integer.parseInt() to parse the empid value. e. Create a reference to the EJB in the web.xml file as in step 5, this time providing businesstier.UpdateEmployeeHome as the home interface, and businesstier.UpdateEmployee as the remote interface. Give the reference a name and specify that this bean is an Entity bean. f. In AddEmployees.jsp, place your cursor beneath the scriptlet that contains the retrieval of the form values, and select the OJSP EJB category from the component palette. g. Use the UseHome tag to create a reference to the UpdateEmployees EJB. Supply an ID of entityhome, a type of businesstier.UpdateEmployeeHome, and the location as java:comp/env/<yourrefname>, where <yourrefname> is the reference name you provided in step e. h. In a scriptlet, call the create() method of UpdateEmployee by using the entityhome reference. Pass in the values that are retrieved from the form submission. i. Supply some text to notify the user that the employee has been added, and close out the condition. 8. Compile the businesstier and webtier projects and run LoginServlet to test. Employees who are administrators are listed below. Note that there is a database constraint that employee IDs and e-mail addresses must be unique. Employee ID 100 101 102 203 Last Name King Kochhar De Haan Mavris
Oracle 10g: Build J2EE Applications 17-26

Practice 17-2 In this practice, you deploy the application that you created in Oracle Application Server 10g. 1. Create an EJB JAR file for the businesstier project. a. Right-click businesstier and select New. b. Expand the General category and click Deployment Profiles. Select EJB JAR File. c. Accept the default deployment profile name. d. Specify the enterprise application name as hrejb. e. Right-click the deployment profile and select Deploy to JAR file. 2. Create a WAR file for the webtier project. a. Right-click webtier and select New. b. From the Deployment Profiles category, select WAR File. c. Accept the default deployment profile name and click OK. d. Specify the context root as /hrapp and click OK. e. Right-click the deployment profile and select Deploy to WAR file. 3. Create an EAR file for the application. a. Right-click webtier and select New. b. From the Deployment Profiles category, select EAR File. c. Accept the default deployment profile name and click OK. d. Name the application hr. e. In the Application Assembly category, include the deployment profiles that you created in steps 1 and 2 and click OK. f. Right-click the deployment profile and select Deploy to EAR file. 4. Deploy the application by using Oracle Enterprise Manager Application Server Control Console: a. Navigate to http://localhost:1810 and supply the username as ias_admin and the password as welcome1. b. Select home to open the OC4J home instance page. c. Click the Applications tab and click the Deploy EAR File button. d. Browse for the application1.ear file. By default, this will be in <JDEV_HOME>\jdev\mywork\practice17ske\webtier\deploy. Supply a name of practice17 for the application name and click Continue. e. Verify whether the URL binding for this application is /hrapp, and click Next. This means that you can access the application by using this shortened name. f. Enter jdbc/hrCoreDS for the JNDI location name and click Next. In practice 2, you have already mapped this data source in OC4J. g. Click Next at the following page because there is no user security defined for this application. h. Click Deploy to deploy the application. 5. Test the application by accessing the following URL: http://localhost/hrapp/loginservlet

Oracle 10g: Build J2EE Applications 17-27

Distributing Modular Applications: Introduction to Web Services

Copyright 2005, Oracle. All rights reserved.

Objectives
After completing this lesson, you should be able to do the following: Describe the Web services technology Identify the standards used by Web services Identify the benefits of Web services Distinguish between remote procedure call (RPC)style and document-style Web services Discuss the role of Simple Object Access Protocol (SOAP), Web Services Description Language (WSDL), and Universal Description, Discovery, and Integration (UDDI) in Web services

Copyright 2005, Oracle. All rights reserved.

Objectives This lesson provides an overview of Web services. This lesson also discusses some of the de facto industry standards such as Simple Object Access Protocol (SOAP), Web Services Description Language (WSDL), and Universal Description, Discovery, and Integration (UDDI). In addition, you learn about the benefits of Web services.

Oracle 10g: Build J2EE Applications 18-2

What Is a Web Service?

HTML HTTP client XML

Web presentation Business logic Web service Databases

External applications

Application Server

Copyright 2005, Oracle. All rights reserved.

What Is a Web Service? A Web service is a software component identified by a Uniform Resource Identifier (URI), whose interfaces and binding can be described by standard Extensible Markup Language (XML) vocabularies. Web service supports direct interactions with other software applications or components and is network accessible. With Web service, you can make your applications programmatically accessible to other applications over the Internet. Browser-based applications provide a Hypertext Markup Language (HTML) front end to a back-end application. The front-end application usually contains an HTML form in which the user enters the data and invokes the back-end application. These applications are valuable because they expose strategically important assets to the outside world. However, a disadvantage of this approach is that data must be entered into a browser screen to access the information. If multiple windows are open, then the user might provide incorrect data or enter the retrieved information into a different Web site, which might cause unwanted delays and errors. It is more efficient for information to be transferred automatically between applications. Web service enables programmatic access of information across the Internet. Unlike Web applications with an HTML form, a Web service can be accessed without a browser. When you consider the type of information or functionality that you might want to expose as a Web service, consider the functions that you currently provide via your Web sites and portals.
Oracle 10g: Build J2EE Applications 18-3

Web Service
A Web service is: A software component whose technology is based on a set of standards for building interoperable distributed applications A set of self-describing business functions Service oriented Component based

Copyright 2005, Oracle. All rights reserved.

Web Service Need for Web Services Several businesses today have become e-businesses. The greatest challenge for the successful transformation is application-to-application communication. An enterprise solution usually has multiple applications, each running on different hardware and sometimes implemented in different languages. There is often a need to communicate and exchange data between applications. To achieve this, developers spend time writing the plumbing application. Web service is a technology based on a set of standards that provides a solution for application-to-application communication and enterprisewide application integration. Standards for Interoperable Distributed Applications Enterprise solutions are developed with a variety of languages such as C++, Java, Visual Basic (VB), and so on. A main requirement of such applications is the need to integrate and exchange data with other applications. By using Web services, clients and servers can communicate over standard Internet protocols regardless of the platform or the programming language. Developers can write their business functionality in any language and on any preferred platform. The applications that are developed must adhere to the standards so that they can be exposed and accessed as Web services.
Oracle 10g: Build J2EE Applications 18-4

Web Service (continued) Self-Describing Web services are discrete business processes. Web services describe their functionality, and the location (the application server to which the service is deployed) from where they can be accessed, so that applications can use them. Service Oriented Web services are developed to offer some service over the Internet. For example: A currency converter can be a Web service. Clients who need the currency conversion in their applications can use the available service rather than coding the functionality themselves. Component Based Web services are an addition to the list of distributed computing models such as Common Object Request Broker Architecture (CORBA), Component Object Model (COM), and Distributed Component Object Model (DCOM). Web services are platform independent and language independent. But unlike these technologies, Web services are not accessed via object-model-specific protocols such as DCOM and Internet Inter-ORB protocol (IIOP). Instead, Web services use the lightweight SOAP protocol over Internet protocols such as HTTP, Simple Mail Transfer Protocol (SMTP), and so on. Web services are loosely coupled and allow document-centric messaging and RPCs.

Oracle 10g: Build J2EE Applications 18-5

Service-Oriented Architecture

Service registry Publish Find

Service provider

Invoke

Service requestor

Copyright 2005, Oracle. All rights reserved.

Service-Oriented Architecture During development of Web services, a new pattern called Service Oriented Architecture (SOA) evolved. SOA has a service provider, a service requestor, and a service registry. Service Provider Web services perform a specific task or a set of tasks. For example, a Web service can be used to obtain the weather report of a given place. A service provider is responsible for developing a Web service, creating the service description, and publishing that description to one or more registries. Service Requestor A consumer of a Web service is considered a service requestor. A service requestor finds the service description in one or more registries to invoke a service. Service Registry A service registry contains descriptions of the services that are published by service providers. Service requestors use this registry to find a service.

Oracle 10g: Build J2EE Applications 18-6

Web Services Constituents


Internet for communication XML as universal data format SOAP for XML messaging WSDL for describing the service UDDI for publishing the Web services

Copyright 2005, Oracle. All rights reserved.

Web Services Constituents The diagram represents the Internet and various standards that are used to send messages from the service requestor to the service provider. Communication The base of the stack is the Internet, because Web services use standard Internet protocols, such as HTTP, FTP, and so on, for communication. Universal Data Format Web services use XML for describing the functionality offered and for exchanging data between the service requestor and service provider. SOAP Web services use the SOAP protocol for XML messaging. The SOAP protocol is used to wrap an XML message in an envelope. It provides a set of conventions for data exchange in RPCs. It is mainly used to invoke a Web service.

Oracle 10g: Build J2EE Applications 18-7

Web Services Constituents (continued) WSDL WSDL documents are self-descriptive. WSDL is a standard to describe the invocation syntax of a Web service. WSDL conforms to the XML syntax. By looking at the WSDL document, you know how to invoke a service. UDDI UDDI is used for publishing and querying the Web services that are described in WSDL.

Oracle 10g: Build J2EE Applications 18-8

Benefits of Web Services


Distributed component model with interoperability XML format for representing data. The request and response messages are in the XML format. Programming language independent Easily accessible with standard protocols such as HTTP, HTTPS, SMTP, and FTP Communication through firewalls Existing components can be exposed as Web services to save development time. Different communication styles:
RPC style (synchronous) Message style (asynchronous)
Copyright 2005, Oracle. All rights reserved.

Benefits of Web Services Distributed Component Model Web services are an addition to distributed applications. Unlike other distributed component models, Web services are language independent and platform independent. Web services developed with Oracle Application Server 10g are based on Java 2, Enterprise Edition (J2EE) architecture and can interoperate with those that are developed for the .NET architecture of Microsoft. XML Format for Representing Data Data encoding is a key aspect in distributed computing approaches. Representing simple data types is easy. However, mapping existing complex data types in an application to the underlying data encoding mechanisms is a difficult task. Web services use XML for representing information. The text-based form of XML eliminates byte-ordering concerns. XMLs hierarchical structure, extension capability, processing tools, and XML Schema definitions are an added advantage. Distributed systems have provided interfaces for formally describing methods and parameters. With these interfaces, the client can invoke the required service. Web services should also provide a means for describing the services and providing the information that the client needs to invoke them. This data is represented in XML. This is a major advantage because XML is neither platform specific nor vendor specific.
Oracle 10g: Build J2EE Applications 18-9

Benefits of Web Services (continued) Programming Language Independent Web services are programming language independent. They enable application-toapplication communication. With Oracle Application Server 10g, any existing J2EE application and PL/SQL procedure can be exposed as a Web service. Accessibility Web services are accessible with standard protocols such as HTTP and HTTPS. Through Web services standards, clients and servers can communicate over HTTP regardless of platform or programming language. SOAP builds on XML and provides a standard format for invoking a Web service. Communication Through Firewalls Distributed applications are aimed at thousands of users. Communication between the client and the server has problems due to firewalls and proxy servers. The main advantage of using SOAP is that it is firewall-friendly because SOAP is layered over HTTP. Exposing Existing Components as Web Services with Oracle Application Server 10g Building a J2EE application involves: Coding the business-tier components that contain the business logic Designing a user interface (a Web page in most cases) Building an application (typically a servlet, JSP, or ASP) that can receive input from the user interface and invoke an appropriate business-tier component Formatting the response as HTML and sending the page to the client Web Services are not dependent on HTML. Java classes and Enterprise JavaBeans (EJBs) can be directly exposed as Web Services, saving development time and improving maintainability. Communication Styles Synchronous: In synchronous messaging, the client and the server must be available at the same time for successful communication. The operation is not complete until the target of the message processes the request information and sends a response back to the client. Asynchronous: In asynchronous messaging, the client and the server need not be available at the same time. The client sends a message to the destination, and does not wait for an acknowledgement. The message can be processed at any time, and the responses arrive via callbacks.

Oracle 10g: Build J2EE Applications 18-10

Web Services Model


Client application XML interface (WSDL)
2 Find

Web services directory


(UDDI)

3 Invoke

1 Publish

XML interface (WSDL) Web service

Copyright 2005, Oracle. All rights reserved.

Web Services Model Java classes, stateless session EJBs, and PL/SQL procedures can be exposed as Web services with Oracle Application Server 10g. When you develop and deploy a Web service in Oracle Application Server 10g, a WSDL is automatically generated. The WSDL has information about the attributes and return types of the methods that can be invoked as Web services. The Web services are registered with the UDDI registry for lookup by the client applications. The illustration in the slide shows the following: 1. A Web service is generated and published to the UDDI registry. 2. The client application browses the UDDI registry to locate an appropriate Web service. There can be many Web services registered with a particular UDDI registry. You can find the Web service that is required by your application, and obtain WSDL definition that describes the services. 3. The client application can invoke any operation of the Web service. Operation in a Web service refers to methods that are exposed as Web services. The client can invoke them with an instance of a proxy class, just like invoking a method on the local machine.

Oracle 10g: Build J2EE Applications 18-11

RPC-Style Web Services


RPC-style Web services are loosely coupled. SOAP messages model the call and response semantics. This style of communication can be described in WSDL.

Copyright 2005, Oracle. All rights reserved.

RPC-Style Web Services You have already learned that Web services can use different communication styles: RPC style and message style. You now learn about RPC-style Web services. RPC-style Web services are interface driven and loosely coupled. They are synchronous. Clients use the Web service by sending parameters and receiving return values. A client sends a SOAP message that contains details about the method to be invoked and the parameters for that method. The SOAP servlet (designed to handle RPC SOAP requests) unwraps the SOAP message envelope and identifies the method to be invoked. The servlet decodes the parameters and invokes the method. The SOAP servlet encodes the return values into a SOAP response and sends it back to the client over the same protocol with which the request was sent. Therefore, the client and the server must be available at the same time to successfully complete the RPC invocation. The applications on the client and the server need not be written in the same language, unlike Remote Method Invocation (RMI), in which the client and the server are Java applications. Therefore, RPC-style Web services are loosely coupled.

Oracle 10g: Build J2EE Applications 18-12

Document-Style Web Services


Document-style Web services are loosely coupled. SOAP messages carry arbitrary XML documents. This style of communication can be described in WSDL.

Copyright 2005, Oracle. All rights reserved.

Document-Style Web Services A document-style Web service follows the messaging style of communication. In document style, the Web services client sends an entire XML document to be processed by the Web service. Unlike in an RPC-style Web service, there is no concept of a method name or input/output in a document-style Web service. A document-style Web service does not model call/response semantics. Instead, it carries XML documents that can also be described in WSDL. Document-style Web services can be synchronous or asynchronous. For synchronous document-style Web service, Oracle supports certain method signatures. Clients call these methods to pass the documents, and in turn get a modified document as response. In an asynchronous document-style Web service, the messages are sent to intermediate destinations often referred to as topics or queues. These messages are then received by the actual destinations depending on their availability. RPC-style APIs require endpoints that need a good infrastructure in large-scale distributed applications. Document-style Web services communicate in a loosely coupled manner and, therefore, make it possible to develop new application behavior in a declarative manner. If XML messages describe themselves, then the senders and receivers need to know less about the infrastructure. RPC-style Web services have RPC/Encoded operations, and document-style Web services have DOC/Literal operations. RPC/Encoded operations and DOC/Literal operations are WSDL (metadata) concepts.
Oracle 10g: Build J2EE Applications 18-13

Oracle Support for Web Services


Oracle Application Server 10g is the infrastructure for: Describing Web services Deploying Web services Publishing Web services Invoking Web services Oracle JDeveloper 10g provides tools for: Developing, deploying, publishing, and invoking Web services Modeling, testing, and debugging Web services Browsing UDDI registry to locate Web services Generating stub files to consume Web services

Copyright 2005, Oracle. All rights reserved.

Oracle Support for Web Services Oracle Application Server 10g provides an infrastructure for: Exposing stateless/stateful Java classes, stateless session EJBs, PL/SQL procedures and functions, and Java Message Service (JMS) destinations as Web services. Oracle Application Server 10g Web services are integrated with the J2EE framework. Web services are described by using standard WSDL. Oracle Application Server provides tools to automatically generate the WSDL. Web services can be invoked by using standard Internet protocols. These Web services can be consumed from existing J2EE applications. Oracle Application Server 10g provides a highly optimized Web services proxy client that can be downloaded and embedded into the clients application. Oracle JDeveloper 10g is an integrated development environment (IDE) that can be used to develop, deploy, test, and debug Web services. It can be used to model Web services with Unified Modeling Language (UML) class diagrams. It can be used to generate WSDL, client stubs, and skeletons. You can use the UDDI browser to browse the UDDI registry and locate Web services. By using JDeveloper, you can deploy the Web service either to the standalone OC4J or to Oracle Application Server 10g.

Oracle 10g: Build J2EE Applications 18-14

SOAP: XML Messaging for Web Services


Introduces a self-describing data representation format in XML Represents request and response as XML messages Supports both RPC-style and document-style invocation Uses HTTP and other protocols at transport layer Supports data encoding and literal styles SOAP hides details of implementations; works with:
Any programming language Any operating system Any hardware platform
Copyright 2005, Oracle. All rights reserved.

SOAP: XML Messaging for Web Services SOAP is a lightweight, XML-based protocol for exchanging data in a distributed environment. SOAP hides the technology choices and implementation details from both parties: service requestor and service provider. SOAP is in XML and places no restriction on the format. SOAP provides a simple and lightweight mechanism for exchanging structured and typed information between peers in a decentralized, distributed environment by using XML. SOAP itself does not define any application semantics such as a programming model or implementation-specific semantics; instead, it defines a simple mechanism for expressing application semantics by providing a modular packaging model and encoding mechanisms for encoding data within modules. SOAP V1.1 describes how the data types defined in associated XML schemas can be serialized, or marshaled, over HTTP (or other transports). SOAP is transport independent. It can be layered over SMTP and FTP. Most common implementations are over HTTP. Both the publisher and the consumer of SOAP messages must have access to the same XML schemas to correctly exchange information. The schemas are typically posted on the Internet, and may have to be downloaded by one or more persons in an exchange of messages.
Oracle 10g: Build J2EE Applications 18-15

Communication with SOAP


Communication by using SOAP protocol includes: Requests to invoke a service Responses from service method Fault from a service

Request

Response SOAP client Firewall Web server

Copyright 2005, Oracle. All rights reserved.

Communication with SOAP SOAP is used for communication between applications. A client sends a request for a service. This request is a SOAP message and is in the standard XML format. The request includes information about the recipient of the message and parameters for successfully invoking the service. This message is then handled by the Request Handler (a servlet) running on the Web server. The Request Handler invokes the requested service. The service returns a response to the Request Handler servlet. The Request Handler returns the response of the service to the client. The response includes return values from the methods. In case of errors while processing the request, SOAP fault codes are returned.

Oracle 10g: Build J2EE Applications 18-16

SOAP Messages
A SOAP message is an XML document that consists of: A mandatory envelope as a toplevel element An optional header A mandatory body An optional fault
HTTP headers SOAP envelope SOAP header Headers SOAP body Message name, data, and fault element

Copyright 2005, Oracle. All rights reserved.

SOAP Messages SOAP is the second generation XML protocol that uses XML schema for data types. Therefore, it is highly extensible. First generation XML protocols rely on XML1.0 and are not extensible. SOAP does not define any application semantics such as a programming model or implementation-specific semantics; instead, it defines a simple mechanism for expressing application semantics. The slide shows a SOAP message over HTTP protocol that contains the following elements: HTTP headers: When a SOAP protocol is used over HTTP, the packet starts with an HTTP header, which contains information about the operation, method, Content-Type, Content-Length, error codes, and the recipient of the message. Envelope: Envelope is a mandatory and top-level element in a SOAP message. Envelope is a wrapper for the message and defines a framework for expressing what is in a message and how to process it. The element contains namespace declarations. It can have subelements and attributes. The SOAP Envelope can contain an optional Header element, but should contain a Body element.

Oracle 10g: Build J2EE Applications 18-17

SOAP Messages (continued) Header: The Header is optional. If present, Header is the first child element of Envelope. Header is included to add features to a SOAP message without prior agreement between the communicating parties. A Header can in turn have any number of headers. These headers are included to provide additional information that is handled by infrastructure services. In a real-world scenario, login information, session information, security, transactional information, and so on, can be included in the body. However, this approach makes the SOAP message more complicated. Instead, this information can be included as multiple headers. Body: The Body element provides a simple mechanism for exchanging mandatory information with the ultimate recipient of the message. This element includes RPCs and error reporting. In case of request messages, the body section contains the methodspecific information that is required to invoke the method. In the response message, the body section contains the return message from the Web service. In case of an error condition, the Body element can contain a Fault element. Fault: Fault element is used to indicate that an error has occurred and provides information about the error. This element is used to carry error or status information within a SOAP message. Fault elements appear as a body entry and must not appear more than once within a Body element. A SOAP application should include the proper SOAP namespaces on all elements that are defined in messages. SOAP messages should not contain Document Type Definition (DTD) and Processing Instructions (PI).

Oracle 10g: Build J2EE Applications 18-18

Web Services Description Language (WSDL)


Is a description language to define Web service interfaces and how to invoke them Is an XML Schema for describing Web services:
Service interface definition: Describes what message must be sent and what message is returned Service implementation definition: Describes to which address the message must be sent

Allows both the messages and the operations on the messages to be defined abstractly in XML Answers three key questions about a Web service:
What does a service do? How is a service accessed? Where is a service located?
Copyright 2005, Oracle. All rights reserved.

WSDL SOAP provides a standard way of transporting messages for use by Web services, whereas WSDL provides a standard way to describe Web services. WSDL is an XML format for describing Web services. WSDL describes what functionality a Web service offers, how it communicates, and where it is accessible. Because it is in the standard XML format, the services developed can easily be made available to thousands of users. Users must invoke the correct services with the appropriate parameters. WSDL defines an XML grammar to specify the location of the service and to describe the operations of a service. A WSDL file contains the following information about an operation: Service interface Implementation details Access protocol Contact endpoints

Oracle 10g: Build J2EE Applications 18-19

WSDL
<?xml version=1.0 encoding=UTF-8 ?> <definitions name=Hello ... targetNamespace=http://tempuri.org/Hello.wsdl ...> <types> <schema targetNamespace=http://tempuri.org/Hello.xsd ... xmlns:xsd=http://www.w3.org/2001/XMLSchema /> </types> <message name=sayHelloOutput>... </message> <message name=sayHelloInput> ... </message> <portType name=HelloPortType> <operation name=sayHello> .... </operation> </portType> <binding name=HelloBinding> <operation> <input>..</input> <output>..</output> </operation> </binding> <service ..> <port> <soap:address location=.. /> </port> </service> </definitions>

Copyright 2005, Oracle. All rights reserved.

WSDL (continued) The slide shows the various tags in a WSDL file. <definitions>: The WSDL document starts with a <definitions> tag. This tag encloses all other tags in the file. This tag contains a few namespace declarations. In Web services, the data that is exchanged between the client and the server must conform to XML Schema. The namespace declarations contained in the <definitions> tag point to the XML Schema definition. For communication using the SOAP protocol, the SOAP libraries are needed. The <definitions> tag contains the SOAP namespace that specifies where to look for these libraries. <types>: The <types> element encloses data type definitions for the exchanged messages. This element contains the xsd schema namespace. This schema is where you define custom types to use with messages. For interoperability and platform neutrality, WSDL uses data types as defined in the XML Schema specification. Therefore, the data types that are used to pass parameters and obtain return values must conform to xsd.

Oracle 10g: Build J2EE Applications 18-20

WSDL (continued) <message>: The <message> element corresponds to the methods of the Web services that can be invoked by a client application. For example, if a function called sayHello() is exposed as a Web service, there are two messages associated with this method: one is the input message and the other is the output message. Therefore, there are two <message> elements associated with every method of a Web service. <portType>: A <portType> is a set of abstract operations and their messages. The operation is the method that is exposed as a Web service. Each <portType> has a unique name identified by the name attribute. Each <portType> can consist of one or more operations. If the <portType> contains an operation called sayHello, that means a function called sayHello is exposed as a Web service. There are two messages associated with this operation: an input message and an output message. The input and output elements of the operation element correspond to these messages. These messages and their parameters are used with the <message> element that you have already learned. <binding>: The <binding> element is used to specify that SOAP protocol is used over HTTP. It also shows whether it is an RPC-style invocation or a document-style invocation of Web service. <service>: The <service> element contains the name of the Web service, the location of the Web service, and the context with which it can be accessed. A service groups a set of related ports together. It can contain zero or more port elements. The port elements specify how this service can be accessed. A port contains a network address and the binding of the Web service. Note that the WSDL file is automatically generated and, therefore, each tag of the WSDL file is not explained in detail.

Oracle 10g: Build J2EE Applications 18-21

UDDI Registry
Is an online electronic registry for registering businesses and Web services Is a specification for description and discovery Supports the Publishing and Inquiry APIs to publish and inquire about a Web service

Copyright 2005, Oracle. All rights reserved.

UDDI Registry You have been introduced to Web services and their benefits. You have also learned that WSDL is used to describe Web services, and that the SOAP protocol is used to invoke them. To invoke a Web service, the service requestor should first discover the service and then send the SOAP message. The UDDI is a registry where businesses and Web services are registered. The requestor can use UDDI to discover a Web service. What Is UDDI? UDDI Project is an industry initiative that provides standards for publishing and discovering information about Web services. The UDDI community, which is established by several leading software vendors including IBM, Microsoft, and Oracle, runs the UDDI Project and makes its results available to the public through http://www.uddi.org/. UDDI is a directory service where businesses can register and search for Web services. It is a platform-independent framework for describing services, discovering businesses, and integrating business services. The UDDI registry can be used at a business level to discover if there are any Web service interfaces with a given type of service. UDDI serves as a mechanism for businesses to reach their customers and partners. It is used to locate information about how the service is exposed and to learn the technical details required to interact with that service.
Oracle 10g: Build J2EE Applications 18-22

UDDI Registry (continued) The UDDI Business Registry is a logically centralized, physically distributed service, with multiple root nodes that replicate data with each other on a regular basis. After a business registers with a single instance of the business registry service, the data is automatically shared with other UDDI root nodes and becomes freely available to anyone who needs to discover which Web services are exposed by a given business. These are public registries. You can also have private UDDI registries. To ensure that most platforms can access UDDIs services, the UDDI directory exposes a set of APIs. These APIs fall under two main categories: Inquiry and Publishing. To involve these APIs, you must send SOAP messages with appropriate body content. The SOAP response that comes back from UDDI contains the businesses that match the search criteria.

Oracle 10g: Build J2EE Applications 18-23

How UDDI Is Used


Business portals and marketplaces UDDI Business Registry

UDDI Registry Business descriptions Service types

Business user

Software developer

Copyright 2005, Oracle. All rights reserved.

How UDDI Is Used UDDI can be used in a number of different ways, based on the perspective of the user. For example, a business user can browse one or more UDDI registries to view the different businesses that expose Web services. However, business users will not use the UDDI registry directly, because the UDDI APIs are not necessarily user-friendly. Instead, business users might use business search portals, marketplaces, or other tools that provide a more user-oriented interface. Tools such as portals and marketplaces use the UDDI Inquiry API to access the registry data. Software developers can use the UDDI Publishing API to publish services. They also might programmatically query the registry to discover services dynamically. The UDDI Business Registry is a conceptually single system that can be built from multiple nodes, called Operator Sites, that have their data synchronized through replication. The UDDI Business Registry is a public registry that anyone can use. A company can set up a private registry that is not part of the public UDDI Business Registry, for its internal use. Private registries can define the access rules of their nodes for different users.

Oracle 10g: Build J2EE Applications 18-24

Searching for a Web Service by Using UDDI


Provider info Contact Info Directory of names White pages Search using context such as location, service type. Point to White pages for details. Yellow pages Information about business model Technical details of provided service Information on business process Green pages

Copyright 2005, Oracle. All rights reserved.

Searching for a Web Service by Using UDDI The UDDI registry contains three types of information that are referred to as the white, yellow, and green pages. White Pages White pages contain basic contact information about a company, including name, address, and contact information. This information allows users to search for businesses and to locate Web services based on the companys business identification. Yellow Pages Yellow pages contain high-level service information, such as service name, a humanreadable service description, a list of categories to which the service belongs. This information allows users to discover a Web service based upon its categorization. Services can be categorized by several taxonomies such as North American Industry Classification System (NAICS), Universal Standard Products and Services Classification (UNSPSC), and ISO 3166 Geographic Taxonomy. Green Pages Green pages contain low-level information required to invoke services. This includes business processes, service descriptions, and binding information. Binding information supplies the service location and protocol that is used to communicate with the service.
Oracle 10g: Build J2EE Applications 18-25

UDDI Specification

UDDI Programmers API UDDI Data Structure Specification and XML Schema UDDI Replication Specification and UDDI XML Replication Schema UDDI Operators Specification

Copyright 2005, Oracle. All rights reserved.

UDDI Specification (Version 2.0) The UDDI Specification consists of the following set of specification and XML schema documents: The UDDI Programmers API specification defines a set of functions that all UDDI registries support for inquiring about services hosted in a registry, and for publishing information about a business or a service to a registry. This specification defines a set of SOAP messages containing XML documents that a UDDI registry accepts. The UDDI Data Structure Specification describes the XML structures that are contained within the SOAP messages defined by the UDDI Programmers API. This specification defines five core data structures and their relationships to each other. The UDDI XML Schema is not a specification document, but an XML Schema document that defines the structure and data types of the UDDI data structures. The UDDI Replication Specification describes the data replication process and the API that is required to accomplish data replication between UDDI Operator Nodes. The UDDI Operators Specification describes the behavior and operational parameters that are required by UDDI Node Operators. (This specification defines no programmers API, and is not relevant for private registries.)

Oracle 10g: Build J2EE Applications 18-26

tModel

Provides metadata information about a Web service specification Contains references to the specification locations Is used for compliance check

Copyright 2005, Oracle. All rights reserved.

tModel A <tModel> is an abstract description of a particular specification of the Web service. A <tModel> is a type of digital fingerprint for determining the specifics of how to interact with a particular Web service. The <tModel> structure does not provide the Web services specification directly. Instead, it contains pointers to the locations of the actual specifications. Companies can use the information pointed to by a <tModel> to determine whether a Web service is compatible with their business requirements. The relation between businessService and tModel is described as follows: <businessService> has a <bindingTemplate> that contains one or more <tModelInstanceInfo> documents. Each <tModelInstanceInfo> document contains a tModelKey attribute that is the Universal Unique Identifier (UUID) of a <tModel> document, representing information about the supporting specification. When businesses want to make their specification-compliant services available to the registry, they include a reference to the tModelKey attribute for that service type in their <bindingTemplate>.

Oracle 10g: Build J2EE Applications 18-27

tModel

<tModel tModelKey="uuid:7716711A-1231-483F-A4B936104341BA78" operator= authorizedName=> <name>Airport Weather</name> <description xml:lang="en"> Web Service to check weather on intl. airports </description> <overviewDoc> <description ></description> <overviewURL>
http://live.capescience.com/wsdl/AirportWeather.wsdl

</overviewURL> </overviewDoc> ... </tModel>

Copyright 2005, Oracle. All rights reserved.

tModel (continued) The slide shows a fragment of the tModel structure. Each <tModel> contains a UUID as a tmodelKey attribute. UUIDs are unique hexadecimal strings that are generated when the data structure is first inserted into the UDDI registry. The tModel name identifies the service. In this example, Airport Weather is the service. The description supplies explanatory information. The tModel also contains an <overwiewDoc> entry which in turn contains an <overviewURL> entry. This URL points to the service WSDL description. A <tModel> has several uses in the UDDI registry. The most common use is to represent a technical specification or concept. The designer of a specification or a concept publishes information about the specification by registering it in an UDDI registry as a tModel. Thus, a tModel identity is defined in the registry, but the actual specification or set of documents that describes the concept of a tModel is not a part of the registry. Instead, it is remotely referenced by the <overviewDoc> structure.

Oracle 10g: Build J2EE Applications 18-28

tModel (continued) How WSDL Relates to UDDI Data Structure WSDL is used to describe the interface of a Web service. It contains an abstract specification of the service, including specification of service parameters, their types, and communication protocols. A WSDL interface can also contain information that is specific to a particular service instance. This information is defined in the <service> and <port> elements that identify the actual service location (the URL of the Web service). If a service is used within the context of UDDI, both parts, the abstract interface definition and the service specific information, can be separated. The abstract service interface definition can be registered in a UDDI registry as a tModel with the <overviewDoc> structure pointing to the WSDL document that describes the service. Such tModel structures are referred to as wsdlSpec tModels. Service providers, who want to provide a service that is compliant to the specification, retrieve a tModel and use the WSDL pointed by it for the service implementation. A new service can then be registered in an UDDI registry. It is represented by the <businessService> data structure, which contains a <bindingTemplate> for each service access point. Furthermore, the <bindingTemplate> includes a <tModelInstanceInfo> element for each wsdlSpec <tModel> that describes the interfaces and bindings supported by the service. The WSDL pointed to by the tModel does not contain the <service> and <port> elements. These service locationspecific information is specified as an <accessPoint> element in the <bindingTemplate>. Consider an example:
<tModel tModelKey="UUID:7F1DA096-B073-48C1-9B21-FE9613CA8FA4" operator=..." authorizedName=...">

<name>Address Correction for USA addresses WSDLinterface</name>


<description xml:lang="en"> Corrects Postal Addresses. Converts Zip Codes to City Names </description>

<overviewDoc> <description xml:lang="en"/> <overviewURL> http://ws.cdyne.com/psaddress/addresslookup.asmx?wsdl </overviewURL> </overviewDoc> <categoryBag> <keyedReference tModelKey="UUID:C1ACF26D-9672-4404-9D7039B756E62AB4" keyName="uddi-org:types" keyValue="wsdlSpec" /> </categoryBag> </tModel>

Oracle 10g: Build J2EE Applications 18-29

tModel (continued) How WSDL Relates to UDDI Data Structure (continued) This tModel also contains a <categoryBag> element that has a tModelKey. In this context, the tModel is used for categorization. A <tModel> that references a WSDL document has a categorization taxonomy of uddi-org:types and categorization value of wsdlSpec that are used in the <categoryBag> element. When a <tModel> refers to a WSDL document, it refers to the entire content of the document, including all of its bindings. If a <tModel> should refer to a single binding, then a fragment identifier is used in the <overviewURL>. The name of this particular binding is used after the hash sign in <overviewURL>. For example:
<overviewURL> http://stockquote-definitions/stq.wsdl#StockQuoteSoapBinding </overviewURL>

<tModel> refers specifically to StockQuoteSoapBinding.

Oracle 10g: Build J2EE Applications 18-30

UDDI Support in Oracle JDeveloper 10g


JDeveloper provides a UDDI browser with which you can: Define a connection to a UDDI registry instance Search for services: Look up tModel by name or category
Locate a service implementing this tModel Add a business providing this service to the UDDI browser

For the located service:


Generate Web service stub/skeleton View WSDL View a business that provides the service
Copyright 2005, Oracle. All rights reserved.

UDDI Support in Oracle JDeveloper 10g UDDI Browser Oracle JDeveloper 10g provides a built-in UDDI browser. You can locate and use Web services in an external UDDI registry or in a private UDDI registry. You can use the Oracle JDeveloper 10g UDDI browser to define a connection to a specific UDDI registry instance, and then to search for a specific Web service. After a desired Web service is found, JDeveloper can generate a proxy stub to invoke the located service programmatically. Define UDDI Registry Connection In the Oracle JDeveloper 10g Navigator panel, under the Connections node, you can find the UDDI Registry entry. Expanding this entry shows a number of predefined UDDI registry connections. You can use these existing connections or you can define new ones to other UDDI registries by using a UDDI Registry Connection Wizard. The wizard prompts you to provide the Connection Name and the Inquiry URL for the Registry instance.

Oracle 10g: Build J2EE Applications 18-31

UDDI Browsing with Oracle JDeveloper 10g

Copyright 2005, Oracle. All rights reserved.

UDDI Browsing with Oracle JDeveloper 10g Find Services You can search for a specific service for a selected UDDI connection by using a Find Web Services Wizard. To start this wizard, right-click any UDDI registry and select Find Web Services. You can use the wizard to search for a tModel by name or category, and then to select existing services from the list of businesses that provide the implementation of the specified tModel. The wizard provides several options for a located service. They are: Generating the stub code for service invocation. The stub is generated and added to an existing project. The business that provides the service is added as a node in the Navigator tree. Opening the end point of this service in the browser Displaying a description for the located service Adding the business to the UDDI browser for further navigation or actions Generate Stub After a specific service is located, the Oracle JDeveloper 10g Web Service Stub/Skeleton Wizard can be used to generate a client-side stub for service invocation or a server-side skeleton for the service implementation. The wizard uses the WSDL of the service that was previously located in UDDI. You can select the operations that are defined in the WSDL for which the stub code must be generated.
Oracle 10g: Build J2EE Applications 18-32

UDDI Publishing and Browsing with Oracle Enterprise Manager


Using Oracle Enterprise Manager Application Server Control Console, you can: Browse and register services within the UDDI registry Publish Web services and deploy them to a J2EE container Monitor and administer Web services

Copyright 2005, Oracle. All rights reserved.

UDDI Publishing and Browsing with Oracle Enterprise Manager With Oracle Enterprise Manager Application Server Control Console, users can manage all their UDDI registry instances from a single console. Oracle Enterprise Manager provides intuitive service browsing and registration. Users can search services based on keyword, service name, service ID, and category information. Oracle Application Server administrators can easily publish Web services as part of the J2EE application deployment wizard. In addition, users can administer J2EE container services for monitoring and logging Web service activities such as up-time, response-time, throughput, CPU, and memory consumption; setting up service failover plans; defining Web service access timeouts; and specifying service access credentials.

Oracle 10g: Build J2EE Applications 18-33

Utilizing External Web Services from JDeveloper

Copyright 2005, Oracle. All rights reserved.

Utilizing External Web Services from JDeveloper Some functionality such as currency conversion, ISD codes, weather information, and so on is already available as Web Services on the Internet. These services are hosted on external sites such as www.xmethods.com and www.capescience.com. You can make use of such services by creating a stub file using JDeveloper. All you need is the WSDL URL. To generate the stub file with a known WSDL URL, right-click any existing project, select New > Web Services from the Business Tier of Categories, and select Web Service Stub/Skeleton. The Generate Web Service Stub/Skeleton Wizard is displayed. Click the Next button and provide the URL of the WSDL file of the Web service. If you want to test invoking the Web service with the stub file itself, you can generate the main()method in the stub. If you want to add a node for the WSDL URL to System-Navigator, select the Import WSDL URL Into Project check box. Click the Next button, and follow the steps of the Wizard to generate the stub file.

Oracle 10g: Build J2EE Applications 18-34

Summary
In this lesson, you should have learned how to: Provide an overview of Web services technology Identify the standards used by Web services Identify the benefits of Web services Locate and invoke Web services by using SOAP, WSDL, and UDDI Distinguish between RPC-style and Documentstyle Web service

Copyright 2005, Oracle. All rights reserved.

Summary In this lesson, you should have learned about Web services. You should have also learned about standards such as SOAP, WSDL, and UDDI. This lesson discussed the benefits of Web services and the different styles of Web services.

Oracle 10g: Build J2EE Applications 18-35

Practice 18-1: Overview


This practice covers revision questions on Web services technology and standards such as SOAP, WSDL, and UDDI.

Copyright 2005, Oracle. All rights reserved.

Practice 18-1: Overview The practice consists of paper-based questions on Web services technology and the standards such as SOAP, WSDL, and UDDI.

Oracle 10g: Build J2EE Applications 18-36

Practice 18-1 Paper-Based Questions 1. Identify three features of Web services. a. Self-describing business function b. Interfaces for a client to invoke a business function c. Service oriented d. Component based e. Language dependent 2. Which three of the following can be exposed as Web services with Oracle Application Server 10g? a. Stateless/stateful Java classes b. C programs c. PL/SQL stored procedures d. Stateless session EJBs e. Stateful session EJBs 3. SOAP is: (Choose two correct answers.) a. A heavyweight protocol b. An XML-based protocol c. Always layered over HTTP d. Request oriented and response oriented 4. Which three of the following statements regarding a SOAP message are true? a. It should have Envelope as top-level element. b. If Envelope is not present, Header should be the top-level element. c. If Header is present, then it should immediately follow the Envelope element. d. It should have a Body, but need not have a Header element. e. It should have an Envelope, Body, and Header, irrespective of their order. 5. Match the elements of a SOAP message in column A to the appropriate statements given in column B.
A 1. Envelope 2. Header 3. Body B a. Is a mandatory element that contains methodspecific information b. Is the top-level element in the SOAP message and contains namespace declarations c. Is an optional element that encapsulates data not specific to the method

6. WSDL is used for: (Choose two correct answers.) a. Locating a Web service b. Describing a Web service c. Invoking a Web service d. Sending messages
Oracle 10g: Build J2EE Applications 18-37

Practice 18-1 (continued) 7. UDDI is: (Choose one correct answer.) a. Universal Directory Difference Information b. Universal Discovery Directory Interface c. Universal Description, Discovery, and Integration 8. Which of the following statements regarding UDDI are true? (Choose three correct answers.) a. An online electronic registry b. Specification for description and discovery c. A registry with key and value pair d. Uses WSDL to describe a service e. Enables search on only one criteria

Oracle 10g: Build J2EE Applications 18-38

Distributing Modular Applications: Developing Web Services

Copyright 2005, Oracle. All rights reserved.

Objectives
After completing this lesson, you should be able to do the following: Identify the components that can be exposed as Web services with Oracle Application Server 10g Develop, deploy, and test a stateless Java class Web service by using Oracle JDeveloper 10g Use the Web services home page to test the deployed Web service Identify the steps that are involved in exposing a PL/SQL stored procedure as a Web service

Copyright 2005, Oracle. All rights reserved.

Objectives This lesson describes how to expose a stateless Java class as a Web service. You learn to use Oracle JDeveloper 10g to develop and deploy a stateless Java Web service. This lesson shows you how to create a client to invoke a Web service. It also discusses the steps involved in exposing a PL/SQL stored procedure as a Web service.

Oracle 10g: Build J2EE Applications 19-2

Oracle Application Server 10g Web Services


Oracle Application Server 10g Web services can be implemented as any of the following: Stateless and stateful Java classes Stateless PL/SQL packages Stateless session Enterprise JavaBeans (EJBs) Java Message Service (JMS) destinations
Copyright 2005, Oracle. All rights reserved.

Oracle Application Server 10g Web Services Oracle Application Server 10g supports building Web services from stateless Java classes and stateful Java classes, stateless PL/SQL packages, and stateless session EJBs. Java Message Service (JMS) destinations can also be exposed as Web services. This lesson describes how to develop and deploy stateless Java classes and PL/SQL packages as Web services.

Oracle 10g: Build J2EE Applications 19-3

Developing a Web Service with a Stateless Java Class


1. 2. 3. 4. Define an interface. Define a stateless Java class. Generate an .ear file. Deploy the generated .ear file to Oracle Application Server 10g.

Copyright 2005, Oracle. All rights reserved.

Developing a Web Service with a Stateless Java Class Developing a Web service with a stateless Java class involves the following steps: 1. Writing an interface (optional) 2. Writing a stateless Java class 3. Generating the .ear file that can be deployed to Oracle Application Server 10g 4. Deploying the generated .ear file to Oracle Application Server 10g Oracle JDeveloper 10g simplifies the creation of Web services. You can use JDeveloper 10g to create, deploy, and test the Web service. The following few slides show you how to create a Web service with a stateless Java class.

Oracle 10g: Build J2EE Applications 19-4

Defining an Interface

Copyright 2005, Oracle. All rights reserved.

Defining an Interface The example used is a stateless Java class that is exposed as a Web service. The Hello Web service contains a sayHello() method, which takes a String as parameter and returns a String when it is invoked. Why Define an Interface? Writing an interface is optional. If an interface is not defined for a class, then the Web service deployment exposes all public methods that are defined in the Java class as Web services. You define an interface to limit the exposure of methods to a subset of the public methods within a class. Although a class can contain n number of public methods, it is not necessary to expose them all as Web services to clients. Therefore, an interface can contain declarations of methods that can be exposed as Web services. Creating the Interface Using JDeveloper 10g Create a workspace and a project. Right-click the project and select New Java Interface as shown in the slide. Provide a name for the new interface. Observe that the name Hello is used for this example. The interface will be created. You have to define the methods of the interface. The slide shows the interface called Hello. It declares a single method, sayHello(), that takes a String as parameter and returns a String.
Oracle 10g: Build J2EE Applications 19-5

Defining an Interface

Copyright 2005, Oracle. All rights reserved.

Defining an Interface (continued) In the interface, declare a single method, sayHello(), that takes a String as parameter and returns a String. The slide shows the method in the interface.

Oracle 10g: Build J2EE Applications 19-6

Defining a Stateless Java Class

Copyright 2005, Oracle. All rights reserved.

Defining a Stateless Java Class After the interface is defined, the next step is to define a Java class. Right-click the project and select New Java Class. Provide a name for the class. Observe that the name HelloImpl is used for this example.

Oracle 10g: Build J2EE Applications 19-7

Defining a Stateless Java Class

Copyright 2005, Oracle. All rights reserved.

Defining a Stateless Java Class (continued) The Java class (whose methods will be exposed as Web services) must include a public constructor that takes no arguments. The HelloImpl class contains the implementation for the sayHello() method declared in the Hello interface. This method takes a String as parameter, appends that parameter to Hello and returns the result String to the client. Although this class can have any number of methods, only the sayHello() method can be exposed as a Web service. Note that the class does not implement the interface Hello, though you have defined an interface with the sayHello() method and implemented that method in the HelloImpl class. The details of the interface and the implementation class are provided in the configuration file that is used to generate the Enterprise Archive (EAR) file. If you are using stand-alone Oracle Application Server 10g Containers for J2EE (OC4J) or Oracle Application Server 10g, then you have to create the config.xml configuration file that contains the details of the interface and the implementation class. The WebServicesAssembler (WebServicesAssembler.jar) uses this config file to create the EAR file for the Web service. If you are using JDeveloper 10g, then the config file is created automatically when you create the Web service.

Oracle 10g: Build J2EE Applications 19-8

Defining a Stateless Java Class (continued) There is a restriction on the data types of parameters and return types of the methods that are exposed as Web services. The following table shows the supported data types.
Primitive Types boolean byte double float int long short Object Types java.lang.Boolean java.lang.Byte java.lang.Double java.lang.Float java.lang.Integer java.lang.Long java.lang.Short java.lang.String java.util.Date org.w3c.dom.Element org.w3c.dom.Document org.w3c.dom.DocumentFragment JavaBeans Single-dimension arrays of types mentioned in the table

Oracle 10g: Build J2EE Applications 19-9

Creating the Web Service

Copyright 2005, Oracle. All rights reserved.

Creating the Web Service You have already created the interface and the implementation class by using JDeveloper 10g. You will now create a Web service from the Java class. Right-click the Java class and select Create J2EE Web Service. Check the System-Navigator to see the files that are created for the Web service. The web.xml and WebServices.deploy files are generated. The MyWebService1 shown under the demo1.jpr in the System-Navigator is the Web service that is created. It consists of the IMyWebService1.java and the IMyWebService1.wsdl files. In the System-Navigator, if you click the Show Categories icon (that resembles three folders placed one below the other with a line next to them), then you see the various Web service files that are created, such as WEB-INF, web.xml, and the deployment files.

Oracle 10g: Build J2EE Applications 19-10

Creating the Client Application

Copyright 2005, Oracle. All rights reserved.

Creating the Client Application Create a client application to test the Web service. Right-click the Web service as shown in the slide and select Generate Sample Java Client.

Oracle 10g: Build J2EE Applications 19-11

Creating the Client Application

Copyright 2005, Oracle. All rights reserved.

Creating the Client Application (continued) The Java client created is the EmbeddedMyWebService1Stub.java file as shown in the slide. In the code editor, look for a commented line that says Add your code here, and add the method invocation. In the example, the following statement is used to invoke the Web service:
System.out.println(stub.sayHello(Web Services));

Oracle 10g: Build J2EE Applications 19-12

Deploying the Web Service

Copyright 2005, Oracle. All rights reserved.

Deploying the Web Service Right-click the Web service and select Run. The embedded OC4J server of JDeveloper 10g will start and the Web service will be deployed to the OC4J server. Observe the Log window and note the URL that you can use to access the Web service.

Oracle 10g: Build J2EE Applications 19-13

Testing the Web Service

Copyright 2005, Oracle. All rights reserved.

Testing the Web Service Right-click the Java client and select Run. The output is displayed in the Log window.

Oracle 10g: Build J2EE Applications 19-14

Web Service Home Page


A Web service home page provides: A link to the service description (WSDL file) Links to Web service test pages to test the available operations of the Web service Links to the Web service client-side Proxy Jar Links to the Web service client-side Proxy Source

Copyright 2005, Oracle. All rights reserved.

Web Service Home Page Oracle Application Server 10g provides a Web service home page for each deployed Web service. To access a home page, enter a service endpoint (URL) that is displayed in the Log window when you deploy the Web service.

Oracle 10g: Build J2EE Applications 19-15

Testing the Deployed Web Service with Home Page

Copyright 2005, Oracle. All rights reserved.

Testing the Deployed Web Service with Home Page The slide shows the home page of the Web service. Click the Service Description link to access the WSDL file. You can also retrieve the WSDL file with the URL http://host:port/URI?WSDL, where URI is the path for the Web service. The MyWebService1 service has a single operation called sayHello. Click the link sayHello to invoke the operation.

Oracle 10g: Build J2EE Applications 19-16

Testing the sayHello Operation

Copyright 2005, Oracle. All rights reserved.

Testing the sayHello Operation When you click the sayHello link, you see the page where you can provide the parameter to invoke the sayHello operation. Enter the parameter in the text field as shown and click the Invoke button to invoke the operation.

Oracle 10g: Build J2EE Applications 19-17

Testing the sayHello Operation

Copyright 2005, Oracle. All rights reserved.

Testing the sayHello Operation (continued) When you click the Invoke button, you see the Simple Object Access Protocol (SOAP) response for the Hello Web service as shown in the slide.

Oracle 10g: Build J2EE Applications 19-18

Serializing and Encoding Parameters and Results


Oracle Application Server 10g Web services support a prepackaged implementation for handling encoding, decoding, serialization, and deserialization. Oracle Application Server 10g supports the following encoding mechanisms: Standard SOAP v.1.1 encoding Literal XML encoding

Copyright 2005, Oracle. All rights reserved.

Serializing and Encoding Parameters and Results The parameters that are passed from the client are serialized and encoded in XML. These parameters are decoded and deserialized when the Web service receives the request. Similarly, the results or return types are serialized and encoded when they are sent from the server to the client. They are deserialized and decoded when the client receives the response. The prepackaged mechanism of Oracle Application Server 10g makes the encoding and decoding transparent to the Web service developer and the client application that invoke the Web service. Standard SOAP, Version 1.1 Encoding Using standard SOAP, version 1.1 encoding, the server-side Web services servlet, which calls the Java class implementation, handles serialization and encoding internally for the types that are supported by Oracle Application Server 10g Web services. Literal XML Encoding By using Literal XML encoding, a Web service client can pass as a parameter, or a Java service can return as a result, a value that conforms to W3C Document Object Model (DOM) org.w3c.dom.Element. When an Element is passed as a parameter to a Web service, the server-side Java implementation processes the Element. For return values that are sent from a Web service, the Web services client parses or processes org.w3c.dom.Element. This style is mainly used for document-style Web services.
Oracle 10g: Build J2EE Applications 19-19

Developing a Stored Procedure Web Service


1. Set up data sources in OC4J by configuring the data-sources.xml file in the ORACLE_HOME\j2ee\home\config folder. 2. Generate the Java wrapper classes for the PL/SQL package and generate the EAR file. 3. Deploy the EAR file to Oracle Application Server 10g or stand-alone OC4J to expose it as a Web service.

Copyright 2005, Oracle. All rights reserved.

Developing a Stored Procedure Web Service You have seen how to develop Web services with stateless Java classes. Now you will see how to develop and deploy a PL/SQL stored procedure Web service. PL/SQL stored procedures can be exposed as Web services by generating Java wrapper classes for the procedures. These wrapper classes are generated by the JPublisher tool. Therefore, you need not recode the functionality of the existing PL/SQL procedures in a different programming language to make them available as Web services. Developing a stored procedure Web service involves the following steps: 1. Set up data sources in data-sources.xml file. 2. Generating the Java wrapper classes for a PL/SQL package. You need not explicitly invoke the JPublisher tool to generate the classes. Oracle JDeveloper implicitly invokes JPublisher. 3. Generating the EAR file 4. Deploying the procedure as a Web service to Oracle Application Server 10g or standalone OC4J

Oracle 10g: Build J2EE Applications 19-20

Generating Wrapper Classes Using JPublisher

Database

JPublisher

Java classes

Copyright 2005, Oracle. All rights reserved.

Generating Wrapper Classes Using JPublisher JPublisher is a utility, written in Java. It is used to generate Java classes to represent the user-defined database entities such as SQL object types, SQL collection types, and PL/SQL packages in your Java program. JPublisher generates classes for PL/SQL packages. These classes have wrapper methods to invoke the stored procedures in the PL/SQL packages. The wrapper methods generated by the JPublisher tool contain SQLJ code. When JPublisher generates wrapper methods, it generally produces .sqlj source files. You can use the methods option of JPublisher to indicate that no wrapper methods should be generated. Then, JPublisher produces .java source files. To expose a stored procedure or function as a Web service, you need not explicitly use JPublisher to create the Java source files. JDeveloper invokes JPublisher to create them.

Oracle 10g: Build J2EE Applications 19-21

Exposing a Function as a Web Service by Using Oracle JDeveloper 10g

Copyright 2005, Oracle. All rights reserved.

Exposing a Function as a Web Service by Using Oracle JDeveloper 10g A connection is established to the database from JDeveloper. The screenshot shows that the schema has a package called emp_pack. This package has a function called get_name that takes an employee number as a parameter and returns that employees first name and last name. You will now see how to expose this function as a Web service.

Oracle 10g: Build J2EE Applications 19-22

Publishing the Package as a Web Service

Copyright 2005, Oracle. All rights reserved.

Publishing the Package as a Web Service Right-click the package body or package in the System-Navigator. Select Publish as Web Service from the context menu. You see the PL/SQL Web Service Publishing Wizard screen. The wizard takes you through the steps to publish the PL/SQL function as a Web service. A stateless session bean can also be exposed as a Web service. The steps to be followed to expose a stateless session bean as a Web service are the same as those involved in exposing an existing Java class as a Web service. In the practice for this lesson, you expose a stateless session bean created in lesson 12 as a Web service.

Oracle 10g: Build J2EE Applications 19-23

JMS Web Services


Oracle Application Server 10g supplies a servlet to support two operations on messages:
Send operation Receive operation

The JMS Web service determines how to handle incoming and outgoing messages from JMS destinations. JMS messages can be processed on the server side by:
Message-Driven Bean (MDB) JMS client

Copyright 2005, Oracle. All rights reserved.

JMS Web Services With Oracle Application Server 10g, you can create JMS Web service that puts messages on and takes messages off JMS destinations. Oracle Application Server 10g supplies a servlet that supports two operations on messages: Send operation: If the destination is a JMS Queue, then send means enqueue. If the destination is a topic, then send means publish the message. The client supplies an XML element and the Web service enqueues this on JMS destination. Receive operation: If the destination is a JMS Queue, then receive means dequeue. If the destination is a topic, then receive means consume the message. The Web service dequeues a message from a specified destination and return it to the client. An individual JMS Web service can support the send operation, or the receive operation, or both operations, as determined by the service developer. The Web services run-time verifier throws an exception if the operation supplied by a JMS Web service client is invalid. For example, if the deployment operation is send, and the request is receive, then an exception is thrown.

Oracle 10g: Build J2EE Applications 19-24

JMS Web Services (continued) The JMS Web service only exposes JMS destinations. The messages are processed either by an MDB or a JMS client on the server. A JMS Web service either sends messages to a JMS destination or receives messages from a JMS destination and can use an MDB on the back end to receive messages. Because JMS uses MDB for generating and consuming messages, it is important to define MDBs.

Oracle 10g: Build J2EE Applications 19-25

Summary
In this lesson, you should have learned how to: Expose a stateless Java class as a Web service Test the Web service with the Web service home page Use Oracle JDeveloper 10g to develop, deploy, and test Web services Expose a PL/SQL stored procedure as a Web service

Copyright 2005, Oracle. All rights reserved.

Summary In this lesson, you should have learned how to expose a stateless Java class as a Web service, and how to develop and deploy Web services from Java classes by using Oracle JDeveloper 10g. You should have also learned how to use Web services home page to test the deployed Web service, and how to write a client application to invoke the Web service. You have learned that a PL/SQL stored procedure can be exposed as a Web service by: 1. Creating Java wrapper classes by using Jpublisher. 2. Creating an EAR file. 3. Deploying the EAR file to Oracle Application Server 10g or stand-alone OC4J.

Oracle 10g: Build J2EE Applications 19-26

Practice 19-1: Overview


This practice covers the following topics: Exposing a stateless session bean as Web service by using Oracle JDeveloper 10g Deploying the Web service to an embedded OC4J server and testing it with a client application Deploying the Web service to Oracle Application Server 10g and testing it with the Web services home page

Copyright 2005, Oracle. All rights reserved.

Oracle 10g: Build J2EE Applications 19-27

Practice 19-1 The purpose of this practice is to expose a stateless session EJB as a Web service. You expose the ValidateCard session bean created in practice 12 as a Web service. Perform the following steps to expose the validate(String s) method of the ValidateCard session bean as a Web service. 1. Expose the ValidateCard session bean as a Web service: a. Open the workspace practice12oneske.jws. You can use this workspace if you have successfully completed practice 12-1. Otherwise, use practice12onesoln.jws. b. Right-click the project; select New. Choose Web Services from the Business node of Categories and select Java Web Service from Items. c. Click OK. You see the Web Service Publishing Wizard. Click Next. d. Browse to select the ValidateCard remote interface. Click Next. e. Select the validate(java.lang.String) method and click Next. In the Web Service Endpoint change the Web Server Port to 8988, because the embedded OC4J runs on port 8988. JDeveloper picks the port number from here and generates the WSDL file. The endpoint in the WSDL file has the same port number. Click Next and then click Finish. f. Note that the Web service, MyWebService1, and the Webservices.deploy files are generated. 2. Generate a client to test the Web service with embedded OC4J. a. Right-click the Web service and select Generate Sample Java Client. b. The sample client is generated. Check the port number in the String endpoint in the client application. c. Edit the client and add the following line to the try block of the main method:
System.out.println(stub.validate(BN349672A));

3. Run the Web service and the client application: a. Right-click the Web service and select Run. Note: Check the port on which embedded OC4J runs and make sure that the string endpoint in the client application (created in step 2 b) has the same port number, or change the port number in the client program. b. Right-click the client application and select Run. You should see the following line displayed in the Log window:
THANKYOU FOR PROVIDING YOUR CUSTOMER CARD NUMBER

Note: If you see any SOAP exceptions when you run the client application, then it is because of port conflicts.

Oracle 10g: Build J2EE Applications 19-28

Practice 19-1 (continued) 4. Deploy the Web service to Oracle Application Server 10g by performing the following steps: a. Right-click the WebServices.deploy file in the System-Navigator and select Deploy to <connection> if a connection to Oracle Application Server 10g already exists. Otherwise, select Deploy and then select New Connection. The Connection Wizard is displayed. Click Next. b. Type Connection1 for Connection Name, select Oracle Application Server 10g from the Connection Type drop-down list. Click Next. c. Provide the username and password. Click Next. d. Specify the Oracle Home directory. Click Next. e. Type welcome for the Remote Method Invocation (RMI) password. Click Next. Click the Test Connection button to test your connection. Wait to see the status Success and then click Finish. f. You see the deployment messages in the Log window. Wait for the process to complete. g. Start Internet Explorer, type the following URL to go to the Enterprise Manager Application Server Control: http://localhost:1810. Enter User Name and Password. h. Click home under System Components. Click the Applications link. You will find a link for your application in the Deployed Applications list. Click the link to see the details of the deployed application. You will see the WebServices link under Web Modules. i. Note the URL binding for this application and the name of the application. In this example, the URL binding is /practice12oneskevalidatecard-context-root and the name is MyWebService1. j. You can now access the Web service with the URL
http://localhost:7777/practice12oneske-validatecardcontext-root/MyWebService1.

k. You will see the Web Services home page. l. Click the validate link. Enter the string BN349672A in the text field and click Invoke. m. You can see the SOAP response from the Web service.

Oracle 10g: Build J2EE Applications 19-29

Implementing Security in J2EE Applications

Copyright 2005, Oracle. All rights reserved.

Objectives
After completing this lesson, you should be able to do the following: Define Java Authentication and Authorization Service (JAAS) Define security issues regarding Web applications and Enterprise JavaBeans (EJB) List the security attributes of the Java Naming and Directory Interface (JNDI) Context interface

Copyright 2005, Oracle. All rights reserved.

Objectives In this lesson, you learn how to configure security for your Java 2, Enterprise Edition (J2EE) applications, because different clients can access your Web applications and EJB components. You also examine how to edit the deployment descriptor to declaratively (instead of programmatically) control access to Web applications and EJB components so that only authorized clients can access the required functionality.

Oracle 10g: Build J2EE Applications 20-2

Goals of J2EE Security Architecture


Lessen the burden of the application developer in securing applications Ensure fine-grained access control to the EJB resources Enable portable and secured Web applications and EJBs

Copyright 2005, Oracle. All rights reserved.

Goals of J2EE Security Architecture Security is a critical issue in the development and deployment of the J2EE applications. The goals of the J2EE security architecture are: To ease the bean developers burden of coding the security mechanism. The security details need not be coded into the bean but can be controlled declaratively by specifying the details in the deployment descriptor when either the application package is assembled or at the time the application is deployed. To provide a fine-grained security mechanism so that an application and its methods can be accessed only by authenticated and authorized users. You can control access to the Web application functionality, based on a URL pattern, or method specifications in an EJB component. To provide a flexible architecture that allows the Web applications or EJB to be used in any security environment. This enables the applications to be portable across multiple J2EE containers. These goals assume that the developer may not have any idea of the target security environment and its requirements. Instead, the application deployer can customize, or map the security policies in the deployment descriptor, depending on the operational environment in which the applications are being deployed.
Oracle 10g: Build J2EE Applications 20-3

Overview of J2EE Security Architecture


Use Java Authentication and Authorization Service (JAAS) APIs to: Authenticate a client to access the system
Define security identities (principal/users), groups, and roles to identify clients to the container Associate principals to the client to enable access to the bean methods

Authorize clients to access the bean methods


Define logical roles, set method permissions, and map roles to users in the deployment descriptors Use containers to authorize the client requests to the methods

Copyright 2005, Oracle. All rights reserved.

Overview of J2EE Security Architecture The J2EE security architecture involves the authentication and the authorization of clients to the system and, for an EJB, the individual methods of the bean. Oracle Application Server 10g supports JAAS by implementing a JAAS provider. The JAAS provider enables application developers to integrate authentication and authorization services into their applications environments. Instead of allocating resources to developing these services, application developers can focus on the presentation and the business logic of their applications. Authentication is the process of verifying the identity of a user, device, or any other entity in a computer system, often as a prerequisite to granting this entity access to resources in a system. For example, when a user enters a username and a password to access the resources on a computer (such as a database) before being permitted access to these resources, the user must first be authenticated (verified) by means of the login information. Authorization is the process of verifying whether a particular method call request from a client should be allowed to execute the method. After a user is authenticated, the authorization process occurs. Authorization is the process of determining if the authenticated user has the right to perform the requested operation (such as updating a table in a database).

Oracle 10g: Build J2EE Applications 20-4

Java Authentication and Authorization Service (JAAS)


JAAS is a framework that: Provides a Java API package to enable applications to authenticate and enforce security Allows definition of logical security names that are mapped in deployment descriptors to users or roles defined in the run-time environment Controls access to Web applications based on URL patterns Allows fine-grained authorization to manage how clients can access bean methods A JAAS provider implements the JAAS framework and applies the Java2 Security Model.
Copyright 2005, Oracle. All rights reserved.

Java Authentication and Authorization Service (JAAS) The JAAS provider implements JAAS and its policies, and integrates with J2SE and J2EE applications that use the Java2 Security Model. JAAS extends the access control architecture of the Java2 Security Model to support principal-based authorization. Policies contain the rules (permissions) that authorize a user to use resources, such as reading a file. Permissions are the basis of the Java2 Security Model. Each permission represents a specific access to a particular resource. All Java classes (whether run locally or downloaded remotely) are subject to a configured security policy that defines the set of permissions that are available for those classes. You can use the Java2 Security Model to configure security at all levels of restriction. This provides developers and administrators with increased control over many aspects of enterprise applet, component, servlet, and application security. JAAS is designed to complement the existing code-based security in JDK 1.3. JAAS implements a Java version of the standard Pluggable Authentication Module (PAM) framework, enabling an application to remain independent from the authentication service. The Web application security involves authentication and authorization of clients based on URL patterns, and the EJB security architecture allows fine-grained access control to the individual methods of a bean.
Oracle 10g: Build J2EE Applications 20-5

Java Authentication and Authorization Service (JAAS)


JAAS supports the following authorization, authentication, and user community (realm) features: Principals Subjects Login module authentication Roles Realms Policies Permissions

Copyright 2005, Oracle. All rights reserved.

Java Authentication and Authorization Service (JAAS) (continued) JAAS supports the following authorization, authentication, and user community (realm) features: Principals: A principal is a specific identity, such as a user named Smith or a role named HR. A principal is associated with a subject on successful authentication to a computing service. Subjects: A subject represents a grouping of related information for a single user of a computing service, such as a person, computer, or process. Such information includes the subjects identities and security-related attributes (such as passwords and cryptographic keys). Subjects can have multiple identities, where principals represent identities in the subject. A subject becomes associated with a principal (user Smith) on successful authentication to a computing service; that is, the subject provides evidence (such as a password) to prove its identity. Login module authentication: To associate a principal with a subject, a client attempts to log in to an application. In login module authentication, the LoginContext class provides the basic methods that are used to authenticate subjects such as users, roles, or computing services. Roles: JAAS does not explicitly define roles or groups. Instead, roles or groups are implemented as concrete classes that use the interface java.security.Principal.
Oracle 10g: Build J2EE Applications 20-6

Java Authentication and Authorization Service (JAAS) (continued) Realms: JAAS does not explicitly define user communities. However, the J2EE Reference Implementation (RI) defines a similar concept of user communities called realms. A realm provides access to users and roles (groups) and optionally provides administrative functionality. Policy: A policy is a repository of JAAS authorization rules. The policy includes grants of permissions to principals, thereby answering the following question: Given a grantee, what are the granted permissions of the grantee? Policy information is supplied by the JAAS provider, which can be file based or can use a Lightweight Directory Access Protocol (LDAP) server. Permissions: Permissions are the basis of the Java 2 Security Model. All Java classes (whether run locally or downloaded remotely) are subject to a configured security policy that defines the set of permissions available for those classes. Each permission represents a specific access to a particular resource. A permission instance comprises a class name (such as java.io.FilePermission), a target or resource to which the permission applies (for example, a directory pattern such as /home/*), and a set of actions associated with the target (such as read, write, and/or execute).

Oracle 10g: Build J2EE Applications 20-7

Authorization of a Client
The authorization is specified in the J2EE-specific and OC4J-specific deployment descriptors. Security roles
Define the security view of the application to the deployer Must be mapped to the appropriate security principals in the target environment

Every client obtains a security principal. A client can invoke a URL or a method only if the clients role has the associated invocation rights. The container provider enforces the security policies and provides the tools for managing security.
Copyright 2005, Oracle. All rights reserved.

Authorization of a Client The security roles that are defined by the application assembler provide the deployer with a logical and simplified security view of the Web application, or the EJB. The deployer is responsible for mapping the logical security roles to principals or to groups of principals that are defined in the target operational environment. At run time, a client is allowed to access a URL or invoke a business method only if the principal making the request is authenticated and authorized (by being associated with an appropriate security role) to access the requested resource. The container provider enforces the security policies at run time and provides the tools for managing security during deployment and at run time. The security view defines the various types of users of the application and their rights to invoke a URL request or methods in the enterprise bean interfaces. Note: The security roles define the logical security view of an application. They should not be confused with the user groups, users, principals, and other concepts that exist in the target enterprises operational environment. The security roles and information are configured and mapped in configuration files and deployment descriptors, as discussed in the following slides.
Oracle 10g: Build J2EE Applications 20-8

JAAS Provider Types in OC4J


The JAAS provider in Oracle Application Server 10g Containers for J2EE (OC4J) supports two provider types: The LDAP-based provider type that is used to access an Oracle Internet Directory (OID) repository The XML-based provider type that is used to access an XML file repository by using:
The jazn-data.xml file The principals.xml file

The repositories store the realm (users and roles) and the policy (permissions) information.
Copyright 2005, Oracle. All rights reserved.

JAAS Provider Services The JAAS provider supports two types of repository providers (referred to as provider types): LDAP-based provider type: Used to access an OID repository XML-based provider type: Used with an XML filebased repository, typically jazn-data.xml, or via principals.xml OID and jazn-data.xml are repositories that are used to store the realm (users and roles) and the policy (permissions) information. This course discusses configuring security with an XML repository file by using the jazn-data.xml file. The OC4J container uses jazn-data.xml as the default security provider because: Passwords are encrypted (They are not encrypted in principals.xml.) A <role> element represents a group comprising users and other roles. The principals.xml file uses a <group> element that does not allow another group to be part of it, and associates a principal with multiple groups in the <user> element. You can use JAAS Role Based Access Control (RBAC), including role hierarchies, direct assignment of permissions to a role, and activation of permissions for the role Full support for the Java 2 Permission Model is implemented
Oracle 10g: Build J2EE Applications 20-9

Configuring Security
Define users and groups in jazn-data.xml (or principals.xml). Define security view or logical roles in J2EE deployment descriptor (web.xml or ejbjar.xml). Map logical roles to users and groups in OC4Jspecific deployment descriptor (orion-web.xml or orion-ejb-jar.xml). Provide a user or group with read and write access to the Java Naming and Directory Interface (JNDI) namespace in application.xml (or application-specific orion-application.xml).
Copyright 2005, Oracle. All rights reserved.

Configuring Security The configuration of the security environment involves: Defining users and groups in a configuration file, that is, in the jazn-data.xml (or principals.xml) file Defining logical roles in the J2EE application deployment descriptor Mapping the logical roles to users and groups in the Oracle-specific deployment descriptor The other methods of authorization and authentication include the LDAP-based OID and the use of single sign-on features of the Oracle Application Server 10g architecture. You can use the JAAS API to build custom providers. The jazn-data.xml file is used in the course examples and labs because it is the default provider and it is easy to configure. To allow a client access to the JNDI namespace, the OC4J application.xml file must be modified by adding a user or group element in a <security-role-mapping> element. For example, allow read access to the JNDI namespace for the administrators group:
<namespace-access><read-access><namespace-resource root=""> <security-role-mapping><group name="administrators" /> </security-role-mapping> </namespace-resource></read-access> ... </namespace-access> Oracle 10g: Build J2EE Applications 20-10

Defining the Users, Groups, and Roles


The identities (users and groups) are known to the container by using the jazn-data.xml. The identities can be specific to an application.

<jazn-realm> <realm><name>jazn.com</name> <users> <user><name>admin</name> <display-name>OC4J Administrator</display-name> <description>OC4J Administrator</description> <credentials>{903}5NwtZOAJa2Ty7Ksbmu3IUOfK9PgK/Kxi </credentials> </user> <user><name>user</name> <description>The default user</description> <credentials>{903}/pQcVBQ6+AN+NNF2MzYb/0+gR4lOVwwh </credentials> </user> ...

Copyright 2005, Oracle. All rights reserved.

Defining the Users, Groups, and Roles A realm provides access to users and roles (groups) and optionally provides administrative functionality. The users and groups are identities that are known by the container. Roles are the logical identities that each application uses to indicate access rights to different objects. Security credentials can be defined at: A global application level: Users and groups can be shared by all the deployed applications if they are defined in the global jazn-data.xml file located in the <ORACLE_HOME>/j2ee/home/config directory. A specific application level: Users and groups may be defined for a particular application by being listed in the application-specific jazn-data.xml file, which is identified in the orion-application.xml file for that application. The <users> element defines one or more users. Each user is specified in a <user> element. A user may be associated with a role that is defined in the file. The example, (jazn-data.xml file) in the slide above shows how to define a realm, called jazn.com, containing the users admin and user. Observe that passwords are encrypted. Each <role> element defined in the <roles> element identifies the group name and provides a <members> element to specify the users belonging to the group (or role). A member element can contain another role name; that is, roles can be hierarchical (see the example in the following slide).
Oracle 10g: Build J2EE Applications 20-11

Defining the Users, Groups, and Roles (continued) Example of jazn-data.xml:


<jazn-realm> <realm> <name>jazn.com</name> <users> ... </users> <roles> <role> <name>administrators</name> <display-name>Realm Admin Role</display-name> <description>Admin role for realm.</description> <members> <member> <type>user</type><name>admin</name> </member> </members> </role> <role> <name>users</name> <members> <member> <type>user</type><name>user</name> </member> <member><type>role</type> <!--creates hierarchy--> <name>administrators</name> </member> </members> </role> </roles> ... </realm> </jazn-realm> ...

Note: In this sample XML file, the <member> element whose <type> is role shows how one role (in this case administrators) can belong to another role, that is, the users role. This is the implementation of a role-based hierarchical structure.

Oracle 10g: Build J2EE Applications 20-12

Managing Users and Groups with the JAZN Admintool


The JAZN Admintool can manage users, roles, and groups and can assign roles to users in XML or LDAPbased data. It modifies jazn-data.xml or the LDAP repository. It prompts for admin username and password. Examples: java Adding a user: adduser jazn.com ora1 oracle jar jazn.jar java Adding a role (oraddrole a group): jar jazn.jar jazn.com managers java Granting a role to a user (assign user to a group): jar jazn.jar grantrole manager jazn.com ora1
Copyright 2005, Oracle. All rights reserved.

Managing Users and Groups with the JAZN Admintool The JAZN Admintool can be used to manage both XML and LDAP-based JAAS data from the command-line prompt. It is a Java application in the jazn.jar file that is located in the Oracle Application Server Containers for J2EE (OC4J) home directory. To run the Admintool, ensure that the following lines are added to your Java Runtime Environment java.security file (Note: This file is located in the <JRE_HOME>/lib/security directory):
auth.policy.provider=oracle.security.jazn.spi.PolicyProvider login.configuration.provider=\ oracle.security.jazn.spi.LoginConfigProvider

To run the Admintool, open a Console window and change the directory to the OC4J home directory, for example, <JDEV_HOME>\j2ee\home. You can enter the following command for help: java jar jazn.jar help The help command does not prompt for a username or a password. The first example on the slide shows how to add a user to a realm. The first parameter after the adduser option is the realm name (jazn.com is the default) followed by the username and password. The password is encrypted in the XML file. Note: The Enterprise Manager Web interface of Oracle Application Server 10g can also manage J2EE security.
Oracle 10g: Build J2EE Applications 20-13

Managing Users and Groups with the JAZN Admintool (continued) The second example in the preceding slide shows how to create a role. Roles are also added to a realm. The addrole option is followed by the realm name and then the role name, which in this case is managers. The third example in the slide assigns the role of managers to the user ora1 in the jazn.com realm. This assigns the user to a role (group). Each time you execute the command-line tool, you are prompted for a username and password. The username and password must be a valid combination that is found in the jazn-data.xml file. However, for administrative tasks (such as creating new users), the user must be privileged, such as the OC4J admin user. The following is an example of using the tool to list realms:
prompt> java -jar jazn.jar listrealms RealmLoginModule username: admin RealmLoginModule password:******** jazn.com

The result text is: jazn.com. The JAZN Admintool has several command-line options. Some of the useful options are: Listing the realms:
java jar jazn.jar -listrealms

Listing all the users in a realm:


java jar jazn.jar listuser jazn.com

Listing all the roles in a realm:


java jar jazn.jar listroles jazn.com

Listing users assigned to the users role in a realm:


java jar jazn.jar listusers jazn.com role users

Creating a role hierarchy by granting a role to another role in a realm:


java jar jazn.jar grantrole users jazn.com role manager

Note: This adds the managers role as a member of the users role. If you intend to execute multiple commands with the JAZN Admintool in one session, then it is recommended that you invoke the command shell feature of the JAZN Admintool. In this way, you need to log in only once for the shell session. To start a JAZN Admintool shell session, use the following command:
java jar jazn.jar shell RealmLoginModule username: admin RealmLoginModule password:******** JAZN:> listusers jazn.com/user ... JAZN:> adduser jazn.com ora1 oracle JAZN:> exit

For more information about JAZN Admintool, refer to Oracle Application Server 10g Containers for Java: Service Guide.

Oracle 10g: Build J2EE Applications 20-14

Defining the Logical Roles


The logical security roles defined in the J2EE deployment descriptors are: Specified in the web.xml file for Web applications, or in the ejb-jar.xml file for EJB components. Defined in the <security-role> element for the application. One or more roles can be specified. Authorized to invoke methods that are listed in the <method-permissions> element for the security role. Scoped at the level of the application or all the enterprise beans in the jar file.

Copyright 2005, Oracle. All rights reserved.

Defining the Logical Roles The roles are logical identities that each application uses to indicate access rights to its different objects. The Web application (web.xml) and EJB deployment descriptor (ejbjar.xml) identify roles that are needed to access different URLs or methods of the application. In the J2EE deployment descriptors, security roles are defined in the <security-role> element that is located in the <assembly-descriptor> element. Because the application assembler provides the (logical) security view of the application, the deployers job is simplified. The application assembler defines one or more security roles in the deployment descriptor and then assigns URL patterns or groups of methods of an enterprise bean to the security roles. Because the application assembler generally does not know the security environment of the operational environment, the security roles are meant to be logical roles (or actors), each representing a type of user that should have the same access rights to the application. The application deployer can then map the logical roles to the security definitions in the execution environment of the application.
Oracle 10g: Build J2EE Applications 20-15

Defining and Using Logical Roles in Web Applications (web.xml)


Define logical role in the <security-role> element Use role in <security-constraint> element
<security-role> <role-name>hr_managers</role-name> <!--define--> </security-role> <security-constraint> <web-resource-collection> <web-resource-name>UpdEmployee</web-resourcename> <url-pattern>/UpdEmployees.jsp</url-pattern> </web-resource-collection> <auth-constraint> <role-name>hr_managers</role-name> <!--apply--> </auth-constraint> <user-data-constraint> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint></security-constraint>
Copyright 2005, Oracle. All rights reserved.

Defining and Using Logical Roles in Web Applications The example in the slide shows how to define a logical security role, named hr_managers, that is to be used by the Web application. Each logical role is defined in the <security-role> element, and many security role elements can be defined. The logical role is applied to a URL pattern that is contained in a <securityconstraint> element. The elements that nest in the <security-constraint> definition are as follows: The <web-resource-collection> element contains a <web-resourcename> that contains one or more <url-pattern> elements. The <web-resource-name> element is the name of the Web application. The <url-pattern> element defines the URL pattern for Web application pages. The <auth-constraint> element gives access to users in the logical role to the collection of URLs that are identified in the enclosing security constraint. The <user-data-constraint> element indicates whether the data that is communicated between the client and the container is protected or not.

Oracle 10g: Build J2EE Applications 20-16

Defining and Using Logical Roles in Web Applications (continued) Note: By default, all users have access to the URLs that are provided in the Web applications, unless you control the access by using the mechanisms that are shown in the slide. The J2EE applications can obtain the username and password from the OC4J container or Web application server, which can be configured to obtain the credentials from HTML form fields, basic or digest authentication mechanisms, or Oracle Single Sign-On services.

Oracle 10g: Build J2EE Applications 20-17

Defining and Using Logical Roles in EJBs (ejb-jar.xml)


Define logical role in <security-role> element. Assign access in <method-permission> element.

<assembly-descriptor> <security-role> <description>HR Manager</description> <role-name>hr_managers</role-name> </security-role> <method-permission> <role-name>hr_managers</role-name> <method><ejb-name>HrApp</ejb-name> <method-name>incrementSalary</method-name> <method-params><method-param>int</method-param> <method-param>int</method-param></method-params> </method></method-permission> ... <assembly-descriptor> ...

Copyright 2005, Oracle. All rights reserved.

Defining and Using Logical Roles in EJBs (ejb-jar.xml) The code in the slide shows the process of specifying the security roles and method permissions on different beans and their methods. All these details are specified in the <assembly-descriptor> element of the XML deployment descriptor. You can specify many security roles with the <security-role> element. The example in the slide shows hr_managers being specified as a role name. The <method-permission> element specifies the role name (from the security role specified above), bean, and its method names for which this role is authenticated. The method permissions are defined for the method that is named in the <method-name> element. The name of a method can be specified as: An asterisk (*) representing all methods in the component A specific individual method name in the component, including its parameters Note: By default, if OC4J generates the EJB deployment descriptor, then it prevents access for all users to methods of the EJB, unless the access is explicitly specified. However, JDeveloper generates an OC4J deployment descriptor that allows the calling user access to all the methods of an EJB. The example in the slide assumes that all the users have been granted access to all the methods of the HrApp bean, except the incrementSalary() method, which can be executed only by users belonging to the hr_managers role.
Oracle 10g: Build J2EE Applications 20-18

Mapping Logical Roles to Users and Groups


Mapping is done in the OC4J deployment descriptors. A logical role to a group:
<security-role-mapping name = "hr_managers"> <group name="managers"/> </security-role-mapping>

A logical role to a user:

<security-role-mapping name = "hr_managers"> <user name="ora1"/> </security-role-mapping>

A logical role to a group or a specific user:

<security-role-mapping name = "hr_managers"> <group name="managers"/> <user name="ora1"/> </security-role-mapping>


Copyright 2005, Oracle. All rights reserved.

Mapping Logical Roles to Users and Groups The mapping of the logical security roles, defined in the J2EE deployment descriptors, is done by using the OC4J-specific deployment descriptor files. Define mapping in: orion-web.xml for Web applications orion-ejb-jar.xml for EJB components orion-application.xml for either the Web applications or the EJB components The logical roles are mapped to the actual users or roles (groups) defined in the security provider that is configured for the J2EE environment (for example, the jazn-data.xml file). The slide shows examples of mapping a logical role to a group, to a specific user, or to a combination of users and groups. For example, method access is given to all the users in the managers group:
<security-role-mapping name="hr_managers" impliesAll="true" > <group name="managers" /> </security-role-mapping>

The impliesAll attribute that is set to true includes all the users with the hr_managers role that are mapped as managers in the J2EE environment. To define the default access permissions for all methods in an EJB component, you define the security role mappings in the <default-method-access> element.
Oracle 10g: Build J2EE Applications 20-19

Programmatic Access to a Callers Security Context


Not all security policies can be expressed declaratively. Use a programmatic interface to access the security context of the calling client from the bean methods. To access the security information of the caller, the javax.ejb.EJBContext interface defines the following two methods:
java.security.Principal getCallerPrincipal(); boolean isCallerInRole(java.lang.String roleName);

Copyright 2005, Oracle. All rights reserved.

Programmatic Access to a Callers Security Context Sometimes a bean code may have special requirements or may need to know the security principal or the role name of the user that is calling methods on the bean. Such a requirement may arise because of the need to perform some special operations of logic for certain user roles or principals. The EJB architecture provides access to the security context of the clients for these purposes. The interface used is the EJBContext:
public interface javax.ejb.EJBContext { ... java.security.Principal getCallerPrincipal(); boolean isCallerInRole(java.lang.String roleName); ... }

The getCallerPrincipal() method is used to obtain the Principal object representing the client that is currently accessing the bean. The Principal object can then be used to track the identity of the clients that are making updates to the specified bean. The isCallerInRole() method tells you whether the client accessing the bean is a member of a specific role, identified by a role name. This method is useful when more access control is needed than the simple method-based access control can provide. This method allows fine-grained programmatic access control to the methods of a bean.
Oracle 10g: Build J2EE Applications 20-20

Client Authentication
For Web applications:
Use Web application server security mechanisms, where credentials are passed through to the J2EE environment Use OC4J container Web security Examples: Basic or Digest Authentication, HTML form fields, and Client SSL certificates

For EJB components:


Stand-alone (remote) clients define credentials in InitialContext, and the jndi.properties file or settings in a Hashtable. Local clients, such as servlets, JSPs, or other EJBs, pass their credentials by using the Context object.
Copyright 2005, Oracle. All rights reserved.

Client Authentication The authentication of Web clients can be managed by using Oracle Application Server 10g HTTP Server capabilities, such as basic or digest authentication, HTML form fields, or Single Sign-On services managed by an LDAP-based service, such as Oracle Internet Directory (OID). Alternatively, you can use similar services from within the OC4J container. For example, you can enable basic authentication for a J2EE Web application by adding the following <login-config> element details to the Web application deployment descriptor (web.xml):
<login-config> <auth-method>BASIC</auth-method> </login-config>

The container then requests a username and password from the Web browser. When you access EJBs in a remote container, you must pass valid credentials to this container. Stand-alone clients define their credentials in initial context. The credentials can then be initialized by using the jndi.properties file deployed with the Enterprise Archive (EAR) file, or the Hashtable. Servlets or JavaBeans running within the container pass their credentials in the InitialContext, which is created to look up the remote EJBs.
Oracle 10g: Build J2EE Applications 20-21

EJB Client Authentication with the jndi.properties file


In the jndi.properties file:
java.naming.security.principal=ora1 java.naming.security.credentials=welcome java.naming.factory.initial=com.evermind.server.\ ApplicationClientInitialContextFactory java.naming.provider.url=ormi://localhost/hrApp

Client accessing the EJB with the above JNDI properties:


Context ic = new InitialContext(); EmployeeHome = (EmployeeHome) ic.lookup( "java:comp/env/Employee");

Copyright 2005, Oracle. All rights reserved.

EJB Client Authentication with the jndi.properties file The client can authenticate by using the JNDI properties defined and deployed with the EJB. The example in the slide shows the jndi.properties file that contains the security principal and credential details defined for the Employee EJB. The client uses the Context object obtained by creating the initial context and performs a look up for the Employee EJB. The JNDI properties file contains a list of key/value pairs. The key is the name of the property (for example, java.naming.factory.initial), and the value is a string in the format defined for that property. The use of this file to specify any JNDI environment properties allows the JNDI to be configured with minimal programmatic setup. Setting the JNDI properties is discussed in the lesson titled Communicating in J2EE. Note: The trailing backslash in the line containing the java.naming.factory.initial value is a standard continuation character used in Java property files to allow a value to continue over more than one line.

Oracle 10g: Build J2EE Applications 20-22

EJB Client Authentication with a Hashtable


Hashtable env = new Hashtable(); env.put("java.naming.provider.url", "ormi://localhost/hrApp"); env.put("java.naming.factory.initial", "com.evermind.server." + "ApplicationClientInitialContextFactory"); env.put(Context.SECURITY_PRINCIPAL, "ora1"); env.put(Context.SECURITY_CREDENTIALS, "welcome"); Context ic = new InitialContext (env); EmployeeHome = (EmployeeHome) ic.lookup( "java:comp/env/Employee");

Copyright 2005, Oracle. All rights reserved.

Client Authentication: InitialContext To access remote EJBs from a local client such as a servlet, another EJB, or a Java ServerPage, the client passes the credentials in the InitialContext object, as shown in the slide. A client needs to specify the following attribute values to authenticate itself with the server: The user ID (Context.SECURITY_PRINCIPAL) The password (Context.SECURITY_CREDENTIALS) The client sets these property values in a Hashtable that is used to get the JNDI InitialContext. Note: Setting the client authorization by using the JNDI properties and the InitialContext object is discussed in lesson 10 of this course.

Oracle 10g: Build J2EE Applications 20-23

Setting Access Control with JDeveloper


You can set security roles to access a Web application or an EJB by using JDeveloper deployment descriptor editors:
Use the Web Application Deployment Descriptor editor for Web applications. Use the EJB Module Editor for EJBs.

For Web applications, set the access permissions as constraints defining URL patterns for a Web resource. For EJBs, set the access permissions for either individual methods or all the methods of the bean.

Copyright 2005, Oracle. All rights reserved.

Setting Access Control with JDeveloper You can create security roles for Web applications or EJB modules by using: The Web Application Deployment Descriptor editor for Web applications The EJB Module Editor for EJBs The Web Application Deployment Descriptor editor is displayed by right-clicking the web.xml file and choosing the Settings menu option. You define the logical security role in the Security section, and define access rules for the logical roles for a Web resource and URL patterns in the Constraints section. The EJB Module Editor is displayed by right-clicking the ejb-jar.xml file and selecting the Edit EJB Module menu option. In the EJB Module Editor, access the Security Role section to create security roles and associate them with method permissions. The slides that follow show how to use the EJB Module Editor.

Oracle 10g: Build J2EE Applications 20-24

Creating Web Application Security Roles


1. Right-click web.xml, select Properties. 2. In the Security Roles section, click Add.

Copyright 2005, Oracle. All rights reserved.

Creating Web Application Security Roles Users and roles (groups) are stored in the jazn-data.xml file, if the JAAS security has been configured to use the OC4J jazn-data.xml file. To declaratively create security for your Web application, you first define one or more roles to be available to the application. The security role names can be: A role name defined in jazn-data.xml Any logical role name of your choice If you define a logical name, you must map it to actual users or roles found in the jazndata.xml file. The mapping is done by using a <security-role-mapping> element in the OC4J deployment descriptor (orion-web.xml). The slide shows how to create a logical role called hr_managers. The dotted arrow indicates that the role will be added to the list of roles available for authentication and authorization rules in this Web application.

Oracle 10g: Build J2EE Applications 20-25

Web Application Login Authentication


Typically done using Oracle HTTP Server using either Basic, Digest, Login Form, Single-Sign On, and so on.

Copyright 2005, Oracle. All rights reserved.

Web Application Login Authentication The Oracle Application Server 10g HTTP Server is a Web server that is typically used to manage authentication. The server provides you with a choice of techniques for authenticating users, including the following: Basic authentication, where the browser prompts for a username and a password. This is not secure and is often combined with Secure Socket Layer (SSL). Digest authentication, where the browser prompts for a username and password, which is more strongly encrypted than basic authentication. This lacks browser support. Form-based authentication, requiring an application to generate a HTML form to submit the username and the password. A J2EE container can authenticate the username and password that is submitted by using an HTML form if the form action attribute is set to the string j_security_check, and the username and password fields are named j_username and j_password, respectively. Note: Oracle Application Server 10g Single Sign-On can be enabled to provide a login form and do the authentication by using an LDAP-based service such as OID. Client certificate authentication, requiring that the browser use HTTPS and have a personal certificate installed Note: The slide shows how to enable basic authentication for the current Web application by using the OC4J container.
Oracle 10g: Build J2EE Applications 20-26

Web Application Authorization


Define a Web resource (URLs and HTTP methods). Grant security roles access to the Web resource.

Copyright 2005, Oracle. All rights reserved.

Web Application Authorization After the user is authenticated, you apply authorization by granting permissions to a user or role. You need to create or modify the <security-constraint> element in the web.xml file to declaratively implement Web application authorization in a J2EE security environment. The <security-constraint> element contains: A Web resource definition in a <web-resource-collection> element An authorization part in the <auth-constraint> element allowing the security role defined for the application to use the Web resource A Web resource is given a user-defined name, contains a collection of one or more URL patterns, and is optionally combined with HTTP methods. This gives a single name for a collection of Web pages and types of HTTP requests that can be made for those pages. The authorization constraint restricts access to a set of security roles that are assigned to the Web resource. The security roles must be defined or mapped to an actual role using the deployment descriptors. The slide shows how to create a Web resource called GetEmployee, with a single URL pattern /GetEmployees.jsp, related to the application root context. The authorization for the GetEmployee Web resource allows all users who have the managers or staff role access to the Web page. By default, all users have access to a Web resource.
Oracle 10g: Build J2EE Applications 20-27

Creating EJB Security Roles

1. Select the Security Roles section. 2. Click Add to create and enter a new logical role name and description in the Create Security Role dialog window.

Copyright 2005, Oracle. All rights reserved.

Creating EJB Security Roles Create users and groups in the jazn-data.xml file. Then, define the logical security roles in the ejb-jar.xml file. This later step can be achieved by using the JDeveloper wizards, as follows: 1. Select the Security Roles section. 2. Click Add to create a new security role (you can delete existing logical security roles by using the Delete button). Enter a new role name and description in the Create Security Role window. In the example, a role hr_managers is created. The information specified here is included in the deployment descriptor of the EJB.

Oracle 10g: Build J2EE Applications 20-28

Setting Method Permissions


In the Method Permissions section, select the roles and the methods that are accessible for those roles.

Copyright 2005, Oracle. All rights reserved.

Setting Method Permissions With this step, you can set different access permissions for different roles on the methods of the bean. All the information specified here is included in the deployment descriptor of the EJB. Select the Method Permissions section. Click Add to add method permissions. (You can click Remove to delete selected permissions.) The existing roles are listed in the Available Security Role Names section. Shuttle the role to the Chosen Security Role Names section to specify method permissions for the role. Click Add Method to create method permissions. Select one or more methods in the list to grant permissions on them to the selected roles. Permissions to all methods is indicated by *. The slide shows the role, hr_managers, being granted access to the incrementSalary(int x,int y) method of the HrApp bean. Deploy the bean with new settings. Any role other than the one specified in the deployment profile will not be able to access the bean methods. If a role is given permission to access only specific bean methods, then the client accessing the bean in that role will have access permissions only to those methods of the bean.

Oracle 10g: Build J2EE Applications 20-29

Method Access in EJB Deployment Descriptors


The example shows the hr_managers role granted access to the incrementSalary() method. Explicit settings have precedence over default method access in the OC4J deployment descriptor.

Copyright 2005, Oracle. All rights reserved.

Method Access Settings in the EJB Deployment Descriptor The slide shows an example of an EJB deployment descriptor (ejb-jar.xml) as created in the JDeveloper, allowing users with the hr_manager role access permissions to the incrementSalary() method of the bean. Depending on the settings in the <default-method-access> element in this descriptor (not shown in the slide), the users with the hr_manager role may or may not be allowed access to other methods in the HrApp bean. If a user calling the incrementSalary() method is not assigned to the hr_managers role, then that user is denied access to the method. Default method access is specified in the OC4J-specific deployment descriptor (orionejb-jar.xml) for the EJB. By default, JDeveloper generates the following default method access setting for EJBs, allowing all authenticated users access to the bean methods:
<default-method-access> <security-role-mapping impliesAll="true" name="&lt;default-ejb-caller-role>"/> </default-method-access>

Note: Explicit method access settings in the J2EE deployment descriptor (ejb-jar.xml) have precedence over the specified default method access settings.

Oracle 10g: Build J2EE Applications 20-30

Creating a Mapping for the Logical Roles


In JDeveloper, edit the orion-ejb-jar.xml file. 1. Right-click the file and select Properties. 2. Select Security Role Mapping, and then click Add.

3. Enter a logical role name (e.g., hr_managers).

Copyright 2005, Oracle. All rights reserved.

Mapping the Logical Role to a JAZN Identity For the security settings to be effective, you must map the logical role that has been assigned method permissions to the identities of a real user or group. The example in the slide modifies the OC4J EJB deployment descriptor to map the logical role hr_managers from the HrApp session bean to a real identity (a group, a user, or a combination of each) existing in the XML JAZN jazn-data.xml file. The slide shows the creation of the role name to be mapped. The next slide completes the mapping by assigning the managers group in the jazn-data.xml file to the logical role.

Oracle 10g: Build J2EE Applications 20-31

Mapping JAZN Identities to a Logical Role

Copyright 2005, Oracle. All rights reserved.

Mapping JAZN Identities to a Logical Role in JDeveloper The slide shows the screenshots indicating the key steps required to map the logical role hr_managers to the managers group, which is defined in the jazn-data.xml file. The steps are: 1. Right-click orion-ejb-jar.xml to open the OCJ4 EJB Deployment Descriptor window, and then select the Settings option. 2. Select the Security Role Mapping entry. 3. Select the hr_managers logical role (added as shown in the previous slide). 4. Click the Details button to display the Details for hr_managers window. 5. Click the Groups tab, and then click the Add button to add the managers group. (You can also add users by using the Users tab.) 6. Click OK to close the Add Group window. 7. Click OK to close the Details for hr_managers window. 8. Click OK to close the OC4J EJB Deployment Descriptor window. View the orion-ejb-jar.xml file to check the results of this mapping procedure.

Oracle 10g: Build J2EE Applications 20-32

Mapping JAZN Identities to a Logical Role

Copyright 2005, Oracle. All rights reserved.

Mapping JAZN Identities to a Logical Role in JDeveloper (continued) The slide shows the screenshots indicating the key steps required to map the logical role hr_managers to the managers group, which is defined in the jazn-data.xml file. The steps are: 1. Right-click orion-ejb-jar.xml to open the OCJ4 EJB Deployment Descriptor window, and then select the Properties option. 2. Select the Security Role Mapping entry. 3. Select the hr_managers logical role (added as shown in the previous slide). 4. Click the Groups tab, and then click the Add button to add the managers group. (You can also add users by using the Users tab.) 5. Click OK to close the Group window. 6. Click OK to close the OC4J EJB Deployment Descriptor window. View the orion-ejb-jar.xml file to check the results of this mapping procedure.

Oracle 10g: Build J2EE Applications 20-33

Mapping Results in orion-ejb-jar.xml

The OC4J XML Deployment Descriptor holds the details for mapping the logical role to the allowed identities (groups or users). For example:

Copyright 2005, Oracle. All rights reserved.

Mapping Results in orion-ejb-jar.xml The slide shows the results after the logical role hr_managers is assigned to the managers group. The <security-role-mapping> element is added with the name attribute set to the logical role hr_managers. One or more groups or user elements can be nested in the <security-role-mapping> element. The slide shows an entry for the managers group.

Oracle 10g: Build J2EE Applications 20-34

Accessing the EJB with New Permissions


Any client with a role other than those specified in the deployment descriptor receives the exception
com.evermind.server.rmi.OrionRemoteException.

Clients without read/write access to the namespace receive the exception javax.naming.NoPermission.

Copyright 2005, Oracle. All rights reserved.

Accessing the EJB with New Permissions A client application invoking EJB methods as a user without the role specified in the EJB deployment descriptor receives the exception com.evermind.server.rmi.OrionRemoteException. Clients that do not have read/write access granted to the JNDI namespace receive the javax.naming.NoPermission exception when attempting to look up the JNDI name of the published EJB. Read/write access to the JNDI namespace is specified in the <namespace-access> element of the OC4J default application.xml file, or the applications own OC4J-specific application.xml file.

Oracle 10g: Build J2EE Applications 20-35

Summary
In this lesson, you should have learned how to: Use the J2EE security architecture to remove from the developer the burden of implementing security Define Web applications and EJB security mechanisms such as security roles Define users, groups, and logical roles; map the logical and concrete roles for client authorization Access security information of the caller by using methods in the javax.ejb.EJBContext interface Authenticate EJB client applications by using the jndi.properties file and InitialContext

Copyright 2005, Oracle. All rights reserved.

Oracle 10g: Build J2EE Applications 20-36

Practice 20-1: Overview


This practice covers the following topics: Using the Web Application Deployment Descriptor to create logical security roles for a Web application Enabling basic authentication in an OC4J container Programmatically determining the user credentials and using it to control access to information Using EJB security to control access to methods in a bean

Copyright 2005, Oracle. All rights reserved.

Practice 20-1: Overview In this practice, you edit the EJB module to change the security settings. You give one user account access to the bean, and you then try to access it from another account to see the effect of the security settings.

Oracle 10g: Build J2EE Applications 20-37

Practice 20-1 In this practice, you are provided with most of the application code. The goal of this practice is to use J2EE declarative security mechanisms to protect access to different parts of the application. You use programmatic techniques to limit the information about an employees salary displayed to the application user (depending on the role of the user). Note: The application in this practice originates from the practice in lesson 17. Understanding the Application Open the practice20.jws workspace in the practice20 directory. There are two projects: The secure project, containing the files you will modify The securesoln project, containing the solutions for this practice Expand the secure project, and take approximately two minutes to examine the content of the following files used to configure the application security credentials: The orion-application.xml file is an OC4J applicationspecific deployment descriptor that identifies the location of the application-specific user and group data in the jazn-data.xml file. It also grants read access to the namespace to the staff role. The jazn-data.xml file contains all the users and roles for this application. This file was created using the JAZN Admintool provided with OC4J, where each username is derived from the EMAIL column of the EMPLOYEES table, and their passwords are all set to oracle. This file defines two roles: - The managers role, which is granted to only those employees in the database who have the following job IDs: AD_PRES, AD_VP, HR_REP, FI_MAN - The staff role, which is granted to all other employees. The managers role has been added as a member of the staff role, because all managers are also staff. The application provides a default index.html page that is not protected, allowing users to access a common welcome page. The only hypertext link on the index page leads to the GetEmployee.jsp page, which must be password protected. The user should log in using a valid name and the password oracle. The GetEmployee.jsp uses an entity bean to retrieve information about that employee, and presents a page that allows users to add new employees or to query employees by department. When employees are queried, the user is able to update or delete the employee record. Your task is to declaratively allow only managers to create and delete employees and update employee salaries. This is achieved through a combination of using Web and EJB authorization techniques covered in this lesson. Practice Steps 1. Deploy the application to observe the default behavior. a. Compile the secure project, and then right-click EmployeesWeb.deploy and deploy the application to your OracleAS10g connection. EmployeesWeb.deploy has a profile dependency on EmployeesEJB.deploy to ensure that the EJB is deployed as part of the enterprise application.
Oracle 10g: Build J2EE Applications 20-38

Practice 20-1 (continued) b. Enter the following URL: http://localhost/secure. Note: You will find that the application has no login mechanism, and defaults to a user called JCHEN, who can perform all tasks. 2. Create Web application security roles by using the actual role names defined in the jazn-data.xml file. a. In the secure project, right-click web.xml and select the Properties menu option to display the Web Application Deployment Descriptor editor. b. Click the Security Roles section, and then click the Add button to create security roles for managers and staff. c. Select the Preview XML section to examine the <security-role> elements added to the web.xml file. Note: Do not close the Web Application Deployment Descriptor editor window. 3. Enable basic authentication to be used by the OC4J container. a. Click Login Configuration and click the HTTP Basic Authentication option button, and enter Employee Application in the Realm field. b. Select the Preview XML section to examine the <login-config> element added to the web.xml file. Note: Do not close the Web Application Deployment Descriptor editor window. 4. Create two security constraints for the application by defining two Web resources and their associated URL patterns and appropriate role authorizations. a. Select the Security Constraints section and click the New button. Click the Add button to create a constraint with the Web resource name GetEmployee. b. Select the GetEmployee Web resource name that you created in the previous step, and in the URL Patterns tabbed page add the following URL: /GetEmployee.jsp. c. Click the Authorization tab and select the check boxes next to the managers and the staff roles. The managers role must be selected, otherwise, the J2EE container does not recognize a user with the managers role, but only their staff role. d. Select the Security Constraints section and click the New button. Click the Add button to create a second security constraint with the Web resource name MaintainEmployee. e. Select the MaintainEmployee Web resource name, and add the following URL patterns: /Add* and /Delete*. In the Authorization tabbed page for this second constraint, select only the check box next to the managers role. f. Select the Preview XML section to examine the two <securityconstraint> elements added to the web.xml file. g. Click the OK button to close the Web Application Deployment Descriptor editor window. 5. Redeploy the application by using the EmployeesWeb.deploy file to your OracleAS10g application server connection. Before you run the application, close all Web browser windows. Then start the Web browser and enter the following URL: http://localhost/secure.
Oracle 10g: Build J2EE Applications 20-39

Practice 20-1 (continued) 6. Click the Get Employees hypertext link to start the application. You should be prompted for a username and password in a dialog box, which has the Realm name of Employee Application. Test your application behavior with two different usernames. Use one user as a staff member only, and the other as a manager. Hint: The following users are staff members only: jchen, ngreenbe, pfay, and jwhalen. The following users are managers: ldehaan, sking, nkochhar, and smavris. All users have the password oracle. Alternatively, check the jazndata.xml file in your project for other names with the staff and managers role. 7. At this stage, all users are able to update other employees salaries. You now modify the EJB to allow only those users with the managers role to update an employees salary. a. In the secure project, right-click ejb-jar.xml and select Properties. b. In the EJB Module Editor, select the Security Roles node and click the Add button to create the managers security role entry. c. Select the Preview XML section to observe the <security-role> element added in the <assembly-descriptor> element. d. Click Method Permissions and click the Add button to create a method permission. e. In the Create Method Permission window, shuttle the managers role to the Chosen Security Role Names area, and select the void setSalary(Long newSalary) entry from the list in the Methods area. Then click the OK button. f. Select Preview XML and observe the <method-permission> element added inside the <assembly-descriptor> element of the bean. g. Click the OK button to close the EJB Module Editor and apply the changes you have made. 8. Redeploy the application with EmployeesWeb.deploy to your OracleAS10g application server connection. Close all your Web browser windows. Then start the Web browser and enter the following URL: http://localhost/secure and test the modification of an employees salary as a user using the managers role and as a user with the staff role. Hint: Close the browser between login sessions.

Oracle 10g: Build J2EE Applications 20-40

Practice 20-1 (continued) Optionally, if you have time, then you can perform the following: 9. Programmatically access and display authentication information for the users after they log in. a. Open the GetEmployee.jsp file in the Code Editor, and locate the following HTML tags:
<hr> <h3>Security Information</h3> <!-- Enter code here for security information --> <hr>

Replace the HTML comment line <! Enter code here --> with output that resembles the following four lines of information, each with a JSP expression after the word shown:
<b>Principal:</b> <%= %><br> <b>Staff:</b> <%= %><br> <b>Manager:</b> <%= %><br> <b>User :</b> <%= %><br>

b. In the JSP expression for Principal, display the string information about the java.security.Principal object. Hint: Use request.getUserPrincipal(). c. In the JSP expression for Staff, display true if the user making the request is a member of the staff role; otherwise display false. Hint: Use request.isUserInRole(...). d. In the JSP expression for Manager, display true if the user making the request is a member of the managers role; otherwise display false. Hint: Use request.isUserInRole(...). e. In the JSP expression for the User information, display the remote username. Hint: Use request.getRemoteUser(). f. Compile the GetEmployee.jsp file to eliminate syntax errors. 10. Programmatically prevent the current user from seeing another employees salary when obtaining the result list after finding employees by department ID. a. Edit GetEmployeeByDept.jsp in the Code Editor. b. Search for the following JSP code: <td><%= emp.getSalary() %></td> in the file and modify this line to display the salary as a string if the current user has the managers role. Otherwise, display the string n/a (not available). c. Compile the GetEmployeeByDept.jsp file to eliminate syntax errors. 11. Finally, deploy the EmployeesWeb.deploy application profile to the OracleAS10g connection. Test the application changes starting with the following URL: http://localhost/secure. Hint: Close the browser windows between the staff and managers user login sessions.

Oracle 10g: Build J2EE Applications 20-41

Oracle Application Server 10g Transaction Support

Copyright 2005, Oracle. All rights reserved.

Objectives
After completing this lesson, you should be able to do the following: Identify the use of bean-managed transactions (BMT) Identify the use of container-managed transactions (CMT) Describe how Oracle Application Server 10g Containers for J2EE (OC4J) supports one-phase and two-phase transaction protocols

Copyright 2005, Oracle. All rights reserved.

Objectives Java 2, Enterprise Edition (J2EE) containers provide a transaction service. Enterprise JavaBeans use Java Transaction API (JTA) 1.0.1 for managing transactions. This lesson discusses the method for using JTA in OC4J.

Oracle 10g: Build J2EE Applications 21-2

What Is a Transaction?
A transaction: Is a single logical unit of work or a set of tasks that are executed together May access one or more shared resources, such as databases Must be atomic, consistent, isolated, and durable (ACID)

Copyright 2005, Oracle. All rights reserved.

Overview Transactions manage changes to multiple databases in a single application as a unit of work. A transaction must be: Atomic: A transaction must execute completely or not execute at all. For example, in an account transfer transaction, both debit and credit must be successful as a unit, or both must fail. Consistent: This refers to the integrity of the underlying database. In an account transfer example, the amount of debit to one account must equal the credit to the other account. Isolated: The steps during a transaction cannot be affected by or be visible to any other part of the system until the transaction is complete. Durable: All data changes that are made during a transaction must be written to some physical storage before the transaction is successfully completed, so that even if the system crashes, the changes are not lost.

Oracle 10g: Build J2EE Applications 21-3

Enterprise JavaBeans (EJB) Support for Transactions


The EJB architecture supports declarative and programmatic transactions. The bean provider is not exposed to the complexity of distributed transactions. The EJB container provides a transaction infrastructure. EJBs do not support a nested transaction model.

Copyright 2005, Oracle. All rights reserved.

Enterprise JavaBeans (EJB) Support for Transactions The EJB architecture supports declarative and programmatic transactions. In CMT, you declare the transaction attributes in the deployment descriptor. A container uses these values for maintaining transactions in the beans. In BMT, you code the logic in the bean class to manage the transactions. An Enterprise JavaBean is required by the specification to support flat transactions but is not required to support nested transactions. This means that the container and the server must provide a transaction service to the EJB components and must also provide some standard interfaces into this service. You see in the next few slides the mandatory interfaces that must be supported by the server provider, so that the bean developer does not have to worry about the low-level details of the transaction infrastructure.

Oracle 10g: Build J2EE Applications 21-4

EJB Transaction Model


Demarcating a transaction determines:
Who begins and ends a transaction When each of these steps occur

A bean-managed (explicit) transaction:


Is demarcated by the bean Is specified programmatically in the bean through JTA interface or Java Database Connectivity (JDBC) interface

A container-managed (declarative) transaction:


Is demarcated by the container Is specified declaratively (implicit) through the XML deployment descriptor
Copyright 2005, Oracle. All rights reserved.

EJB Transaction Model Demarcating transactions refers to defining the transaction boundaries, that is, who starts and stops the transaction, and when each occurs. A transaction may involve more than one source and destination, and may span across multiple client and server objects. EJB transactions can be demarcated as BMT or CMT. The bean provider uses the EJB deployment descriptor to specify a value of a Bean or Container in the <transaction-type> element to define the type of transaction demarcation implemented. In the BMT model, the EJB client or the bean programmatically demarcates the transaction by executing the appropriate begin or commit/rollback methods by using Oracles implementation of the JTA specified by Sun Microsystems. Oracles JTA implementation supports JDBC, HTTP, and Internet Inter-ORB Protocol (IIOP)-based clients. The CMT model allows for implicit or declarative management of transactional behavior through the use of transaction attributes specified in the EJB deployment descriptor. The container begins and ends the transactions as necessary. The CMT transactional behavior of the bean can be changed at application assembly or deployment time, without changing business logic and, thus, it reduces code complexity.

Oracle 10g: Build J2EE Applications 21-5

Demarcating Transactions
Container-managed transactional demarcation:
The <transaction-type> element set to container in the deployment descriptor No transactional management code in the bean Transaction management depends on value of the <trans-attribute> element Available to entity, session, and message-driven beans (MDBs)

Bean-managed transactional demarcation:


The <transaction-type> element set to bean in the deployment descriptor Bean implementation must demarcate the begin, commit, or rollback for the transaction Available to session bean and MDBs, but not entity beans
Copyright 2005, Oracle. All rights reserved.

Single Phase Commit: Demarcating Transactions Depending on who demarcates the transaction, the bean or the container creates a new transaction context, starts the transaction, calls the transactional methods on the server objects in the current transaction context, and finally commits or rolls back the transaction. Bean-managed transactional demarcation can also be classified as client-side or server-side, depending on the object that demarcates the transaction. Client-side transaction demarcation is not required by the J2EE specification, and is not recommended for performance and latency reasons. Currently, OC4J does not support remote client-side transaction demarcation. Propagation of the transaction context cannot cross Java virtual machines (JVMs). Thus, neither a remote client nor a remote EJB can initiate or join the transaction. Container-managed demarcations enable you to write EJBs that can be used in different types of applications having different transactional requirements. They also ease the burden on the bean developer by removing the responsibility of keeping track of transactions. Note: The <transaction-type> element appears in only the session bean deployment descriptors. For entity beans, only CMT demarcation is possible, and this tag does not exist.

Oracle 10g: Build J2EE Applications 21-6

Container-Managed Transactions
<session> <ejb-name>hrApp</ejb-name> <home>demos.hrAppHome</home> ... <transaction-type>Container</transaction-type> <resource-ref> <res-ref-name>jdbc/hrCoreDS</res-ref-name> ... </session> <assembly-descriptor> ... <container-transaction> <description>no description</description> <method> <ejb-name>HrApp</ejb-name> <method-name>*</method-name> </method> <trans-attribute>RequiresNew</trans-attribute> </container-transaction> </assembly-descriptor> ...
Copyright 2005, Oracle. All rights reserved.

Container-Managed Transactions A container-managed transaction is also known as a declarative transaction because you specify the method of transactional management in the J2EE deployment descriptor. Specifying Container for the <transaction-type> in the XML deployment descriptor indicates that the container demarcates the transactions of the bean. That is, the container manages the transactions by providing begin, commit, and rollback statements. Before a bean can be deployed, its transaction attributes must be specified in the deployment descriptor. The transaction attributes can be specified by the bean provider, the application assembler, or the deployer.

Oracle 10g: Build J2EE Applications 21-7

CMT: Transaction Attributes


The following are the EJB-specified values of transaction attributes:
NotSupported Required Supports RequiresNew Mandatory Never

The transactional behavior of a bean can be changed with these attributes during deployment time.

Copyright 2005, Oracle. All rights reserved.

CMT: Transaction Attributes This slide shows the various values that you can specify for the transaction attributes of EJBs and their methods. These values affect how the container handles the transaction contexts and its propagation to other objects that it calls. The brief explanation of these attribute values and the effect of the attribute values on the invoked bean is as follows: NotSupported: The existing transaction context is not propagated to the bean. This attribute applies to stateless session bean (SLSB) and MDB. Required: The bean always runs in a transaction. This attribute applies to all types of beans. Supports: The bean runs in a transaction if the client has one. Otherwise, it runs without a transaction. This attribute applies to SLSB only. RequiresNew: The bean always needs a new transaction. This attribute applies to all types of beans except MDB. Mandatory: The bean must enter an already-started transaction. This attribute applies to all types of beans except MDB. Never: The bean is not allowed in a transaction. This attribute applies to SLSB only. Generally, you do not need to change the bean code for implementing CMT. However, for some of the transaction attributes above, you need to change the bean class implementation. For example, for using the RequiresNew transaction attribute, you must code the statements to begin and end a new transaction in the bean code.
Oracle 10g: Build J2EE Applications 21-8

CMT: Transaction Attributes


You specify the transaction attributes as follows: Specify for all the methods of a stateful session bean or an entity beans component interface and all direct and indirect superinterfaces of the component interface. Do not specify for: The methods of the javax.ejb.EJBObject
interface and the beans home interface in an stateful session bean The getEJBHome, getHandle, getPrimaryKey, isIdentical, getEJBMetaData, and getHomeHandle methods in an entity bean

Copyright 2005, Oracle. All rights reserved.

CMT: Transaction Attributes (continued) Transaction attributes should not be specified for the stateful session beans home interface.

Oracle 10g: Build J2EE Applications 21-9

Transaction Attribute: NotSupported

A client has: No transaction: The bean does not start one. A transaction: The bean suspends it. The transaction resumes when the client gains control.
Client (bean or servlet) No transactional context Client (bean or servlet) Transactional context Threads of execution Bean

No transactional context Suspended Resumed No transactional context Bean

Copyright 2005, Oracle. All rights reserved.

Transaction Attribute: NotSupported An unspecified context means that there is no context associated with the thread. For a bean method whose transaction attribute value is NotSupported, the container invokes the method in an unspecified context. Unspecified transaction context is used in the EJB specification to refer to the cases in which the EJB architecture does not fully define the transaction semantics of an enterprise bean method. This may give unpredictable results. In OC4J, unspecified transaction context is implemented to use no transaction context. It is recommended that the transaction attributes are set at least to Required or RequiresNew. If the client calls the bean with a transaction context, then the container suspends the association of the context from the current thread and resumes the association after the method is complete. If the business method invokes other enterprise beans, then the container passes no transaction context with the invocation.

Oracle 10g: Build J2EE Applications 21-10

Transaction Attribute: Required

A client has: No transaction: The bean starts a new one. A transaction: The bean uses it.

Client (bean or servlet) No transactional context Client (bean or servlet) Transactional context

Threads of execution

Bean

New transactional context Threads of execution Bean

Client transactional context

Copyright 2005, Oracle. All rights reserved.

Transaction Attribute: Required Bean methods with a transaction attribute value of Required must always be invoked in a transaction context. In such cases: If a client calls the method with a transaction context, then the container invokes the method in the clients transaction context. If the client call is not associated with a transaction context, then the container starts a new transaction before delegating the method to the bean, and tries to commit the transaction after the method returns and before returning to the client. If the bean method invokes other beans, then the container passes the context with the invocation.

Oracle 10g: Build J2EE Applications 21-11

Transaction Attribute: Supports

A client has: No transaction: The bean does not start new one. A transaction: The bean uses it.

Client (bean or servlet) No transactional context Client (bean or servlet) Transactional context

Threads of execution

Bean

No transactional context Threads of execution Bean

Client transactional context

Copyright 2005, Oracle. All rights reserved.

Transaction Attribute: Supports Bean methods with a transaction attribute value of Supports are invoked as follows: If the client calls with a transaction context, then the method is invoked in the clients transaction context, and the context is passed to any other bean method that the current method calls. If the client calls the method without a transaction context, then the method is called with an unspecified transaction context.

Oracle 10g: Build J2EE Applications 21-12

Transaction Attribute: RequiresNew

A client has: No transaction: The bean starts a new one. A transaction: It is suspended, the bean starts a new one and commits it, and then the old one resumes.
Client (bean or servlet) No transactional context Client (bean or servlet) Threads of execution Bean

Bean transactional context Suspended Resumed Bean transactional context Bean

Client Transactional context

Copyright 2005, Oracle. All rights reserved.

Transaction Attribute: RequiresNew Methods with the RequiresNew transaction context are always invoked with a new transaction context. If the client invokes the method without any transaction context, then the container starts a new transaction before delegating the call to the client, and tries to commit the transaction after the method is completed and before returning the call to the client. If the client calls with a transaction context, then the container suspends the clients transaction context and starts a new transaction. The suspended transaction is resumed after the business method and the new transaction are completed.

Oracle 10g: Build J2EE Applications 21-13

Transaction Attribute: Mandatory

A client has: No transaction: The bean requires one. It throws the


javax.transaction.TransactionRequiredException

exception. A transaction: The bean uses it.


Client (bean or servlet) No transactional context Client (bean or servlet) Transactional context Threads of execution Bean

EXCEPTION THROWN Threads of execution Bean

Client transactional context

Copyright 2005, Oracle. All rights reserved.

Transaction Attribute: Mandatory Methods with a transaction attribute of Mandatory should always be called with a transaction context. If the client calls the method without a transaction context, then the container throws a javax.transaction.TransactionRequiredException exception. If a client calls the method with a transaction context, then the container invokes the method in the clients transaction context.

Oracle 10g: Build J2EE Applications 21-14

Transaction Attribute: Never

A client has: No transaction: The container calls the method in an unspecified transaction context. A transaction: The container throws the java.rmi.RemoteException exception.

Client (bean or servlet) Transactional context

Threads of execution

Bean

java.rmi.RemoteException

Copyright 2005, Oracle. All rights reserved.

Transaction Attribute: Never Methods with a transaction attribute of Never should never be called with a transaction context. If the client calls the method with a transaction context, then the container throws a java.rmi.RemoteException exception. If the client calls the method without any transaction context, then the container calls the method in an unspecified transaction context.

Oracle 10g: Build J2EE Applications 21-15

CMT: The setRollbackOnly() Method


The setRollbackOnly() method can control the transaction state in the bean for a CMT. The setRollbackOnly() method marks the current transaction for rollback. If a transaction is marked for rollback, then the container rolls back the transaction before returning to the caller.

Copyright 2005, Oracle. All rights reserved.

Container-Managed Transactions In a CMT bean, the bean cannot, and must not, directly invoke the commit() or rollback() methods to end the transactions. Typically, an enterprise bean marks a transaction for rollback to protect data integrity before throwing an application exception, because an application exception does not automatically cause the container to roll back the transaction. A CMT bean can invoke the javax.ejb.EJBContext.setRollbackOnly() method to set the current transaction to rollback. The bean can use the javax.ejb.EJBContext.getRollbackOnly() method to detect if it has been marked for rollback.

Oracle 10g: Build J2EE Applications 21-16

JDeveloper: Setting Transaction Attributes


1. Open the EJB Module Editor for a selected EJB. 2. Select the Container Transactions section.

Copyright 2005, Oracle. All rights reserved.

Setting Transaction Attributes Using JDeveloper Open the EJB Module Editor of the CMT EJB to set the transaction attributes. In the Container Transactions section, you can view the existing transaction attributes. Click the Add button to create a new container transaction attribute, the Remove button to delete the selected container transactions attribute, or the Edit button to modify the selected container transaction attribute. By default, the transaction attribute is set to Required for all the methods of the bean.

Oracle 10g: Build J2EE Applications 21-17

JDeveloper: Setting Transaction Attributes


1. Select the Transaction Attribute type from the list. 2. Select methods from the list and associate them with the necessary transaction attributes.

Copyright 2005, Oracle. All rights reserved.

Setting Transaction Attributes Using JDeveloper (continued) You can set different transaction attributes for different methods: 1. Select the attribute from the list of attributes available. 2. Select methods from the list and associate them with the necessary transaction attributes. The information selected in this step is included in the EJBs deployment descriptor. The example in the slide sets the transaction attribute to NotSupported for all the methods of the Departments bean (indicated by *).

Oracle 10g: Build J2EE Applications 21-18

Java Transaction API (JTA)


JTA is used for managing transactions in J2EE. JTA transactions involve:
Enlisting resources: Single-phase commit or twophase commit Demarcating transactions: BMT or CMT

The JTA package provides an application interface (UserTransaction).

Copyright 2005, Oracle. All rights reserved.

Java Transaction API (JTA) JTA is used to explicitly demarcate transactions. A JTA transaction involves enlisting resources (databases). The complexity of your transaction is determined by how many resources your application enlists. Enlisting can be of two types: Single-phase commit (1pc), if only a single resource is enlisted in the transaction Two-phase commit (2pc), if more than one resource is enlisted. The two-phase commit is more difficult to configure. The two-phase commit mechanism allows transactions to be managed across different servers and databases. A JTA transaction also involves demarcating the transaction to be a BMT or a CMT. A transaction manager coordinates transactions by propagating the transaction context from one bean to another when invoked by a client, thus ensuring that all the beans invoked during the process are involved in a global transaction. The transaction manager can decide whether changes made by beans can be committed or rolled back, depending on the success or failure of the beans. JTA consists of a high-level transactional client interface and a low-level X/Open XA interface. Only the high-level application interface is discussed in this lesson. This interface is accessible to the beans and is the recommended transactional interface for client applications. The low-level XA interface is used by the EJB server and container to automatically coordinate transactions with resources (such as databases).
Oracle 10g: Build J2EE Applications 21-19

JTA: The UserTransaction Interface

Allows applications to explicitly manage transaction boundaries Encapsulates most of the functionality of a transaction manager
public public public public abstract abstract abstract abstract void begin (); void commit (); int getStatus (); void rollback ();

public interface javax.transaction.UserTransaction{

public abstract void setRollbackOnly (); public abstract void setTransactionTimeout( int secs); }

Copyright 2005, Oracle. All rights reserved.

JTA: The UserTransaction Interface The UserTransaction interface in the javax.transaction package is the key interface that enables the bean developer to manage the scope of transactions explicitly. begin(): Starts a global transaction and associates it with the current thread. The transaction-to-thread association is done by the transaction manager. commit(): Completes the transaction that is associated with the current thread. When this method completes, the thread is no longer associated with a transaction. getStatus(): Determines the transaction status. The return value can indicate a status of active, no transaction, marked rollback, committed, committing, rolledback, and unknown. rollback(): Rolls back the transaction associated with the current thread and reverts the updates. The thread is no longer associated with a transaction. setRollbackOnly(): Modifies the transaction such that the only outcome of the transaction is to roll back the transaction whether the updates succeeded or failed. Any BMT bean participating in the transaction can invoke this method. setTransactionTimeout(int seconds): Sets the timeout value, which indicates the time before which the transaction should complete. If not called, the transaction manager automatically sets a timeout value. This method must be invoked after the begin() method.
Oracle 10g: Build J2EE Applications 21-20

Bean-Managed Transactions Demarcation


Is indicated by the value Bean for the <transaction-type> element in the deployment descriptor Uses the UserTransaction interface of JTA to demarcate and manage the transactions programmatically By using a UserTransaction object, the bean: Initializes a transaction context on the client Invokes the begin(), commit(), or rollback() methods on the current transaction context to manage the transactions

Copyright 2005, Oracle. All rights reserved.

Bean-Managed Transactions (BMT) Demarcation An entry <transaction-type>Bean</transaction-type> in the deployment descriptor indicates that a session bean demarcates a transaction programmatically. That is, the bean manages the transactions in its code by providing begin, commit, and rollback statements. Then the begin(), commit(), and rollback() methods of the UserTransaction object are implemented in the bean. A reference to a javax.transaction.UserTransaction object can be obtained by using the lookup() method on the Java Naming and Directory Interface (JNDI) namespace using java:comp/UserTransaction. For more details about this namespace, refer to Oracle Application Server Containers for J2EE Enterprise JavaBeans Developers Guide.

Oracle 10g: Build J2EE Applications 21-21

BMT Demarcation: Process


1. Retrieve the UserTransaction object from the bean code by using a JNDI name. 2. Start a transaction by invoking the begin() method on the UserTransaction object. 3. Execute the business logic to be included in the transaction. 4. End the transaction by invoking the commit() or rollback() methods of the UserTransaction object.

Copyright 2005, Oracle. All rights reserved.

BMT Demarcation: Process The steps in the slide indicate the process of creating BMT demarcation for global transactions. For examples, refer to Oracle Application Server Containers for J2EE Enterprise JavaBeans Developers Guide.

Oracle 10g: Build J2EE Applications 21-22

Using UserTransaction Support in EJBs

Code example using BMT:


SessionContext ctx; public void setSessionContext(SessionContext ctx) { this.ctx = ctx; } public beanMethodA() { UserTransaction utx = ctx.getUserTransaction(); utx.begin(); do work utx.commit(); }

Copyright 2005, Oracle. All rights reserved.

UserTransaction Support in EJB Server The sample code shown in the slide is for a BMT bean. In the code sample, you see how the bean saves the reference to the context object in the setContext method and later uses it to get a reference to the userTransaction object.

Oracle 10g: Build J2EE Applications 21-23

Client-Demarcated Transactions Using UserTransaction


For Web applications (or EJB client) demarcation: Get an InitialContext object Look up java:comp/UserTransaction, and cast to javax.transaction.UserTransaction
Context ctx = new InitialContext (); // Retrieve the UserTransaction object. // Use its methods for transaction demarcation UserTransaction ut = (UserTransaction) ictx.lookup("java:comp/UserTransaction"); ut.begin(); //Start the transaction //Look up bean & access logic to perform sql // If everything went well, commit the transaction ut.commit();
Copyright 2005, Oracle. All rights reserved.

Web Application Client Transaction Demarcation An EJB client, such as a Web application, can initiate a transaction by looking up a javax.transaction.UserTransaction object from the container, as shown in the slide. Note: There is no env pathname in the lookup for java:comp/UserTransaction. The env namespace is generally used for references defined for the components enterprise naming context (ENC), which is usually defined in the deployment descriptors of the component.

Oracle 10g: Build J2EE Applications 21-24

BMT Demarcation: Restrictions


Session and message-driven EJBs can have beanmanaged transactions if their <transactiontype> element is set to Bean. An instance that starts a transaction must complete the transaction before it starts a new transaction. A stateful session bean can commit a transaction before a business method ends. A stateless session bean must commit the transaction before the business method returns.

Copyright 2005, Oracle. All rights reserved.

BMT Demarcation: Restrictions While an instance is in a transaction, it must not attempt to use the resource manager specific transaction demarcation. In EJB 1.1, the session beans with the <transaction-type> value of Bean can be BMT beans. MDBs can also have bean-managed transactions. Entity beans can never be BMT beans. Entity beans manage their own transaction attributes for their methods. A stateful session bean can commit a transaction before a business method ends. If a transaction has not been completed by the end of a business method, then the container retains the association between the transaction and instance across multiple client calls until the instance eventually completes the transaction. For sample code, see the previous slides.

Oracle 10g: Build J2EE Applications 21-25

Local and Global Transactions


A local transaction:
Is started and coordinated internally by the resource manager Has a single-phase commit

A global transaction:
Is controlled by a transaction manager external to the resources involved Has a two-phase commit

Copyright 2005, Oracle. All rights reserved.

Local and Global Transactions Local transactions are started and coordinated internally by the resource manager. Singlephase commit transactions are local transactions. Global transactions are controlled by a transaction manager that is external to the resources involved in the transaction. Two-phase commit transactions that involve more than one resource are global transactions.

Oracle 10g: Build J2EE Applications 21-26

Single-Phase Commit
Configure a data source:
Use the default emulated data source configuration. Modify the url attribute with the URL of your database.

Enlist a resource (database): Retrieve a connection to the data source in the bean after the transaction has begun.
Look up the data source in the JNDI namespace. Retrieve the connection by using the JTA/JDBC interface.

Copyright 2005, Oracle. All rights reserved.

Single-Phase Commit Configure the DataSource in data-sources.xml. For a single-phase commit JTA transaction, use the emulated default data source. Modify this data source url attribute with your database URL information. You retrieve the data source in your code by using a JNDI lookup with the JNDI name configured in the ejb-location attribute. Configure a DataSource for each database that is involved in the transaction. To enlist a single resource in single-phase commit, you must retrieve a connection to that database (the configured data source) before you execute any SQL statements against tables in the database. For these updates to be included in the JTA transaction, you must perform one of the following tasks in your bean implementation after the transaction has begun. After the transaction has begun (demarcated), look up the DataSource from the JNDI namespace. You can perform a JNDI lookup on a DataSource definition (as defined in data-sources.xml and ejb-jar.xml) or by using the environment (mapped in orion-ejb-jar.xml). These are discussed later in this lesson. Retrieve a connection from this DataSource object by using the getConnection() method.

Oracle 10g: Build J2EE Applications 21-27

Data Source Revisited


A data source is an instantiation of an object that implements the javax.sql.DataSource interface. You can use a data source to retrieve a connection to a database server. A data source offers a portable, vendorindependent method for creating JDBC connections. J2EE applications use JNDI to look up DataSource objects. Data sources are defined in data-sources.xml. Data sources can be emulated or nonemulated.
Copyright 2005, Oracle. All rights reserved.

What Is a Data Source? A data source is a Java object that has the properties and methods specified by the javax.sql.DataSource interface. Data sources offer a portable, vendor-independent method for creating JDBC connections. That is, a data source is a JDBC connection factory. J2EE applications use JNDI to look up DataSource objects. Each JDBC 2.0 driver provides its own implementation of a DataSource object, which can be bound into the JNDI namespace, and can be retrieved by using a JNDI look up request. Data sources are the recommended way for J2EE applications to retrieve connections to data servers. In the OC4J environment, data sources are defined in an XML file called datasources.xml. This configuration file comes with a default definition of a data source, which is sufficient for most of the transactions. Data sources can be emulated or nonemulated. The default data source is an emulated data source. That is, it is a wrapper around Oracle data source objects. You can use this data source for applications that access and update only a single data server. If you need to update more than one database, then you must use a nonemulated data source. This course discusses only single-phase commits. For information about coordinating twophase commits, refer to Oracle Application Server Containers for J2EE Services Guide.

Oracle 10g: Build J2EE Applications 21-28

Default data-sources.xml

<data-source class="com.evermind.sql.DriverManagerDataSource" name="OracleDS" location="jdbc/OracleCoreDS" xa-location="jdbc/xa/OracleXADS" ejb-location="jdbc/OracleDS" connectiondriver="oracle.jdbc.driver.OracleDriver" username="scott" password="tiger" url="jdbc:oracle:thin:@localhost:5521:oracle" inactivity-timeout="30" />

Copyright 2005, Oracle. All rights reserved.

Default data-sources.xml The code in the slide shows the default data source configuration. The class attribute defines the type of data source that you want to use. The location, xa-location, and ejb-location attributes are JNDI names that the data source is bound to in the JNDI namespace, where: - location identifies a basic data source with no added services. - xa-location identifies a data source with additional support for pooling and distributed transactions (XA). - ejb-location, used by EJBs, adds support for container-managed transactions in addition to services provided by the xa-location data source. Note: Always use ejb-location in JNDI lookup requests for a data source for access to all services. In addition, location and xa-location are now obsolete. The connection-driver attribute defines the type of connection you expect to be returned to you from the data source. The url, username, and password identify the database, its default username, and password. The data source in the slide example is extremely fast and efficient, because it does not require any JTA or XA operations. To use the OC4J default data source file, modify the data source name, username, password, and connection details with your database information.
Oracle 10g: Build J2EE Applications 21-29

Emulated Versus Nonemulated Data Sources


An emulated data source:
Is valid for a single database and local transactions Is a wrapper around the Oracle data source Is useful for Oracle and other databases Has the com.evermind.sql.DriverManagerDataSource class

A nonemulated data source:


Is pure Oracle data source implementation Is needed for two-phase commit and global transactions Provides XA and JTA global transaction support Has the com.evermind.sql.OrionCMTDataSource class
Copyright 2005, Oracle. All rights reserved.

Emulated Versus Nonemulated Data Sources Emulated data sources are wrappers around Oracle data sources. If you use these data sources, your connections become extremely fast, because they do not provide full XA or JTA global transactional support. It is recommended that you use emulated data sources for local transactions or when your application operates on a single database. Emulated data sources can be used for Oracle or non-Oracle databases. You can use the emulated data source to obtain connections to different databases by programmatically changing the values of url and connection-driver. To improve efficiency, the connections that are retrieved in a single transaction from the same JNDInamed data source using the same username and password cause the logical connections to share a single physical connection. Local transactions can be used only with a connection retrieved from an emulated data source. If you want to use global transactions, then you must use a nonemulated data source. Nonemulated data sources are pure Oracle data sources. Nonemulated data sources provide XA and JTA global transactional support. Thus, if you want to coordinate modifications in a global transaction, you should use this data source. You can use only these data sources for global two-phase commit transactions. Nonemulated data sources share physical connections for several logical connections to the same database for the same user.
Oracle 10g: Build J2EE Applications 21-30

Retrieve Connection to Data Source


<data-source class="com.evermind.sql.DriverManagerDataSource" name="hrCourseDS" location="jdbc/CoreDS" xa-location="jdbc/xa/hrCoreXADS" ejb-location="jdbc/hrCoreDS" ... /> data-sources.xml <resource-ref> <res-ref-name>jdbc/hrCoreDS</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> ejb-jar.xml </resource-ref> Context ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup("jdbc/hrCoreDS"); Connection conn = ds.getConnection(); Bean Code
Copyright 2005, Oracle. All rights reserved.

Retrieve Connection to Data Source After the data source is configured, you can retrieve the DataSource object through a JNDI lookup on the data source definition in the data-sources.xml file. The lookup is performed on the logical name of the default data source, which is an emulated data source defined in the ejb-location tag in the data-sources.xml file. You must always cast or narrow the object that JNDI returns to the DataSource, because the JNDI lookup() method returns a Java Object. Create a connection to the database represented by the DataSource object by using the getConnection() method of the DataSource object . The getConnection() method takes the schema username and password as defined in the data-sources.xml file. Alternatively, you can pass these values as parameters to an overloaded form of this method. After you have the connection, you can construct and execute JDBC statements against this database specified by the data source. In the slide, the J2EE deployment descriptor ejb-jar.xml contains the same logical name in the <res-ref-name> tag as defined in the <ejb-location> tag of the data-sources.xml file. If the two do not match, you must map the data source by using the Oracle-specific deployment descriptor orion-ejb-jar.xml. This process is explained in the next slide.
Oracle 10g: Build J2EE Applications 21-31

Retrieve Connection to Data Source


<data-source ... ejb-location="jdbc/hrCoreDS"... /> <resource-ref-mapping name="jdbc/HumanResourcesDS" location="jdbc/hrCoreDS"/>

data-sources.xml

orion-ejb-jar.xml

<resource-ref> <res-ref-name>jdbc/HumanResourceDS </res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> ejb-jar.xml Bean Code Context ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup("jdbc/HumanResourceDS");
Copyright 2005, Oracle. All rights reserved.

Retrieve Connection to Data Source (continued) In the slide, the logical name for the data source defined in ejb-jar.xml is different from the ejb-location defined in the data-sources.xml file. In this case, you need to map the JNDI name bound in the data-sources.xml file by using the <res-ref-mapping> element in orion-ejb-jar.xml. Then, retrieve the data source by using the environment JNDI lookup request. The format of the parameter for the JNDI lookup in this case is java:comp/env/jdbc/HumanResourceDS.

Oracle 10g: Build J2EE Applications 21-32

Global Transaction Resource Request Flow


When an EJB requests a JDBC connection or some other transactional resource, it gets associated with the global transaction. Consider an EJB with a container-managed transactions (CMT). Assume that:
The client invokes a bean with the transaction attribute Required The client is not associated with a global transaction

Copyright 2005, Oracle. All rights reserved.

Global Transaction Resource Request Flow This section provides a brief description of how an application server can handle a connection request from the application. The diagram in the next slide illustrates the use of JTA. The steps shown are for illustrative purposes and are not prescriptive. Note: The resource request flow is described in the JTA specifications.

Oracle 10g: Build J2EE Applications 21-33

Resource Request Flow

Client

3 4

Application (Bean) 8 9

OC4J

5 6 Resource adapter 7

2 Transaction manager (Oracle10g DB)

Copyright 2005, Oracle. All rights reserved.

Resource Request Flow Assuming that a client invokes an EJB with a Required transaction attribute and that the client is not associated with a global transaction, the EJB container starts a global transaction by invoking the TransactionManager.begin() method. The diagram in the slide shows the process of resource request flow, according to the JTA specifications. 1. The client invokes a method on the EJB, and the EJB container starts a global transaction. 2. The OC4J server begins the transaction with the transaction manager on an Oracle database. The command used is TransactionManager.begin(). 3. After the transaction starts, the container invokes the bean method. 4. The business logic of the bean makes a request for a connection-based resource by using the API provided by the resource adapter. The bean invokes JNDI to get the resource (for example, a JDBC data source) using the statement:
myDS = ic.lookup("jdbc/hrCoreDS");

Oracle 10g: Build J2EE Applications 21-34

Resource Request Flow (continued) 5. The container obtains a resource from the resource adapter via the method ResourceFactory.getTransactionalResource(). The resource adapter creates the TransactionalResource object and the associated XAResource and Connection objects. The container then invokes the getXAResource() method and obtains the connection as follows:
OracleXADataSource xaDs =new OracleXADataSource(); XAConnection axConn = xaDs.getXAConnection(); XAResource xaResource = xaconn.getXAResource();

6. The container enlists the resource to the transaction manager by using the statement Transaction.enlistResource(xaRes); 7. The transaction manager invokes the XAResource.start()method to associate the current transaction to the resource. 8. The container invokes the getConnection() method and returns the Connection object reference to the bean. 9. The bean performs operations on the connection by using the JDBC statements such as conn.createStatement();. After the operations are performed, the bean closes the connection by using the statement conn.close();. The resource adapter notifies the container that the connection is closed, and then the container enlists the resource. The transaction manager then invokes XAResource.end() to dissociate the transaction from the XAResource. The container asks the transaction manager to commit the transaction by using the statement TransactionManager.commit(). The transaction manager invokes XAResource.prepare() to inform the resource manager to prepare the transaction work for commit. The transaction manager then invokes the statement XAResource.commit() to commit the transaction. The transaction is now complete and the client has the control.

Oracle 10g: Build J2EE Applications 21-35

Enlisting Database Resources


The process of including SQL updates in a transaction is called enlisting. JTA automatically enlists databases opened with a DataSource object in a global UserTransaction object. Since JDK 1.2, a DataSource published into a JNDI namespace is the recommended way to make connections. If your global transaction involves more than one database, then you must configure a two-phase commit engine.

Copyright 2005, Oracle. All rights reserved.

Enlisting Database Resources Each resource (including databases) that you want managed in the global transaction must be enlisted: JDBC is used to connect to database resources. However, to include all the changes made to multiple databases in a transaction, you must use the JDBC connections in a JTA global transaction. The process of including database SQL updates in a transaction is referred to as enlisting a database resource. The Oracle10g JTA implementation enlists all the databases in which the JDBC connection is opened through the getConnection() method of a JTA DataSource published in the JNDI namespace. For this to happen, you must bind any DataSource object to be used in a JTA transaction with the dstype jta option of the bindds command. This binds an Oracle-specific JTA DataSource in the namespace. You cannot use any other type of DataSource for global transactions. You see an example of how to do that later in this lesson. You must retrieve the connection in the context of a global transaction; that is, retrieve the connection after the begin() method of the UserTransaction object. The JTA automatically enlists a database resource through a DataSource object. A client or server object opens a JDBC connection to a remote database through the DataSource object in the context of a global transaction. A client can open connections to remote databases through any client JDBC driver.
Oracle 10g: Build J2EE Applications 21-36

Enlisting Database Resources (continued) The enlistment of both the default and remote databases depends on an open global transaction context when the database connection is opened. That is, you must retrieve the database connection through the DataSource.getConnection() method after the UserTransaction.begin() method has been invoked. If your transaction involves more than one database, then you must specify an Oracle database as the two-phase commit engine. Two-phase commits are not discussed in this course.

Oracle 10g: Build J2EE Applications 21-37

Summary
In this lesson, you should have learned how to: Describe bean-managed and container-managed transactions Explain how OC4J supports one-phase and twophase transaction protocol logic

Copyright 2005, Oracle. All rights reserved.

Oracle 10g: Build J2EE Applications 21-38

Practice 21-1: Overview


This practice covers the following topics: Deploying a Web application and entity bean with CMT Altering the transaction attributes of the methods in the entity bean, and testing behavior Optionally, creating a session bean to mediate a transaction between the Web application and the entity bean methods

Copyright 2005, Oracle. All rights reserved.

Practice 21-1: Overview This practice covers the deployment of a Web application and a transaction-enabled entity bean. You then modify the settings of the transactional attributes of the entity bean methods and redeploy the application to test its behavior. Optionally, you create a stateless session bean with a single method to mediate the updating of an employee record between the Web application and the entity bean.

Oracle 10g: Build J2EE Applications 21-39

Practice 21-1 The goal of this practice is to get some experience working with container-managed transactional attributes. The application you are using here is identical to the one that you used in the previous lesson, without all the security constraints. You still require a valid login, but all users have access to all functions, because security is not the objective of this lab. 1. Open practice21.jws in the practice21 directory, and test the application with default transaction attributes: a. Deploy the application by using ManageTxApp.deploy file b. Start your browser and enter the URL http://localhost/managetx to run the application. Log in as any user, for example jchen, ngreenbe, or ldehaan, with the password oracle. c. Create a new employee in department 10. Use an employee ID of 900, enter your first name and last name in the first and last name fields, respectively, and enter a job type of IT_PROG. Enter values for all fields. d. Return to the Welcome employee page, and find all employees in department 10. e. Click the Update link and make a change to the first name and last name, and delete the last letter from the job type. This job type is invalid and generates an exception for the operation of changing the job type. But what happens to the changes to the first name and last name? 2. Edit the EJB and mark all methods with a transaction attribute of Required. a. Right-click ejb-jar.xml and select Properties. Click Container Transactions and click the Add button to add a transaction entry. In the Create Container Transaction Entry window select the Required transaction attribute. Click Add Method, select Employees in EJB Name and click * in the methods area. Click OK. Click OK again to close the window. b. Select Preview XML to observe the <assembly-descriptor> element inside <container-transaction>. Click OK to close the window. c. Redeploy the application. d. Run the application, search for employees in department 10. Attempt to update your record again. What happens this time? 3. Edit the EJB and mark all methods with a transaction attribute of NotSupported. a. Right-click ejb-jar.xml and select Properties. Select Container Transactions and click the Transaction Attribute field value in the existing entry. Pick the NotSupported entry from the drop-down list. b. Select Preview XML to observe the <assembly-descriptor> element inside <container-transaction>. Click OK to close the window. c. Redeploy the application. d. Run the application, search for employees in department 10. Attempt to update your record again. What happens this time? 4. Edit the EJB module and change the existing transaction attribute entry to mark only the setXXX() methods with an attribute value of Mandatory. Select Preview XML and note the changes. Click OK to close the window. Hint: Select all the setXXX() methods. a. Redeploy the application.
Oracle 10g: Build J2EE Applications 21-40

Practice 21-1 (continued) b. Run the application and search for employees in department 10. Attempt to update your record again. What is the result? Hint: Using Notepad look for an exception at the end of the file called <ORACLE_HOME>\opmn\logs\OC4J~home~default_island~1. 5. Modify UpdateEmployee.jsp to use client-demarcated transactions by starting a UserTransaction before calling the entity bean methods to update the employee fields. Hint: Import javax.naming.* and javax.transaction.* to look up a UserTransaction. a. Redeploy the application b. Run the application, search for employees in department 10. Attempt to update your record again. What happens this time? Optionally, if you have time, then you can perform the following: 6. Create a new stateful session EJB called MaintainEmployee, and set the transactions to be bean managed so that you can create a user transaction to demarcate the transaction boundaries. Make sure that you only use the local interfaces. a. Add a component method called updateEmployee() that receives the following arguments: java.lang.Long employee_id, java.lang.String first_name, java.lang.String last_name, java.lang.String email, java.lang.String job_id, java.lang.Long salary, java.lang.Long department_id, and returns a java.lang.String. b. In the MaintainEmployee bean, create a local EJB reference to the entity bean called Employees. c. Implement the updateEmployee() method to look up the UserTransaction interface, using java:comp/UserTransaction, and start the transaction. Note: Import javax.transaction.UserTransaction. d. Modify the updateEmployee() method to look up the entity bean by using the getEmployeesLocalHome() method that was added when you created the local EJB reference. Note: Import managetx.EmployeesLocal. e. Add code to updateEmployee(). Change the columns corresponding to the arguments by calling the appropriate set methods of the entity bean instance that you found. Enclose this code in a try/catch block and return the string Employee Updated if successful. Otherwise, return the exception message text. Hints: Copy or look at the code in the UpdateEmployee.jsp file. Make sure you use the user transaction object to commit the transaction on success or roll back when there is a failure. 7. Modify the web.xml file to add a local EJB reference with a JNDI name of ejb/local/MaintainEmployee for the MaintainEmployee session bean. Note: Do not overwrite the EJB local reference for Employees entity bean.

Oracle 10g: Build J2EE Applications 21-41

Practice 21-1 (continued) 8. Modify UpdateEmployee.jsp to create a MaintainEmployee EJB instance using the JNDI name created in the previous step. a. Replace the code that uses the entity bean to update the employee by calling the session beans updateEmployee() method. b. Redeploy the application c. Run the application, search for employees in department 10. Attempt to update your record again. What is the result?

Oracle 10g: Build J2EE Applications 21-42

_____________ A Practice Solutions _____________

Practice 2-1 Solution In this practice, you navigate to the Oracle Enterprise Manager console, modify the default data source, and restart the OC4J server. Additionally, this practice gives you the opportunity to view the files that OC4J uses to configure a J2EE application. You also deploy an existing application by using Oracle Enterprise Manager. 1. Navigate to the Oracle Enterprise Manager console. a. Open a browser and navigate to http://localhost:1810. b. Enter the username ias_admin and the password welcome1. c. Navigate to the home instance page by clicking the home link. 2. Create a data source reference. a. Click the Administration tab and click the Data Sources link. b. Click Create and enter these details: Name: hrDS Description: hr Data Source Class: com.evermind.sql.DriverManagerDataSource JDBC URL: The URL provided to you by your instructor JDBC Driver: oracle.jdbc.driver.OracleDriver In Datasource Username: Username: oraxx (as provided to you by your instructor) Use a cleartext password of oracle In JNDI Locations: Location: jdbc/hrCoreDS Transactional location: jdbc/xa/hrXADS EJB location: jdbc/hrDS Leave all other fields blank or set to the default. c. Click Create and restart OC4J when prompted. 3. Verify the change that you made to the data source. a. Navigate to the oraas10g directory and locate the j2ee\home\config directory. b. Open data-sources.xml in WordPad. Note that the data source that you added in step 2 is defined here. c. You may also want to view application.xml, server.xml, and other configuration files that are discussed in this lesson. 4. Deploy an existing J2EE application by using Oracle Enterprise Manager. The application you deploy in this step is actually the application that you will build in practice 17. a. Click the applications tab from the OC4J home page and click Deploy EAR File. b. Browse to the <JDEV_HOME>\jdev\mywork\practice02 directory and select application1.ear. c. Name the application practice02 and click Continue. d. Modify the URL Mapping as /practice02 and click Next. e. Enter jdbc/hrCoreDS for the JNDI location name and click Next. f. Because there is no user security defined for this application, click Next in the following page. g. Click Deploy to deploy the application. h. Click OK after the application has been deployed.
Oracle 10g: Build J2EE Applications A-2

Practice 2-1 Solution (continued) 5. Access the application. a. Enter the following URL in the browser: http://localhost/practice02/loginservlet b. Enter 100 in the Employee ID field and King in the Employee Name field and click Login. c. View the Employees in Kings department and click the Insert link. d. Enter the following information in the form. ID: 500 First Name: Your first name Last Name: Your last name Email: Your e-mail account Hire Date: A date in the format of dd-mon-yy Job ID: AD_VP e. Verify whether the employee was inserted by using SQL*Plus to query the EMPLOYEES table.

Oracle 10g: Build J2EE Applications A-3

Practice 3-1 Solution In this practice, you identify the MVC components for a sample application by using the design patterns and architectures that are discussed in this lesson. Using the sample flow diagram given in slide 12, decide how the processes are implemented in the J2EE components. Match each process to its possible implementation:

Log in Receive order status Place orders

a. EJB methods that query and update inventories in various warehouses

b. An EJB that maintains the orders in each customers shopping cart

c. A front controller servlet, accessing the database by using JDBC

Browse products

d. An EJB that delivers a message that there is a new order

Fill orders

e. A JSP that displays the available items for sale

Update inventories

f. A servlet or JSP that accesses the customers outstanding orders

Oracle 10g: Build J2EE Applications A-4

Practice 4-1 Solution The purpose of this practice is to create the login form for the J2EE application that you are developing. You create and run an HTML form and an HTTP servlet. Run JDeveloper by using the desktop shortcut. Open the practice04 workspace in the practice04 folder and navigate to the login project. 1. Modify an HTML form for logging in to an application. a. Expand the login project and the Web Content folder. Open the login.html file in the code editor by double-clicking the file. b. There are two text areas in this form (you can switch between the visual and code view using the Design and Source tabs) . The text areas have labels but no names. Complete the <input type="text" name=""> code to include a name for both the text areas. These are the values that you pass to the request object and, therefore, it is important to follow standard naming conventions so that you can refer to the value later. You can perform this step by using the code editor, or by selecting the text item box in the visual editor and modifying the name property in the property inspector.

<input type="text" name="custId"> <input type="text" name="custName">

c.

Modify the form so that the action tag points to firstservlet. You create the servlet in the next step.

<form name="form1" method="post" action="firstservlet">

d.

Optionally, modify the forms layout. Add a style sheet by selecting CSS from the component palette dropdown list and then dragging a style sheet to the .html file.

<link rel="stylesheet" href="css/oracle.css" media="screen"> e. Save the login.html file. 2. Create a new HTTP servlet. a. With the login project selected, Select File > New from the menu. Select the Web Tier > Servlets category and then the HTTP Servlet item and click OK. b. Click Next to dismiss the first page of the wizard. c. Ensure that the package name is login and name the class FirstServlet.

Oracle 10g: Build J2EE Applications A-5

Practice 4-1 Solution (continued) d. Because you are sending a POST action from the form, select the doPost() method in the Servlet Wizard, in addition to doGet(). This ensures that the doPost() skeleton code is generated. Click Next. e. Click Next to leave the servlet parameters empty for now. f. The last step in creating a servlet is the mapping details. Select the check box to specify a name for the servlet, and accept the default values. g. Click Finish. You have created FirstServlet.java, a servlet with skeleton code for the doGet() and doPost() methods. h. Open the web.xml file in the code editor. Note that login.FirstServlet is mapped to /firstservlet. 3. Modify the HTTP servlet to handle the login. a. Add code to the doPost() method to retrieve the Customer Name parameter from the request object. Remember that the value being passed is the parameter that you specified in step 1.b, not Customer Name. Remove the out.println statement containing "The servlet has received a POST"

String name = request.getParameter("custName");

b. Add code to the doPost() method to greet the customer by using his or her name in the greeting. If the customer does not enter a name, the name is an empty string. In this case, greet an anonymous user. Hint: Use the skeleton code that is provided as a template, to properly format your document by ensuring that the appropriate HTML tags are used.
out.println("<body>"); if (name.length() > 0) { out.println ("Hello " + name + ": Welcome to Order Entry!"); } else { out.println ("Hello... I see you do not want to reveal your name!"); } out.println ("</body></html>"); out.close();

c. Right-click FirstServlet.java and select Make to compile the class. 4. Run login.html to test the functionality. a. Right-click login.html and select Run. b. Enter any name (ignore the Customer Id field), and click Login. c. The name that you enter should be welcomed by the doPost() method of the servlet.
Oracle 10g: Build J2EE Applications A-6

Practice 4-2 Solution In this practice, you use the doGet() method to combine the login process completed in Practice 4-1 into a single servlet. The servlet creates the login form and runs initially, rather than login.html. 1. Create a servlet to handle the login process. a. In the login project, create a new servlet as in step 2 of practice 4-1. b. Select login as the package name and name the class LoginServlet. c. Select the doGet() and doPost() methods in the Servlet Wizard. This ensures that the skeleton codes of both the methods are generated as in Practice 4-1. d. Click Next to leave the servlet parameters empty. e. This servlet contains an HTML form that references the doPost() method. As before, the URL pattern for this servlet matches the virtual path in the action tag of the doGet() method. Create a mapping for this servlet as /loginservlet. f. Click Finish and you have created LoginServlet.java, with skeleton code for the doGet() and doPost() methods. 2. Modify the doPost() method. a. Copy the doPost() method from FirstServlet.java and paste it into the doPost() method of LoginServlet.java. This ensures that the login process remains the same, whereas the URL being called to log in changes.
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); PrintWriter out = response.getWriter(); String name = request.getParameter("custName"); out.println ("<html>"); out.println("<head><title>FirstServlet</title></head>"); out.println ("<body>"); if (name.length() > 0) { out.println ("Hello " + name + ": Welcome to Order Entry!"); } else { out.println ("Hello... I see you do not want to reveal your name!"); } out.println ("</body></html>"); out.close(); }

b. Right click inside the code editor and select Make to compile LoginServlet.java. 3. Modify the doGet() method to create the form that is used in login.html. a. Create a variable to store the servlets Uniform Resource Identifier (URI) from the request.getRequestURI() method.
Oracle 10g: Build J2EE Applications A-7

Practice 4-2 Solution (continued)


String servleturi = request.getRequestURI();

b. Copy the contents of login.html and paste into the doGet() method of LoginServlet.java, just below the line PrintWriter out=response.getWriter();. Remove the out.println statement containing "The servlet has received a GET" c. Modify the HTML code so that it is wrapped in out.println statements. This also involves eliminating quotes from the HTML and adding escape characters where necessary. Specify the variable you created in step 3a for the value of the action tag. For example, the first four lines of the statements should be: out.println("<html>"); out.println("<head><title>Login to Order Entry</title>"); out.println("<link rel=stylesheet href=\"css/oracle.css\" media=\"screen\"/></head>"); out.println("<body>" + "<form method=\"post\" " + "action=" + <yourservleturivariable> + ">" d. Continue to concatenate statements and eliminate extraneous quotes until the HTML is formatted properly in the servlet.

out.println("<html>"); out.println("<head><title>Login to Order Entry</title>"); out.println("<link rel=stylesheet href=\"/css/oracle.css\" media=\"screen\"/></head>"); out.println("<body>" + "<form method=\"post\" " + "action=" + servleturi + ">" + "<h1 align=\"center\">Welcome to the Order Entry Application </h1>" + "<div align=\"center\">" + "<p>&nbsp;</p><p>&nbsp;</p>" +"<table border=0><tr><td><h4>Customer Id:</h4></td>" + "<td><input type=\"text\" name=\"custId\"></td></tr>" + "<tr><td><h4>Customer Name:</h4></td>" + "<td><input type=\"text\" name=\"custName\"></td></tr>" + "</table><p>" + "<input type=\"submit\" name=\"Submit\" value=\"Login\">" + "<input type=\"reset\" name=\"Reset\" value=\"Reset\">" + "</p></div></form>"); out.println("</body></html>"); out.close(); }

4. Run LoginServlet.java to test the functionality: a. Right-click LoginServlet.java and select Run. b. Enter a name (ignore the Customer Id field), and click Login. c. The name that you enter should be welcomed by the doPost() method of the servlet.
Oracle 10g: Build J2EE Applications A-8

Practice 4-3 Solution In this practice, you deploy the application that you built in the previous practices. 1. First, create a connection to your Oracle Application Server 10g instance. a. Click the Connections tab in the Application Navigator. Right-click Application Server and select New Application Server Connection. b. Name the connection OracleAS10g and specify Oracle Application Server 10g as the connection type. Click Next. c. Provide welcome1 as the password for the ias_admin user and click Next. d. Accept the default host name and port and specify the ORACLE_HOME directory for the Oracle Application Server 10g install, E:\oraas10g, and click Next. e. Click Next and in the following page, click Test Connection. When the status message indicates success, click Finish. 2. Create a deployment profile for the application. a. Right-click the login project and select New. b. Select Deployment Profiles within the General category and create a WAR file deployment profile for this project. c. Name the deployment profile login and click OK. d. Specify the J2EE Web Context Root as /practice04, accept all other default settings, and click OK. 3. Deploy the application. a. Right-click the deployment profile and deploy to the OracleAS10g connection that you created in step 1. b. When you see the text Deployment Finished in the message window, the application is deployed. c. Access the application by using the following URL:http://localhost/practice04/loginservlet d. Navigate to E:\oraas10g \j2ee\home\config and view the contents of default-web-site.xml in WordPad. This is where the application that you deployed is specified.

Oracle 10g: Build J2EE Applications A-9

Practice 5-1 Solution The purpose of this practice is to create a servlet that interacts with a database by using JDBC. The customer number and name provided in LoginServlet.java is validated in the CUSTOMERS table of the database, and the customer is shown a list of his or her existing orders. In JDeveloper, open the practice05.jws workspace. 1. Create the connection to use as the data source for the servlet. a. Select File > New and select Connections from the General category. b. Select Database connection and click OK. c. Name the connection oe and specify an Oracle JDBC connection type. d. The username is orann (as indicated by your instructor) and the password is oracle. The password should be deployed at run time. e. Enter the host, port, and SID as indicated by your instructor. f. Test the connection and click Finish to close the wizard. g. You are now able to look up this data source reference by using its <ejb location> name, jdbc/oeDS. 2. Modify LoginServlet.java to include the new functionality. a. Double-click the verifylogin project and navigate to the Libraries tab to add the Oracle JDBC library to your project. b. Open LoginServlet.java in the verifylogin project. c. Import the javax.naming (for the resource lookup), javax.sql (for the DataSource class), java.sql (for the Connection class), and oracle.jdbc packages to the LoginServlet.
import import import import javax.naming.*; javax.sql.*; java.sql.*; oracle.jdbc.*;

d. Create instance variables for the Connection (as conn), the DataSource (as ds), and the PreparedStatement (as ps) objects.
private Connection conn; private DataSource ds; private PreparedStatement ps;

e. In a try/catch block of the init() method, use the lookup method of the Context class to retrieve the data source that you created in step 1.
try { Context ic = new InitialContext(); ds = (DataSource)ic.lookup("jdbc/oeDS"); }

Oracle 10g: Build J2EE Applications A-10

Practice 5-1 Solution (continued) f. Catch a NamingException if the name is not found.

catch (NamingException ne) { ne.printStackTrace(); }

g. In the try block, initialize the connection object. Catch a SQLException.


conn = ds.getConnection(); catch (NamingException ne) { ne.printStackTrace(); } catch (SQLException se) { se.printStackTrace(); }

h. Also in the try block, create a PreparedStatement object from the Connection object that is stored in the PreparedStatement object declared in step 2.d. The query string should select all columns from the ORDERS table for all orders with the CUSTOMER_ID equal to a bind variable parameter.
ps = conn.prepareStatement("SELECT * " + "FROM orders " + "WHERE customer_id = ?");

i. Create the destroy() method to close the connection and prepared statement objects that you created in a try/catch block. Catch a SQLException.
public void destroy() { super.destroy(); try { ps.close(); conn.close(); } catch (SQLException sqle) { sqle.printStackTrace(); } }

Oracle 10g: Build J2EE Applications A-11

Practice 5-1 Solution (continued) 3. Create the functionality to validate the provided name and ID. a. Create a new synchronized Boolean method in the servlet to verify the customer information. This method accepts the connection, the customer ID, and the customer name as arguments, and throws a SQLException.
public synchronized boolean verifyCustomer (Connection conn, String customer_id, String customer_name) throws SQLException {

b. Create a method variable to initialize the customer ID.


String custid = null;

c. Create an instance of the Statement object.


Statement stmt = conn.createStatement();

d. Create a variable to store the query for this method. The query should select the customer_id and cust_last_name from the CUSTOMERS table, where the customer_id and cust_last_name match those that are provided as arguments to the method.
String verifyquery = "select customer_id, cust_last_name from customers " + "where cust_last_name like '" + customer_name + "'" + " and customer_id like " + customer_id;

e. Use the executeQuery() method of the Statement object that you created in step d. Assign this value to a ResultSet variable.
ResultSet rs = stmt.executeQuery(verifyquery);

f. While iterating through the result set, retrieve the customer ID.
while (rs.next()) { custid = rs.getString(1); }

g. Close the result set and return true if the customer ID is not null or an empty string. Otherwise, return false.

Oracle 10g: Build J2EE Applications A-12

Practice 5-1 Solution (continued)


rs.close(); if (custid != null && custid.length() > 0) { return true; } else { return false; } }

4. Create the functionality to query the database for the customers existing orders. a. Create a new synchronized method to get the orders for a customer. This method accepts the Connection and customer ID as arguments, and throws a SQLException.
public synchronized String getOrders(Connection conn, String customer_id) throws SQLException {

b. Declare one method variable of type String. Initialize the variable to a string with a length of zero ("").
String htmlOutput = "";

c. Use the setString() method of the PreparedStatement object to pass the value of the method argument to the query statement created in step 2.h.
ps.setString(1,customer_id);

d. Execute the query from the PreparedStatement object, and store the results in a ResultSet object.
ResultSet rs = ps.executeQuery();

e. By using a while loop, loop through all records in the ResultSet object. As you iterate through each row, fetch the column values and save them into three string variables named orderId, orderSatus, and orderTotal.
while (rs.next()) { String orderId = rs.getString("ORDER_ID"); String orderStatus = rs.getString("ORDER_STATUS"); String orderTotal = rs.getString("ORDER_TOTAL");

Oracle 10g: Build J2EE Applications A-13

Practice 5-1 Solution (continued) f. In the while loop, add the following code, replacing yourStringVariableName with the name that you chose in step b: yourStringVariableName += "<tr><td>" + orderId + "</td><td>" + orderStatus + "</td><td>" + orderTotal + "</td></tr><p>"; Note that you are appending the variables onto the String object that you declared in the first step and formatting the data in a table.
htmlOutput += "<tr><td>" + orderId + "</td><td>" + orderStatus + "</td><td>" + orderTotal + "</td></tr>"; }

g. Close your ResultSet object outside the while loop.


rs.close();

h. Return yourStringVariableName. Keep in mind that this represents a string of HTML output including a list of all the orders placed by a given customer.
return htmlOutput; }

5. Modify the doPost() method to call the new methods: a. Create an instance variable to retrieve the customer ID from the request object.
String id = request.getParameter("custId");

b. Delete the if/else block for checking if a customer name was entered. c. If the return of the method you created in step 4 is true, then include the return value from the method that you created in step 5, formatted in an HTML table. Pass the Connection object and customer ID variable to this method. If the return value is false, then alert the customer that the login is invalid.
try { if (verifyCustomer(conn,id,name)) { out.println("<table border=1><tr><td>" + "Order Id" + "</td><td>" + "Order Status" + "</td><td>" + "Order Total" + "</td><td>" + getOrders(conn,id) + "</td></tr></table>"); } else { out.println("Invalid login. Please try again."); } } Oracle 10g: Build J2EE Applications A-14

Practice 5-1 Solution (continued) d. Catch a SQLException.


catch(SQLException sqle) { sqle.printStackTrace(); }

6. Compile to test and run the application from LoginServlet.java. Note that not all customers have current orders in the database. Valid customer IDs and names that have orders are listed below:

101 102 103 104 105 106 107 108 109 116 117 118 119 120 121 122 123

Welles Pacino Taylor Sutherland MacGraw Hannah Cruise Mason Cage Martin Edwards Mahoney Hasan Higgins Sen Daltrey Brown

Oracle 10g: Build J2EE Applications A-15

Practice 6-1 Solution The purpose of this practice is to use cookies within multiple servlet instances. You modify the LoginServlet.java file that you created in practice 5. This servlet uses a cookie to store the users name and retrieve that value when the user accesses the servlet. Open the practice06.jws workspace and navigate to the newlogin project. Open LoginServlet.java in the code editor. 1. Add code to the doPost() method of LoginServlet.java servlet to create a cookie: a. Create a new Cookie object named LoginCookie. The cookie value will be the variable that holds the custName value.
Cookie cookie = new Cookie ("LoginCookie", name);

b. Set the cookies maximum age to two minutes.


cookie.setMaxAge(120);

c. Add the cookie to the response object to send it to the browser.


response.addCookie(cookie);

2. Retrieve the cookie from the browser. Add the following code to the doGet() method of LoginServlet.java: a. Create a variable to store the value of the cookie.
String cookievalue = null;

b. Use the getCookies() method to fetch the array of Cookie objects. Then, check if the request returned any cookies.
Cookie[] cookies = request.getCookies(); if (cookies != null) {

c. If so, use iteration to loop through the array of cookies. For each iteration, test to see if the cookies name is LoginCookie. If so, retrieve the cookie value into the variable that you created in step 2.a. and break out of the loop.
for (int i=0; i<cookies.length; i++) { if (cookies[i].getName().equals("LoginCookie")) { cookievalue = cookies[i].getValue(); break; } } }

Oracle 10g: Build J2EE Applications A-16

Practice 6-1 Solution (continued) d. Test whether the cookie was found. If not, display the form that is already created in the doGet() method. If it is found, add code to welcome the user back to the Order Entry application by using the value of the cookie for personalization.
if (cookievalue ==null) { out.println("<html>"); out.println("<head><title>Login to Order Entry</title></head>"); out.println("<link rel=stylesheet href=\"css/oracle.css\" media=\"screen\"/>"); out.println("<body>" + "<form method=\"post\" " + "action=" + servleturi + ">" + "<h1 align=\"center\">Welcome to the Order Entry Application </h1>" + "<div align=\"center\">" + "<p>&nbsp;</p><p>&nbsp;</p>" + "<table border=0><tr><td><h4>Customer Id:</h4></td>" + "<td><input type=\"text\" name=\"custId\"></td></tr>" + "<tr><td><h4>Customer Name:</h4></td>" + "<td><input type=\"text\" name=\"custName\"></td></tr>" + "</table><p>" + "<input type=\"submit\" name=\"Submit\" value=\"Login\">" + "<input type=\"reset\" name=\"Reset\" value=\"Reset\">" + "</p></div></form>"); out.println("</body></html>"); } else { out.println ("Hello " + cookievalue + ": Welcome back to Order Entry!"); } out.close();

e. Compile LoginServlet.java. 3. Test and run the application. a. Run LoginServlet.java. You should see the form that was created in the previous practice. Enter a valid name and ID in the fields (refer to practice 5 for valid name and ID entries) and click Login. b. You should see the orders displayed for the customer as in the previous practice. However, the name is now stored as a cookie for two minutes. c. Run LoginServlet.java the second time to test whether the cookie is being correctly set. You should be welcomed back to the application. d. To ensure that your cookie is expiring correctly, wait for two minutes and then run LoginServlet.java. You should see the form as in step a.

Oracle 10g: Build J2EE Applications A-17

Practice 6-2 Solution The purpose of this practice is to redirect a user by sending a header to the response. Suppose that the contract between your company and customer number 104 is currently being reviewed, and as the developer you have been instructed to temporarily block this customer from entering the Order Entry application. You can do this by modifying the servlet code to check for this customer and redirect him or her to an appropriate error message. However, this would mean modifying the servlet itself. Therefore, to incorporate this business rule, use a servlet filter. 1. Select File > New > Web Tier > Servlets and create a new Servlet Filter in the newlogin project. Name the filter and the class LoginFilter, and ensure the package name is newlogin. Map this filter to every servlet in the URL pattern. 2. Use the Properties class of the java.util package to create an instance variable named blockUser. a. Create an instance variable of type java.util.Properties. Note that you will need to import this package.
private Properties blockUser = new Properties();

b.

Use blockUser.setProperty to define the business rule that you are creating: the name property with a value of Sutherland.

{ blockUser.setProperty("name", "Sutherland"); }

c.

Additionally, create an instance variable to store the value of javax.servlet.ServletContext. Note that you must import this package.

private ServletContext context;

3. Modify the init() method: a. Set the context for this method as filterConfig.getServletContext(); and write to the context log that the filter has been initialized. Use filterConfig.getFilterName() to retrieve the name of the filter.
context = filterConfig.getServletContext(); context.log("Filter " + filterConfig.getFilterName() + " initialized.");

4. Modify the doFilter() method to check for the supplied customer name. a. Loop through the enumeration returned from the keys() method of blockUser and look for the String value of this variable. Use the hasMoreElements() method of java.util.Enumeration to increment in the loop.
for (Enumeration en = blockUser.keys(); en.hasMoreElements();) { String name = (String)en.nextElement(); Oracle 10g: Build J2EE Applications A-18

Practice 6-2 Solution (continued) b. Retrieve the custName parameter from the request object, and set it to a temporary String variable.
String param = request.getParameter("custName");

c. Verify whether the value of the variable created in the previous step matches the value that is retrieved from the enumeration.
if ((param != null) && blockUser.get(name).equals(param)) {

d. If the values match, send an error message by using javax.servlet.http.HttpServletResponse to the browser, indicating that the service is unavailable. Additionally, include a message in the error to indicate that the value specified has been temporarily rejected. Send this error message text to the context log.
HttpServletResponse servletResponse = (HttpServletResponse) response; String msg = "Request for " + name + " " + param + " temporarily rejected."; servletResponse.sendError(servletResponse.SC_SERVICE_UNAVAILABLE, msg); context.log(msg); return; } }

e. Finally, pass the doFilter() method down the filter chain.


chain.doFilter(request, response);

5. Compile the filter and test by running LoginServlet, and by supplying a customer number of 104 and a name of "Sutherland". The filter should modify the response so that a service_unavailable error is sent in the response.

Oracle 10g: Build J2EE Applications A-19

Practice 7-1 Solution In this practice, you create a shopping cart application to track a customers orders in the Order Entry application. You create a link to the LoginServlet that displays the products. Each product can then be added to a shopping cart by passing in the productID and name of the selected product. You create a class to store the products that are selected for each session, and display them by using a servlet. Open the practice07.jws workspace and select orderproducts. 1. Create a servlet to display the products that are available for order: a. Create a new servlet named ProductsServlet in the orderproducts package. Generate a doGet() method for this servlet and use the default mappings. b. Import the javax.naming.*, javax.sql.*, java.sql.*, and oracle.jdbc.* packages. c. Create instance variables for the Connection (as conn) and DataSource (as ds).
private Connection conn; private DataSource ds;

d. Create a new method in ProductsServlet.java to retrieve the PRODUCT_ID, PRODUCT_NAME, and PRODUCT_DESCRIPTION from the PRODUCTS view, ordering by the CATEGORY_ID. You must use coding similar to that used in the init() and verifyCustomer() methods of LoginServlet.java.
public void init(ServletConfig config) throws ServletException { super.init(config); try { Context ic = new InitialContext(); ds = (DataSource)ic.lookup("jdbc/oeDS"); conn = ds.getConnection(); } catch (NamingException ne) { ne.printStackTrace(); } catch (SQLException se) { se.printStackTrace(); } } // public String getProducts() throws SQLException { String htmlOutput = ""; Statement stmt = conn.createStatement();

Oracle 10g: Build J2EE Applications A-20

Practice 7-1 Solution (continued)


String productquery = "SELECT PRODUCT_ID, PRODUCT_NAME, PRODUCT_DESCRIPTION " + "FROM PRODUCTS " + "ORDER BY CATEGORY_ID"; ResultSet rs = stmt.executeQuery(productquery);

e. Loop through the result set and retrieve the values of the columns into variables.
while (rs.next()) { String name = rs.getString("PRODUCT_NAME"); String desc = rs.getString("PRODUCT_DESCRIPTION"); String prodid = rs.getString("PRODUCT_ID");

f. Set the return value for this method by creating a table to store the variables that are returned in step 1d in a table format. Include an href link at the end of each row that points to showcartservlet, and allows the customer to add this product to his or her shopping cart. You create this servlet later in the practice. Close the result set object and return the variable name. Hint: Include two parameters in the url, using the variables you created in the previous step: <yourreturnvaluename> += "<tr><td>" + var1 + "</td><td>" + var2 + "</td><td>" + "<a href=\"showcartservlet" + "?param1=" + var1 + "&param2=" + var2 + "\"/> + Add to Shopping Cart" + "</a></td></tr><p>";
htmlOutput += "<tr><td>" + name + "</td><td>" + desc + "</td><td>" + "<a href=\"showcartservlet" + "?prodid=" + prodid + "&name=" + name + "\"/>" + "Add to Shopping Cart" + "</a></td></tr><p>"; } rs.close(); return htmlOutput; }

g. Modify the doGet() method to call the method that you have created in a try/catch block. Make sure to create table headings for the product name and description.
out.println("<h3>Please select from the following products:</h3>"); try { out.println("<table border=1><tr><td>" + "Product Name" + "</td><td>" + "Product Description" + "</td><td>" + getProducts() + "</table>"); } catch(SQLException sqle) { sqle.printStackTrace(); } Oracle 10g: Build J2EE Applications A-21

Practice 7-1 Solution (continued) 2. Create a link from LoginServlet to ProductsServlet. a. Below the code for displaying orders for a customer (in the doPost() method), insert an href link to point to the ProductsServlet. You can use the URL-pattern mapping name that is generated for you, described in the web.xml file. Note that the cookie functionality created in the last practice has been removed to prevent any confusion.
if (verifyCustomer(conn,id,name)) { out.println("Orders for " + name + ":"); out.println("<table border=1><tr><td>" + "Order Id" + "</td><td>" + "Order Status" + "</td><td>" + "Order Total" + "</td><td>" + getOrders(conn, id) + "</td></tr></table>"); out.println("<a href=productsservlet>Order Products</a>"); }

3. Create a ShoppingCart class to store the selected products in a Hashtable. a. Create a new class file by selecting Java Class from the Simple Files category (within the General category). Name the class ShoppingCart and click OK to accept the default package and attributes. b. Import the java.util.* package because you will be using a Hashtable from that package.
import java.util.*;

c. Declare two instance variables in the class definition: items and numberOfItems. Declare items as a Hashtable and numberOfItems as type int, initializing to null and zero, respectively.
Hashtable items = null; int numberOfItems = 0;

d. In the class constructor, initialize items as a new Hashtable object.


public ShoppingCart() { items = new Hashtable(); }

e. Create a method named add(). This method should return void and pass in two arguments, prodid and name, both strings.
public void add(String prodid, String name) {

Oracle 10g: Build J2EE Applications A-22

Practice 7-1 Solution (continued) f. Add code to this method to store the prodid and name arguments in the Hashtable object that you created in step 3.d., and increment the numberOfItems variable.
items.put(prodid, name); numberOfItems++; }

g. Create a second method named getNumberOfItems(). This method should return numberOfItems.
public int getNumberOfItems() { return numberOfItems; }

h. Create a third method named getItems(). This method should return an enumeration of elements in the items hashtable.
public Enumeration getItems() { return items.elements(); }

i. Compile ShoppingCart.java. 4. The next step is to create a servlet to display the products in the users shopping cart. a. Create a new servlet and name it ShowCartServlet. Change the package name to orderproducts and create servlet mappings as in previous practices. b. Add code to the doGet() method to create a new session object if one does not already exist.
HttpSession session = request.getSession(true);

c. Next, retrieve the users shopping cart as cart from the session object. Use the getId() method of the session to find the unique identifier of the session.
ShoppingCart cart = (ShoppingCart)session.getAttribute(session.getId());

d. If the user does not have an existing shopping cart, create a new one by passing in the sessions unique identifier and cart object.
if (cart == null) { cart = new ShoppingCart(); session.setAttribute(session.getId(), cart); }

Oracle 10g: Build J2EE Applications A-23

Practice 7-1 Solution (continued) e. Create two variables to retrieve the prodid and name parameters from the request object.
String prodid = request.getParameter("prodid"); String prodname = request.getParameter("name");

f. Add these values to the cart object by calling the add() method of the ShoppingCart class and passing in the prodid and name arguments.
cart.add(prodid, prodname);

g. Create an int variable to retrieve the number of items ordered from the ShoppingCart class.
int num = cart.getNumberOfItems();

h. Add HTML to display the number of items in the users shopping cart, and create a table to display the elements in the cart. Note that the getItems() method returns a java.util.Enumeration of items in the Hashtable. You need to import this package. Use the hasMoreElements() method to verify items in the getItems() method. Remove the skeleton HTML code.
out.println("<html>"); out.println("<head><title>Products Shopping Cart</title></head>"); out.println("<body>"); out.println("<h1 align=center>Products Shopping Cart </h1><p>"); out.println("<p>You have " + num + (num==1 ? " item" : " items") + " in your shopping cart:"); out.println("<p><table border=1>" + "<tr>" + "<td><strong>Product Name</strong></td>" + "</tr>"); Enumeration e = cart.getItems(); while (e.hasMoreElements()) { out.println("<tr><td>" + e.nextElement() + "</td></tr>"); } out.println("</table></body> </html>");

i. Compile ShowCartServlet.java. 5. Save and compile the project, and test the application by running LoginServlet.java.

Oracle 10g: Build J2EE Applications A-24

Practice 8-1 Solution The purpose of this practice is to familiarize you with expressions and scriptlets that you have learned in the lesson. You generate a simple HTML form that displays a text field and a Submit button. Name this form Form.html. Develop a Charcounter.jsp file that counts the occurrence of each character in a string. The HTML form should invoke the Charcounter.jsp file when the string is entered in the text field, and the Submit button is clicked. The JSP should obtain the string and count the occurrence of each character and display the characters. Open the practice08.jws workspace and navigate to the countchars project. 1. Generate the Charcounter.jsp file: a. Right-click countchars and select New. Expand the Web Tier node under Categories. b. Select JavaServer Pages under Web Tier and select JSP Page from Items. Click OK. c. Enter Charcounter.jsp in the File Name field. Click OK. You see the JSP file in the Web Content folder. 2. Edit the Charcounter.jsp file: a. Select the CSS category from the Component Palette, and drag the Oracle style sheet onto the page. b. Switch to the Source view and change the title to Character Counter. c. Add code to declare the following variables (use the scriptlet tag): A string (inputString) to hold the input parameter A character array (inputArray) to hold the characters of the string An integer (len) to hold the length of input string An integer array (count) and a character array (c) with the size equal to the length of the string An integer (lastpos) A Boolean variable (done) initialized to false
<% String inputString; char[] inputArray; char[] c; int len, lastpos=0; int[] count; boolean done=false; %>

d. Add code to count the occurrences of each character in the string and display it. Use the scriptlet tag to code the logic. Note: You can implement the logic to count the occurrences of characters in different ways. The solution provided for this practice is only one way of doing it.

Oracle 10g: Build J2EE Applications A-25

Practice 8-1 Solution (continuation)


<% inputString= request.getParameter("input"); %> <%= "The input string is "+ inputString %> <br> <br> <% inputArray = inputString.toUpperCase().toCharArray(); len= inputArray.length; count=new int[len]; c = new char[len]; for( int i = 0; i < len ; i++ ) { for( int j=0;j<lastpos;j++) if( c[j] == inputArray[i] ) { count[j]++; done=true; break; } if( !done ) { c[lastpos] = inputArray[i]; count[lastpos++]++; } done=false; }

for( int i = 0; i < lastpos ; i++ ) { %> <%= c[i] + " " + count[i] %> <BR> <% } %>

3. Open Form.html in the visual editor: a. Select HTML from the Component Palette and insert tags to create a form that displays a text box with a name attribute of "input", and a Submit button. b. Select the form in the visual editor and change the value of the action attribute in the Property Inspector to Charcounter.jsp.
<form action="Charcounter.jsp" method=post> <input type="text" name="input"> <BR> <input type="submit" value="Submit"> </form>

Oracle 10g: Build J2EE Applications A-26

Practice 8-1 Solution (continuation) 4. Test and run the application: a. Run the Form.html file: Right-click Form.html in the System Navigator and select Run. b. Enter a string in the text field and press [Enter] or click the Submit button. 5. Sample Input/Output: - Input: STATISTICS - Output: S 3 T 3 A 1 I 2 C 1

Oracle 10g: Build J2EE Applications A-27

Practice 8-2 Solution The purpose of this practice is to use JavaBeans in JSPs. You develop a JavaBean, DiscountBean.java, which calculates equal discount on the total amount of purchase and returns the new price. You also design a JSP, CallDiscountBean.jsp, which uses the JavaBean. The total amount of purchase (original price) is passed with the URL to the JSP. The JSP then invokes the bean method, which calculates the price after discount by passing the price, and displays the price after discount. Navigate to the discountbean project in practice08.jws. 1. Open DiscountBean.java in the code editor: a. Add code to declare three instance variables discount, price, and priceAfterDiscount of double type. Initialize discount to 10.5.
double discount=10.5,price, priceAfterDiscount;

b. Implement the set() method for price. Optionally, you can also implement the get() method:
public void setPrice(double p) { price=p; }

c. Implement the get() method for priceAfterDiscount. Write code to calculate the price depending on the value of discount and return the new price.
public double getPriceAfterDiscount() { priceAfterDiscount = price-((price*discount)/100); return priceAfterDiscount; }

2. Open the CallDiscountBean.jsp file in the editor. Look for comments and insert the tags as instructed, using either the design or source view: a. Insert an expression to get the price from the URL:
<%= request.getParameter("price")%>

b. Declare a string called price with the declaration tag and write a scriptlet to get the value of parameter price from the URL and assign it to the string price:
<%! String price; %> <% price = request.getParameter("price"); %>

c. Insert a useBean tag to instantiate the DiscountBean class:


<jsp:useBean id="db" scope="session" class="discountbean.DiscountBean" /> Oracle 10g: Build J2EE Applications A-28

Practice 8-2 Solution (continued) d. Insert a JSP expression to display the price:
price before discount: <%= price %>

e. Insert the setProperty tag to set the value of price:


<jsp:setProperty name="db" property="price" value='<%=price %>' />

f. Insert the getProperty tag to get the price after discount:


<jsp:getProperty name="db" property="priceAfterDiscount" />

3. Test and run the application: a. Run CallDiscountBean.jsp: Right-click CallDiscountBean.jsp in the System-Navigator and select Run. b. You see java.lang.NullPointerException because you have not passed any parameter. Note the target URL for this JSP and append the following to the URL in the browser to invoke the JSP: ?price=1000 4. Sample Input/Output: a. Input: <target-url>?price=1000.
http://localhost:8988/practice08-discountbean-context-root/ CallDiscountBean.jsp?price=1000

b. Output:
USING A JAVABEAN TO CALCULATE PRICE AFTER DISCOUNT FOR A PURCHASE OF $1000 price before discount: 1000$ price after discount: 895.0$

Oracle 10g: Build J2EE Applications A-29

Practice 8-3 Solution The purpose of this practice is to create a JSP that interacts with a database by using JDBC. You design a JSP to display PRODUCT_NAME and LIST_PRICE from the PRODUCT_INFORMATION table. The information about the products is displayed in the form of a table. The Java class ProductInfo is responsible for retrieving the data from the database and returning the productnames and listprice in the form of vectors. This class contains get() methods to retrieve the vector. The product.jsp file invokes the get() method to obtain the details and displays them in the form of a table. Navigate to the product project in practice08.jws. Note: Use the oe database connection that you created in Practice 5-1. 1. Set up the project to use this connection (optional): a. Right-click the web.xml file in product.jpr and select Properties. b. Select Resource Environment References and click Add to add this connection to the project as a data source. c. Name the environment reference jdbc/oeDS and specify the type as javax.sql.DataSource. d. You are now able to look up this data source reference using jdbc/oeDS. 2. To add the Oracle JDBC library to the project, double-click the product project and navigate to the Libraries tab under the Development node. Add the Oracle JDBC library to the Selected Libraries for the project. 3. Open ProductInfo.java in the code editor: a. Import the java.sql, javax.sql, javax.naming, and java.util packages:
import import import import java.sql.*; javax.sql.*; javax.naming.*; java.util.*;

b. Declare the following private variables: Vector productnames and listprice ResultSet rs Statement st Connection c
private private private private Vector productnames, listprice; ResultSet rs; Statement st; Connection c;

Oracle 10g: Build J2EE Applications A-30

Practice 8-3 Solution (continued) c. Implement an establishConnection() method with no parameters, and void as a return type. This method should establish the JDBC connection to the oe schema with the data source oeDS that you created in practice 5. Start a try block. Create a Context object. Look for the data source jdbc/oeDS and create an instance of data source, ds. Call the getConnection() method on the ds data source using the Connection object c you declared in the previous step. Create the statement object with this connection. Close the try block. The operations can throw the SQLException or NamingException exceptions. Provide catch blocks for SQLException and NamingException.
public void establishConnection() { try { Context ic = new InitialContext(); DataSource ds = (DataSource)ic.lookup("jdbc/oeDS"); c = ds.getConnection(); st=c.createStatement(); } catch (SQLException se) { System.out.println(se); } catch (NamingException ne) { System.out.println(ne); } }

d. Create a new method to close the connection at the end of the processing. The method should be public, return void and be named closeConnection. Create a try block. Inside the block call the close() method on the connection object. If there is an exception caught, call system.out.println() and issue a message that shows an error closing the connection.

Oracle 10g: Build J2EE Applications A-31

Practice 8-3 Solution (continued)


public void closeConnection() { try { c.close(); } catch(Exception e) { System.out.println(Exception thrown and caught while closing the Connection); } }

e. Implement a private method getData() with no arguments, and void as the return type. Initialize productnames and listprice declared earlier. Start a try block. Use the Statement object created in the establishConnection() method to execute a query. This query should select product_name and list_price from the PRODUCT_INFORMATION table where product_status is orderable and list_price is not null. Populate the productnames Vector with the product_name in the Resultset, and listprice Vector with list_price in the result set. Close the try block. Provide a catch block to catch a generic exception.
private void getData() { productnames = new Vector(); listprice = new Vector(); try { rs=st.executeQuery("select product_name, list_price from product_information where product_status='orderable' and list_price is not null"); while (rs.next()) { productnames.addElement(rs.getString(1)); listprice.addElement(rs.getString(2)); } } catch(Exception e) { System.out.println(e); } }

f. Invoke the methods establishConnection(), getData() and closeConnection()in the constructor.


Oracle 10g: Build J2EE Applications A-32

Practice 8-3 Solution (continued)


public ProductInfo() { establishConnection(); getData(); closeConnection(); }

g. Implement the getProductnames()method, which returns Vector productnames.


public Vector getProductnames() { return productnames; }

h. Implement the getListprice()method, which returns Vector listprice.


public Vector getListprice() { return listprice; }

4. Open Product.jsp: a. Include page directive to import the product package, which contains the ProductInfo class. Also, import the java.util package.
<%@ page import="product.*,java.util.*" %>

b. Include a scriptlet tag to do the following: Instantiate the ProductInfo class. Declare two variables, productnames and listprice, of Vector type. Invoke the getProductnames()and getListprice()methods of the ProductInfo class to populate productnames and listprice respectively. Enumerate through the Vector elements and add the elements as rows to the table:
<% ProductInfo pi=new ProductInfo(); Vector productnames,listprice; productnames=pi.getProductnames(); listprice=pi.getListprice(); Enumeration pn= productnames.elements(); Enumeration lp=listprice.elements(); while (pn.hasMoreElements()) { %> <tr><td> <%=pn.nextElement()%> </td><td> <%=lp.nextElement()%> </td></tr> <% } %>

Oracle 10g: Build J2EE Applications A-33

Practice 8-3 Solution (continued) 5. Test and run the application. Right-click Product.jsp and select Run.

Oracle 10g: Build J2EE Applications A-34

Practice 9-1 Solution The purpose of this practice is to use the Core JSTL tags in a JSP. Open the practice09.jws workspace in JDeveloper. 1. Create a form that asks a user to log in. a. Select the JSTL project and create a new JSP. Name the JSP Login.jsp. b. Select the HTML category from the Component Palette and create a form containing a Submit button that submits to LoginSubmit.jsp. c. Within the form, create two text input fields named username and password. Hint: Use the Property Inspector to change the name attributes of the text fields. d. Create labels for the username and password fields and, optionally, add a style sheet to the page.
<form action="LoginSubmit.jsp"> <P>Username: <input type="text" name="username"/> </P> <P>Password: <input type="text" name="password"/> </P> <P> <input type="submit" value="Submit"/> </P> </form>

2. Use the Core JSTL tags to create a JSP that welcomes the user. a. Create a new JSP named LoginSubmit.jsp in the JSTL project. b. Select the JSTL Core category from the Component Palette. Drag the set tag to the page and set the value property in the Property Inspector to the username request parameter. Name the variable un.
<c:set value="${param.username}" var="un"/>

c. Welcome the user by name using the <c:out> tag to return the value of the un variable. If the name is null, welcome the default user as a guest.
<H1>Welcome, <c:out value="${un}" default="Guest"/> </H1>

d. Run Login.jsp to test.

Oracle 10g: Build J2EE Applications A-35

Practice 9-1 Solution (continued) 3. Next, redirect the user to a URL depending on the username that the user has entered. a. Create a c:choose block in LoginSubmit.jsp. b. If the name supplied is Larry, redirect the user to http://www.oracle.com. c. If the name supplied is Scott, redirect the user to http://java.sun.com. d. Otherwise, advise the user that the username provided is incorrect. Create a URL variable for Login.jsp and supply an href link to the user labeled Try Again. Hint: Create the tags by using the tag dialog that appears when you drag a tag onto the JSP from the Component Palette, then modify the generated code in the source code editor.
<c:choose> <c:when test="${un == 'Scott'}" > <c:redirect url="http://java.sun.com" /> </c:when> <c:when test="${un == 'Larry'}" > <c:redirect url="http://www.oracle.com" /> </c:when> <c:otherwise> Sorry, the username you entered is invalid. Please try again. <c:url value="Login.jsp" var="loginUrl" > </c:url> <a href='<c:out value="${loginUrl}"/>'>Try Again</a> </c:otherwise> </c:choose>

e. Run Login.jsp to test.

Oracle 10g: Build J2EE Applications A-36

Practice 9-2 Solution The purpose of this practice is to use the SQL and Formatting JSTL tags in a JSP. You will query the Products table and display the list price of the products according to a user-selected format. 1. Create a JSP that converts currencies. a. Create a new JSP in the JSTL project named Products.jsp. At the top of the page, insert an HTML form and add the text Convert To:. b. Create three option buttons with values GBP, Yen, and Dollar. The name of these buttons should be Currency. Supply the labels of the option buttons as UK Pounds, Yen, and US Dollars. c. Create a Submit button and submit the form to this page. Hint: Use the HTML tag library in the Component Palette for creating the form, option buttons, and submit buttons. Set the value of the buttons in the Property Inspector.
<form action="Products.jsp"> <P>Convert To: <input type="radio" name="Currency" value="GBP"/>UK Pounds <input type="radio" value="Yen" name="Currency"/>Japanese Yen <input type="radio" name="Currency" value="Dollar"/>US Dollars </P> <P> <input type="submit" value="Submit"/> </P> </form>

d. Beneath the form, use the JSTL SQL tags to select the PRODUCT_ID, PRODUCT_NAME, and LIST_PRICE from the PRODUCTS table where a LIST_PRICE exists. Select only the first 25 rows, using the defined jdbc/oeDS data source, and name the return variable prodresult.
<sql:query dataSource="jdbc/oeDS" var="prodresult" sql="SELECT PRODUCT_ID, PRODUCT_NAME, LIST_PRICE from PRODUCTS where LIST_PRICE is not null" maxRows="25"/>

e. Create a 1 row by 3 column table. f. Within the table, create a <c:forEach> tag to repeat a table row for each row of prodresult returned. Name the returned row variable prodrow. Hint: Create the <c:forEach> tag and then drag it between the <table> and <tr> elements using the Structure Pane.
<table cellspacing="2" cellpadding="3" border="1" width="100%"> <c:forEach items="${prodresult.rows}" var="prodrow"> <tr> <td>

Oracle 10g: Build J2EE Applications A-37

Practice 9-2 Solution (continued) g. In the table, output the value of the PRODUCT_ID and PRODUCT_NAME using a <c:out> tag.
<td> <c:out value="${prodrow.PRODUCT_ID}"/> </td> <td> <c:out value="${prodrow.PRODUCT_NAME}"/> </td>

h. Switch to the code editor and just before the third <td> element, create a JSTL variable named Price for the returned LIST_PRICE.
<c:set var="Price" value="${prodrow.LIST_PRICE}"></c:set>

2. Now create the functionality for converting the price to the specified currency. a. Create conditional tags to test the Currency parameter for GBP or Yen and create a <c:otherwise> tag for the Dollar. b. Within the <c:when> tags, use the setLocale and formatNumber tags to format the variable you created in step 1.h. Use en_GB as the Locale for Pounds, and ja_JP as the Locale for Yen. Multiply the variable by the currency rate (for example, .5437 and 106.034, respectively). Name the variable convertedPrice and set the formatType attribute to currency.
<c:choose> <c:when test="${param.Currency == 'GBP'}"> <fmt:setLocale value="en_GB" /> <fmt:formatNumber var="convertedPrice" value="${Price*.5437}" type="currency" /> </c:when> <c:when test="${param.Currency == 'Yen'}"> <fmt:setLocale value="ja_JP" /> <fmt:formatNumber var="convertedPrice" value="${Price*106.034}" type="currency" /> </c:when>

c. Otherwise, the user must have selected dollars. Use a third formatNumber tag to return the value of the Price variable to the convertedPrice variable.
<c:otherwise> <fmt:formatNumber var="convertedPrice" value="${Price}" type="currency" /> </c:otherwise> </c:choose>

Oracle 10g: Build J2EE Applications A-38

Practice 9-2 Solution (continued) d. Within the last table cell, output the value of the convertedPrice variable.
<td><c:out value="${convertedPrice}" /></td> </tr> </c:forEach> </table>

e. Run Products.jsp to test.

Oracle 10g: Build J2EE Applications A-39

Practice 10-1 Solution The aim of this practice is to write the code to perform JNDI lookup of an EJB and data source object. You do not need to know anything about an EJB other than its name to formulate an appropriate JNDI lookup request, and how to call a method, which is similar to calling a method by using an object reference in any Java application. In JDeveloper open the workspace practice10ske.jws in the practice10ske directory and expand the usingjndi.jpr project. The project contains a HelloWorld stateless session EJB and its deployment descriptor. 1. Enable the HelloWorldLocal.jsp application to invoke the greeting() method of the HelloWorld session bean. The JSP and the session bean execute in the same embedded OC4J container. a. Open the HelloWorldLocal.jsp file and in the first scriptlet create an initial context object and assign it to a Context variable called context.
<% // Create an initial context Context context = new InitialContext(); ... %>

b. Which package name is required in the import statement to compile this line of code?
javax.naming

c. Now modify the string parameter value in the context.lookup() method to be the name of the EJB. Hint: Open the ejb-jar.xml file for the EJB and find the <ejb-name> element.
<% // Create an initial context Context context = new InitialContext(); HelloWorldHome helloWorldHome = (HelloWorldHome) context.lookup("HelloWorld"); HelloWorld helloWorld = helloWorldHome.create(); %>

d. Save your changes, compile the JSP, and correct any syntax errors. e. Expand the usingjndi.impl package, and right-click the HelloWorld node to run the HelloWorld EJB component in the embedded OC4J container. f. Run HelloWorldLocal.jsp and observe the results in the generated HTML page. The HTML page should contain the following text: Result from the HelloWorld greeting() method is: Hello World (from Stateless Session EJB).
Oracle 10g: Build J2EE Applications A-40

Practice 10-1 Solution (continued) 2. Create a stand-alone Java class, with a main() method to invoke the HelloWorldEJB in the embedded OC4J container. a. Right-click the usingjndi project and select New. Then, click Simple Files and create a new Java class called HelloWorldClient, and ensure that the Generate Main Method check box is selected.
package usingjndi; public class HelloWorldClient { public HelloWorldClient() { } public static void main(String[] args) { HelloWorldClient helloWorldClient = new HelloWorldClient(); } }

b. In the default constructor, copy the code from the scriptlet of the HelloWorldLocal.jsp into the body of a try block, with Exception class being caught in the catch block. Hint: Make sure that you import the javax.naming package and any others that may be required in your class, and call the exception object printStackTrace() method in the catch block.
package usingjndi; import javax.naming.*; public class HelloWorldClient { public HelloWorldClient() { try { Context context = new InitialContext(); HelloWorldHome helloWorldHome = (HelloWorldHome) context.lookup("HelloWorld"); HelloWorld helloWorld = helloWorldHome.create(); } catch (Exception e) { e.printStackTrace(); } } Oracle 10g: Build J2EE Applications A-41

Practice 10-1 Solution (continued)


public static void main(String[] args)

{ HelloWorldClient helloWorldClient = new HelloWorldClient(); } }

c. In the last line of the try block, enter the following code to print the return value of the greetings() method of the EJB: System.out.println(helloWorld.greetings());

package usingjndi; import javax.naming.*; public class HelloWorldClient { public HelloWorldClient() { try { Context context = new InitialContext(); HelloWorldHome helloWorldHome = (HelloWorldHome) context.lookup("HelloWorld"); HelloWorld helloWorld = helloWorldHome.create(); System.out.println(helloWorld.greeting()); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { HelloWorldClient helloWorldClient = new HelloWorldClient(); } }

d. Right-click HelloWorldClient.java, and select Run from the menu. e. You are expected to get an error. Can you explain the error? Hint: Check the first line of the error message displayed.

Oracle 10g: Build J2EE Applications A-42

Practice 10-1 Solution (continued)


javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial --The problem here is the no-arg constructor does not have the correct JNDI properties set for the client. This client is running external to the OC4J container, unlike the HelloWorldLocal.jsp that runs in the OC4J container, and gets the intial context JNDI properties from the defaults provider by the container. The solution is to provide the JNDI properties using a Hashtable (env) passed to the InitialContext(env) constructor, or provide a jndi.properties file in the CLASSPATH for this client. The next step in this lab forms the solution using a Hashtable.

f. Modify the HelloWorldClient application to create a java.util.Hashtable with JNDI properties set to the following values: Context.INITIAL_CONTEXT_FACTORY set to the string "com.evermind.server.rmi.RMIInitialContextFactory" Context.SECURITY_PRINCIPAL set to "admin" Context.SECURITY_CREDENTIALS set to "welcome" Context.PROVIDER_URL set to "ormi://localhost:23891/current-workspace-app" Hints: Remember to add an import statement for the java.util.Hashtable. Make sure that the port number in the PROVIDER_URL is the same as the RMI port number printed in the Embedded OC4J Container tab window in the Log Message window.
package usingjndi; import javax.naming.*; import java.util.Hashtable; public class HelloWorldClient { public HelloWorldClient() { try { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.evermind.server.rmi.RMIInitialContextFactory"); env.put(Context.SECURITY_PRINCIPAL, "admin"); env.put(Context.SECURITY_CREDENTIALS, "welcome"); env.put(Context.PROVIDER_URL, "ormi://localhost:23891/current-workspace-app");

Oracle 10g: Build J2EE Applications A-43

Practice 10-1 Solution (continued)


Context context = new InitialContext(); HelloWorldHome helloWorldHome = (HelloWorldHome) context.lookup("HelloWorld"); HelloWorld helloWorld = helloWorldHome.create(); System.out.println(helloWorld.greeting()); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { HelloWorldClient helloWorldClient = new HelloWorldClient(); } }

g. Modify the HelloWorldClient application to provide the Hashtable object as a parameter to the constructor when creating the InitialContext.
... Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.evermind.server.rmi.RMIInitialContextFactory"); env.put(Context.SECURITY_PRINCIPAL, "admin"); env.put(Context.SECURITY_CREDENTIALS, "welcome"); env.put(Context.PROVIDER_URL, "ormi://localhost:23891/current-workspace-app"); Context context = new InitialContext(env); ...

h. Right-click HelloWorldClient.java and select Run. The Log window should show the bean message.
Hello World (from Stateless Session EJB) Process exited with exit code 0.

3. Open the UseDataSource.java file and write the JNDI code to obtain a data source object from an OC4J server. You must run the HelloWorld EJB application to start the embedded OC4J container. a. In the try block of the UseDataSource() constructor create a new InitialContext with the same JNDI properties that are used in the HelloWorld.jsp application.

Oracle 10g: Build J2EE Applications A-44

Practice 10-1 Solution (continued) Hints: Use a Hashtable parameter with the InitialContext constructor, or copy the jndi.properties file located in your <JDEV_HOME>\jdev\mywork\practice10ske directory to your <JDEV_HOME>\jdev\mywork\practice10ske\usingjdni\classes directory, and use the no-arg constructor of the InitialContext. You may need to edit the port number in the java.naming.provider.url property of the jndi.property file.
package usingjndi; import import import import import import import import javax.naming.Context; javax.naming.InitialContext; javax.sql.DataSource; java.sql.Connection; java.sql.Statement; java.sql.ResultSet; java.sql.SQLException; java.util.Hashtable;

import javax.rmi.PortableRemoteObject; public class UseDataSource { public UseDataSource() { Context ctx = null; try { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.evermind.server.rmi.RMIInitialContextFactory"); env.put(Context.SECURITY_PRINCIPAL, "admin"); env.put(Context.SECURITY_CREDENTIALS, "welcome"); env.put(Context.PROVIDER_URL, "ormi://localhost:23891/current-workspace-app"); ctx = new InitialContext(env); } catch (Exception e) { e.printStackTrace(); } finally { } } public void listDepartments(Connection conn) { Statement stmt = null; ResultSet rset = null; try { Oracle 10g: Build J2EE Applications A-45

Practice 10-1 Solution (continued)


stmt = conn.createStatement(); rset = stmt.executeQuery( "select department_id, department_name from departments"); while (rset.next()) { System.out.println(rset.getString(1) + " " + rset.getString(2)); } } catch (Exception e) { e.printStackTrace(); } finally { if (rset != null) try { rset.close(); } catch (Exception e) {} if (stmt != null) try { stmt.close(); } catch (Exception e) {} } } public static void main(String[] args) { try { Class.forName("oracle.jdbc.driver.OracleDriver"); UseDataSource useDataSource = new UseDataSource(); } catch (Exception e) { e.printStackTrace(); } } }

b. Use the context object to create a javax.sql.DataSource object by looking up the JNDI name of jdbc/oeDS.
package usingjndi; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; ... public class UseDataSource { public UseDataSource() { Context ctx = null; DataSource ds = null; try Oracle 10g: Build J2EE Applications A-46

Practice 10-1 Solution (continued)


{ Hashtable env = new Hashtable(); ... ctx = new InitialContext(env); ds = (DataSource) ctx.lookup("jdbc/oeDS"); } catch (Exception e) { e.printStackTrace(); } finally { } } ...

c. Create a java.sql.Connection using the data source object by calling the getConnection(), or the getConnection(user, pass) with your database username and password.
... public UseDataSource() { Context ctx = null; DataSource ds = null; Connection conn = null; try { Hashtable env = new Hashtable(); ... ctx = new InitialContext(env); ds = (DataSource) ctx.lookup("jdbc/oeDS"); conn = ds.getConnection("oraxx","oracle"); } catch (Exception e) { e.printStackTrace(); } finally { if (conn != null) try { conn.close(); } catch (Exception e) {} } } ...

d. Call the listDepartments() method by using the JDBC connection object that you opened from the data source to verify that your JNDI lookup works.
Oracle 10g: Build J2EE Applications A-47

Practice 10-1 Solution (continued)


... public UseDataSource() { Context ctx = null; DataSource ds = null; Connection conn = null; try { Hashtable env = new Hashtable(); ... ctx = new InitialContext(env); ds = (DataSource) ctx.lookup("jdbc/oeDS"); conn = ds.getConnection("ora1","oracle"); this.listDepartments(conn); } catch (Exception e) { e.printStackTrace(); } finally { if (conn != null) try { conn.close(); } catch (Exception e) {} } } ...

e. Compile the code and eliminate any syntax errors. f. Run the HelloWorld EJB to launch the OC4J container. g. Run the UseDataSource application. The application should display a list of department ID and names in the JDeveloper Log window. Optionally, if you have time, then you can perform the following: 4. Alter the client applications to work with the HelloWorld EJB deployed to Oracle Application Server 10g. a. Right-click HelloWorldEJB.deploy and select Deploy to OracleAS10g, or select Deploy to EAR file and deploy the resulting EAR file by using the Oracle Enterprise Manager Web interface. b. Modify HelloWorldClient.java and UseDataSource.java to work with Oracle Application Server 10g.
In HelloWorldClient.java and UseDataSource.java use: env.put(Context.SECURITY_CREDENTIALS, "welcome1"); env.put(Context.PROVIDER_URL, "opmn:ormi://localhost:home/HelloWorldEJB");

Oracle 10g: Build J2EE Applications A-48

Practice 10-1 Solution (continued) c. Run HelloWorldClient.java. You should see the EJB message, Hello World (from Stateless Session EJB), displayed in the Log Message window. d. In HelloWorldClient.java, alter the code that executes the lookup() method by passing the return value of the context.lookup() method to the first parameter of the javax.rmi.PortableRemoteObject.narrow() method. Hint: PortableRemoteObject.narrow() requires HelloWorldHome.class as a second parameter and an import javax.rmi.PortableRemoteObject statement.
package usingjndi; import javax.naming.*; import java.util.Hashtable; import javax.rmi.PortableRemoteObject; public class HelloWorldClient { public HelloWorldClient() { try { Hastable env = ... Context context = new InitialContext(env); HelloWorldHome helloWorldHome = (HelloWorldHome) PortableRemoteObject.narrow( context.lookup("HelloWorld"), HelloWorldHome.class); HelloWorld helloWorld = helloWorldHome.create(); System.out.println(helloWorld.greeting()); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { HelloWorldClient helloWorldClient = new HelloWorldClient(); } }

Oracle 10g: Build J2EE Applications A-49

Practice 10-1 Solution (continued) e. Run the HelloWorldClient.java application again, and it should yield the same result as before. In the client code, you use PortableRemoteObject.narrow()to resolve the remote object reference obtained from the a JNDI lookup request into its target object type. 5. Modify HelloWorldClient.java or UseDataSource.java to use RMI over HTTP tunneling. Hint: Prefix PROVIDER_URL with http:.
In HelloWorldClient.java and UseDataSource.java use: env.put(Context.SECURITY_CREDENTIALS, "welcome1"); env.put(Context.PROVIDER_URL, "http:opmn:ormi://localhost/HelloWorldEJB");

Oracle 10g: Build J2EE Applications A-50

Practice 11-1 Solution The purpose of this practice is to reinforce the concepts of EJBs by creating a simple session bean in JDeveloper, testing it, and deploying it. 1. Create a new EJB: a. Navigate to the EJB project in the practice11ske.jws workspace. Right-click the EJB project and select New. b. From the Business Tier category, select Enterprise JavaBeans and select Session Bean from the items list. c. Select EJB 2.0 to create a session bean that complies with the 2.0 specification. d. Accept the defaults for the name, session, and transaction types, and click Next. e. Accept the defaults for the bean class and source directory, and click Next. f. Accept the default to include the remote interfaces for the bean. g. Click Finish to generate the EJB. 2. Add a field to the EJB that you have created: a. Right-click the bean class that is generated for you and select Go to Bean Class. b. Click the Class tab to open the class editor. c. Click the Fields tab and add a String field named hello to the EJB. d. Accept all the other field defaults and click OK. e. Click the Source tab to view the code that is generated for you. f. Select the bean in the System-Navigator and double click the remote interface in the Structure Pane. g. Create a declaration in the remote interface for the setHello() and getHello() methods. These methods should throw a java.rmi.RemoteException exception.
void setHello(String newHello) throws RemoteException; String getHello() throws RemoteException;

3. Test the EJB. a. Right-click the bean in the navigator and choose Run. This starts the embedded OC4J server and deploys the EJB. After the message, Oracle Application Server Containers for J2EE 10g initialized appears, the bean is running and you can access it with a client. b. Right-click your session bean and select New Sample Java Client. c. In the Sample EJB Java Client Details dialog box, select the option to connect to the embedded OC4J server and click OK. d. A new client file is created for you. View the code in the editor to see how the client accesses the EJB that you created in step 1. e. Uncomment the setHello() method and set the value to any String value.
sessionEJB.setHello("hi there");

f. Call getHello() and print it to the console.


System.out.println(sessionEJB.getHello( ));

Oracle 10g: Build J2EE Applications A-51

Practice 11-1 Solution (continued) g. If the code was not added for you, obtain access to the InitialContext object by copying and pasting the following code into the getInitialContext() method: Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.evermind.server.rmi.RMIInitialContextFactory"); env.put(Context.SECURITY_PRINCIPAL, "admin"); env.put(Context.SECURITY_CREDENTIALS, "welcome"); env.put(Context.PROVIDER_URL, "ormi://localhost:23891/current-workspace-app"); return new InitialContext(env); h. Finally, run the client by right-clicking the client and selecting Run. You should see the output in the EJB.jpr message window containing your String value.

Oracle 10g: Build J2EE Applications A-52

Practice 12-1 Solution The purpose of this practice is to create a stateless session bean that validates the entry made for the customer card number. The bean should contain a business method that takes the customer card number in the form of a string and validates the card. Note that this practice does not check the card number against some entries in the database. A card number can be alphanumeric. A card is valid if: The length of the number is nine characters It starts with AN, BN, CN, or LN The last character is A The rest of the characters are numbers and not letters The workspace for this practice is practice12oneske.jws. Open the validatecard project. This project contains the necessary skeleton files for this practice. 1. Expand the validatecard node, select the ValidateCard EJB, and double-click ValidateCard.java in the Structure Pane to open it in the code editor. This is the remote interface. a. Import the java.rmi package.
import java.rmi.*;

b. Declare a method called validate(), which takes a string as parameter and returns a string. This method should throw a RemoteException exception.
public String validate(String s) throws RemoteException;

2. Add code to the bean class. Open ValidateCardBean.java in the code editor. Implement the validate() method that is declared in the remote interface. This method should verify that the card is valid. The conditions for the validity of the card are given above.
public String validate(String s) { String input=s.toUpperCase(); boolean flag=true; if(input.length()!=9) return "Ensure that you enter right number of characters"; else { if(input.startsWith("AN")||input.startsWith("BN")||input.startsWith("CN") ||input.startsWith( "LN")) { char c[]=new char[6]; input.getChars(3,9,c,0); for(int i=0;i<5;i++) { int j=c[i]; if((j <48) || (j>57)) flag=false; Oracle 10g: Build J2EE Applications A-53

Practice 12-1 Solution (continued)


} if(flag) { if((c[5]=='a')||(c[5]=='A')) return " THANKYOU FOR PROVIDING YOUR CUSTOMER CARD NUMBER"; else return "Please verify your custormer card number"; } else return "Please verify your custormer card number"; } else return "Please verify your custormer card number"; } }

3. Generate a sample Java client. Right-click the ValidateCard bean in the navigator and select New Sample Java Client. Select Connect to OC4J Embedded in JDeveloper if you are testing your EJB with the embedded OC4J, otherwise select Connect to Remote Application Server. Click OK. 4. Invoke the validate() business method from the client application ValidateCardClient.java: Add code to the try block of the main() method to invoke the validate() method. Invoke the method twice: once with a valid card number and once with an invalid card number.
System.out.println("Passing a valid customer card number BN349672A "); System.out.println(validateCard.validate("BN349672A")); System.out.println("Passing an invalid customer card number BN3496723A"); System.out.println(validateCard.validate("BN3496723A"));

5. Test and run the application: a. Right-click ValidateCard bean and select Make (optional). b. Right-click ValidateCard bean and select Run. c. Right-click the client application and select Run. 6. Sample Input/Output: If the following lines are added to the client application:
System.out.println("Passing a valid customer card number BN349672A "); System.out.println(validateCard.validate("BN349672A")); System.out.println("Passing an invalid customer card number BN3496723A"); System.out.println(validateCard.validate("BN3496723A"));

Oracle 10g: Build J2EE Applications A-54

Practice 12-1 Solution (continued) The output is:


Passing a valid customer card number BN349672A THANKYOU FOR PROVIDING YOUR CUSTOMER CARD NUMBER Passing an invalid customer card number BN3496723A Ensure that you enter right number of characters

Oracle 10g: Build J2EE Applications A-55

Practice 12-2 Solution The purpose of this practice is to create a stateless session bean that interacts with the database by using JDBC. So far you have used the oe schema for the practices. In this practice, you create a connection to the hr schema and create the data source reference to it. The bean should contain a business method that takes the employee_id and retrieves first_name, last_name, email, department_name from the EMPLOYEES table and the DEPARTMENTS table. The business method returns an instance of EmployeeDetails class. This instance has variables to hold the first name, last name, e-mail, and department name of the employee. Note: The EMPLOYEES table has many fields, some of them are first_name, last_name, and email. However, the EMPLOYEES table does not contain the department_name. The DEPARTMENTS table has department_name, and the common field in both the EMPLOYEES and DEPARTMENTS table is department_id. Therefore, you can join the two tables to obtain the department_name. For the description of each of these tables, refer to Appendix B. The workspace for this practice is practice12twoske.jws. Open the employeedetails project and expand the employeedetails node. The Employee bean contains the skeleton files that are required to implement the session bean. 1. Create the connection to use as the data source for the session bean: a. In the Connection Navigator, right-click Database and select New Database Connection. You see the Connection Wizard. Click Next. b. Provide hr for Connection Name and select Oracle (JDBC) as Connection Type. Click Next. c. Provide username and password as oraxx/oracle (as provided by your instructor). Click Next. d. Check the Host Name, JDBC port, and SID, as indicated by your instructor. Click Next. e. Test connection by clicking the Test Connection button. Click Finish. 2. Edit the EmployeeDetails.java file in the code editor: a. Import java.io package.
import java.io.*;

b. Declare four string variables: fname, lname, email, and deptname.


String fname, lname, email, deptname;

c. Provide a constructor that takes parameters to initialize all four instance variables.
public EmployeeDetails(String fname, String lname, String email, String deptname) { this.fname=fname; this.lname=lname; this.email=email; this.deptname=deptname; } Oracle 10g: Build J2EE Applications A-56

Practice 12-2 Solution (continued) d. Override the toString() method to provide a string representation of the object.
public String toString() { return fname + " "+lname+" "+email+" "+deptname; }

3.

Modify the remote interface: a. Navigate to Employee.java and open it in the code editor. b. Import the java.rmi package.

import java.rmi.*;

c. Declare a getDetails()method that takes an integer as argument and returns an EmployeeDetails object. This method should throw the RemoteException exception:
public EmployeeDetails getDetails(int empno) throws RemoteException;

4. Modify the bean class: a. Open the EmployeeBean.java file in the code editor. b. Import the packages java.sql, javax.naming, javax.sql, and employeedetails (contains the EmployeeDetails class).
import import import import java.sql.*; javax.naming.*; javax.sql.*; employeedetails.*;

c. Declare the following instance variables: Connection variable conn, Statement variable st, and ResultSet variable rs.
Connection conn; Statement st; ResultSet rs;

5. Implement a method establishConnection() that returns a Connection object as follows: a. Declare variable ds of type DataSource.
Connection establishConnection() { DataSource ds=null;

Oracle 10g: Build J2EE Applications A-57

Practice 12-2 Solution (continued) b. Start a try block, and get the initial context and lookup for the data source jdbc/hrDS. This code can throw the NamingException exception.
try { Context ic = new InitialContext(); ds=(DataSource)ic.lookup("jdbc/hrDS");

c. Get the connection by invoking the getConnection() method on the data source. This can throw a SQLException exception. You can have two catch blocks, or you can catch the generic exception.
conn=ds.getConnection();

d. Close the try block and add catch blocks.


} catch(NamingException n) { System.out.println(n); } catch(SQLException s) { System.out.println(s); }

e. Return the connection.


return conn; }

6. Implement the getDetails() method as follows: a. It should take an integer as argument, which is the employee_id of an employee, and return an instance of EmployeeDetails class.
public EmployeeDetails getDetails(int empno) {

b. Create a variable emp of type EmployeeDetails.


EmployeeDetails emp = null;

Oracle 10g: Build J2EE Applications A-58

Practice 12-2 Solution (continued) c. Start a try block. Call the establishConnection() method to initialize the Connection object conn. Create a Statement with this object.
try { conn=establishConnection(); st=conn.createStatement();

d. Execute the query to retrieve employee first_name, last_name, and email from the EMPLOYEES table and department_name from the DEPARTMENTS table.
rs=st.executeQuery("select x.first_name, x.last_name,x.email, y.department_name from employees x, departments y where x.employee_id = " + empno + " and x.department_id=y.department_id");

e. Create an instance called EmployeeDetails class with first_name, last_name, email, and department_name as parameters.
while (rs.next()) { emp= new EmployeeDetails(rs.getString(1),rs.getString(2),rs.getString(3),rs.getStr ing(4)); }

f. Close the try block and catch generic exception.


} catch(Exception e) { System.out.println(e); }

g. Return EmployeeDetails object emp.


return emp; }

Oracle 10g: Build J2EE Applications A-59

Practice 12-2 Solution (continued) 7. Edit the client application EmployeeClient.java in the code editor. Invoke the getDetails()business method: a. Add code to the try block of the main() method to invoke the getDetails() method.
System.out.println(employee.getDetails(119));

8. Test and run the application: a. Right-click Employee bean and select Make (optional). b. Right-click Employee bean and select Run. c. Right-click the client application and select Run. 9. Sample input/output: If the following line is added to the client application: System.out.println(employee.getDetails(119)); The output is:
Karen Colmenares KCOLMENA Purchasing

Oracle 10g: Build J2EE Applications A-60

Practice 13-1 Solution 1. Which two of the following statements regarding entity beans are true? a. Live for the lifetime of a client b. Are long-lived and, therefore, are independent of a clients session c. Model a process or workflow and, therefore, are represented by verbs d. Contain complex business logic that is needed to process the workflow e. Represent persistent data. They model data but not business process and, therefore, are represented by nouns.
b,e

2. Which three of the following statements regarding finder methods are true? a. An entity bean can have one or more finder methods. b. Finder methods find one row at a time in the database table. c. Finder methods find a row or rows in the database table. d. These methods must throw FinderException but need not throw RemoteException. e. These methods must throw both FinderException and RemoteException. f. They return home interface reference or collection of objects of home interface type.
a, c, e

3. For methods given in column A, choose appropriate statements from column B A 1) ejbFind() B a) Removes or deletes the database data but the in-memory entity bean instance is retained by the container to handle different data/row of the table. b) Saves the data from the bean instance to the persistent storage c) Does not create new database data but loads some existing entity bean data. The developer has to implement this method in case of BMP beans and the container implements this in case of CMP beans. d) Loads the data from the persistent storage to the bean e) Releases the resources held by the entity bean and saves the bean state to the underlying storage. The bean instance is put into a generic instance pool.

2) ejbPassivate() 3) ejbRemove()

4) ejbLoad() 5) ejbStore()

1) c, 2) e, 3) a, 4) d, 5) b

Oracle 10g: Build J2EE Applications A-61

Practice 13-1 Solution (continued) 4. The ejbRemove()method of entity beans does not take any parameters. This method is not called if the client times out. (True/False) True There is only one form of ejbRemove() method for an entity bean. Reason: Entity bean instances can be dynamically assigned to handle different data and, therefore, the getPrimaryKey() method should be used to find out which bean has to be removed before removing. The bean implementation code can either get its identity from getPrimaryKey()or from accessing its CMP field (or method). The lifetime of an entity bean is independent of a clients lifetime and, therefore, the ejbRemove ()method is not called if the client times out. 5. Which two of the following statements regarding primary key classes are true? a. Used to uniquely identify the entity bean instances b. Contains only a single primary key to identify bean instances c. Should implement java.io.Serializable d. Can be used to create an instance, but cannot be used for removing the instance
a, c

Oracle 10g: Build J2EE Applications A-62

Practice 14-1 Solution The purpose of this practice is to create a CMP entity bean (UpdateEmployee) that represents the EMPLOYEES table of the hr schema. The bean should contain the set() and get() methods for the CMP fields. It should also contain a business method called updateDetails() that updates the EMPLOYEES table. Note: For this practice, you can use the database connection hr, which was created in step 1 of practice 12-2. The workspace for this practice is practice14ske.jws. Open the updateemployeeCMP project. This project contains the necessary skeleton files for this practice. Note that these files are created by using the entity beans from the Tables option of JDeveloper, which was demonstrated in the demonstration in this lesson. 1. Navigate to UpdateEmployee.java in the UpdateEmployee bean and open it in the code editor. This is the remote interface: Declare an updateDetails() method that takes the following as parameters: Long empid (this corresponds to employee_id, which is the primary key of the table), String lname, String fname, String email, Timestamp hdate, and String jid. This method should throw the RemoteException exception.
void updateDetails(Long empid, String lname, String fname, String email, Timestamp hdate, String jid) throws RemoteException;

2. Add code to the bean class. Open UpdateEmployeeBean.java in the code editor. Implement the updateDetails() method that is declared in the remote interface: a. Invoke the set() methods for the CMP fields lname, fname, email, hdate, and jid in the updateDetails() method.
public void updateDetails(Long empid, String lname, String fname, String email, Timestamp hdate, String jid) { System.out.println("CALLED updateDetails()... "); setLastName(lname); setFirstName(fname); setEmail(email); setHireDate(hdate); setJobId(jid); System.out.println(" UPDATED SUCCESSFULLY..."); }

3. Edit the UpdateEmployeeClient.java file: a. Import java.sql.Timestamp:


import java.sql.Timestamp;

Oracle 10g: Build J2EE Applications A-63

Practice 14-1 Solution (continued) b. Add code to the try block of the main() method. Use the second form of create()method with parameters and add a new employee with the following data: employee_id=600, last_name=shenoy, email=pshenoy, hire_date=21-jul-2001, and job_id=ST_MAN. Note: Observe the code that creates a Calendar object with the hire_date. Time in milliseconds is obtained with this object. Use this long value to create the Timestamp object while invoking the create()and updateDetails() methods. Pass the long value to the constructor of Timestamp. Other forms of constructors are deprecated.
Calendar cal=Calendar.getInstance(); cal.set(2001,07,21); long l=cal.getTimeInMillis(); System.out.println("Adding a new employee with employee_id 600"); updateEmployee = updateEmployeeHome.create( new Long(600), "shenoy", "pshenoy", new Timestamp(l), "ST_MAN" ); System.out.println("Added successfully... \n\n");

c. After the record is added, use the set() method to set the first name to Preetham. Invoke the get() methods to display the first_name and last_name.
System.out.println("Calling setFirst_name() to set the first_name to Preetham "); updateEmployee.setFirstName("Preetham"); System.out.println("Displaying the first_name and last_name \n " + updateEmployee.getFirstName().toUpperCase() + " "+ updateEmployee.getLastName().toUpperCase()+ "\n");

d. Invoke the updateDetails()business method to update the details of the employee. Change first_name to Joseph, last_name to Dsouza and email to jdsouza. Display the first_name and last_name.
System.out.println("CALLING THE updateDetails() BUSINESS METHOD TO UPDATE THE DETAILS OF THE EMPLOYEE"); updateEmployee.updateDetails(new Long(600), "Dsouza","Joseph", "jdsouza", new Timestamp(l), "ST_MAN"); System.out.println("Displaying the first_name and last_name \n " + updateEmployee.getFirstName().toUpperCase() + " "+ updateEmployee.getLastName().toUpperCase()+ "\n");

e. Find details of the employee whose employee_id=120. Hint: Use findByPrimaryKey()method. Display the first_name and last_name of this employee.
System.out.println("Finding details of an employee whose employee_id=120, using the findByPrimaryKey() method"); updateEmployee = updateEmployeeHome.findByPrimaryKey(new Long(120)); System.out.println("Displaying the first_name and last_name \n " + updateEmployee.getFirstName().toUpperCase() + " "+ updateEmployee.getLastName().toUpperCase()+" \n"); Oracle 10g: Build J2EE Applications A-64

Practice 14-1 Solution (continued) 4. Test and run the application: a. Right-click the UpdateEmployee bean and select Make (optional). b. Right-click the UpdateEmployee bean and select Run. c. Right-click the client application and select Run. 5. Sample Output:
Adding a new employee with employee_id 600 Added successfully... Calling setFirst_name() to set the first_name to Preetham Displaying the first_name and last_name PREETHAM SHENOY CALLING THE updateDetails() BUSINESS METHOD TO UPDATE THE DETAILS OF THE EMPLOYEE Displaying the first_name and last_name JOSEPH DSOUZA Finding details of an employee whose employee_id=120, using the findByPrimaryKey() method Displaying the first_name and last_name MATTHEW WEISS

Oracle 10g: Build J2EE Applications A-65

Practice 15-1 Solution The purpose of this practice is to create Employees and Departments entity beans with a one-to-many relationship. The workspace for this practice is practice15ske.jws. Open the empdeptCMR project. This project contains the two entity beans: Employees and Departments. Note: You will use the database connection hr, which you have used for the lesson 14 practice.
1. Expand the empdeptCMR project and double click DepartmentsBean.java in the

Structure Pane to open it in the editor. Examine the various methods in this class and observe that all the set() and get() methods are abstract methods. You will use the following method in your application:
public abstract Collection getEmployees_departmentId();

2. Similarly, observe the methods in EmployeesBean.java. You will use the following method in your application: public abstract DepartmentsLocal getDepartments_departmentId(); 3. Create a session bean named EmpdeptSession containing a remote interface. Enter EmpdeptSession for the EJB Name and accept all other defaults. 4. Add EJB Local References of Employees bean and Departments bean to the session bean by following these steps: a. Double-click EmpdeptSession to open the EJB Module Editor. b. Select EJB Local References and click Add. c. Select Departments from the Auto-create Reference to EJB drop-down menu and click OK. d. Click Add again and select Employees from the Auto-create Reference to EJB drop-down menu and click OK. e. Click OK to close the EJB Module Editor. f. Double-click EmpdeptSessionBean.java and see the lookup code that is added as a result of adding EJB Local References to EmpdeptSession.
5. Create Data Transfer Object (DTO) for both Employees and Departments entity bean by right-clicking the bean and selecting Generate Data Transfer Object.

Note: Refer to the last page of this lesson to learn about DTOs. 6. Edit the remote interface, EmpdeptSession.java, of the session bean. Import the following: java.rmi.RemoteException and java.util.Collection. Add a method called getEmployeesInDept()that takes a Long value as argument and returns a Collection.

Oracle 10g: Build J2EE Applications A-66

Practice 15-1 Solution (continued)


import import public { public } java.rmi.RemoteException; java.util.Collection; interface EmpdeptSession extends EJBObject Collection getEmployeesInDept(Long deptno) throws RemoteException;

7. Include another method getDepartmentID() that takes a Long value as argument and returns an object of Long.
public Long getDepartmentID(Long empno) throws RemoteException;

8. Edit the EmpdeptSessionBean.java session bean. Import java.util.*. Implement the getEmployeesInDept() method as follows:
import java.util.*; public Collection getEmployeesInDept(Long deptno) { Collection returnColl = new ArrayList(); try { DepartmentsLocal dept = this. getDepartmentsLocalHome().findByPrimaryKey(deptno); Collection empColl = dept.getEmployees_departmentId(); Iterator empIter = empColl.iterator(); while(empIter.hasNext()) { EmployeesLocalDTO empDTO = new EmployeesLocalDTO(); EmployeesLocal empBean = (EmployeesLocal)empIter.next(); empDTO.setEmployeeId(empBean.getEmployeeId()); empDTO.setFirstName(empBean.getFirstName()); empDTO.setLastName(empBean.getLastName()); returnColl.add(empDTO); } } catch(Exception ex) { System.out.println(" Error getting employees in dept : "+deptno+" "+ex); } return returnColl; }

Oracle 10g: Build J2EE Applications A-67

Practice 15-1 Solution (continued) 9. Implement the getDepartmentID()method as follows:


public Long getDepartmentID(Long empno) { Long deptno=new Long(0); try { EmployeesLocal emp =this.getEmployeesLocalHome(). findByPrimaryKey(empno); deptno = emp.getDepartments_departmentId(). getDepartmentId(); } catch(Exception ex) { System.out.println(" Error getting the department_id of employee "); } return deptno; }

10. Create the client application. Right-click the session bean and select New Sample Java Client. Select Connect to OC4J Embedded in JDeveloper and click OK. a. Edit the client application and Import java.util.*.
import java.util.*;

b. In the main()method, use the session bean instance to invoke the getEmployeesInDept()to get the information of all employees working in department 50. Note that this method in turn invokes the getEmployees_departmentId()method of the Departments bean.
public static void main(String [] args) { EmpdeptSessionClient empdeptSessionClient = new EmpdeptSessionClient(); try { Context context = getInitialContext(); EmpdeptSessionHome empdeptSessionHome = (EmpdeptSessionHome)PortableRemoteObject.narrow(context.lookup("EmpdeptSe ssion"), EmpdeptSessionHome.class); EmpdeptSession empdeptSession; empdeptSession = empdeptSessionHome.create(); Collection empColl = empdeptSession.getEmployeesInDept ( new Long(50) );

Oracle 10g: Build J2EE Applications A-68

Practice 15-1 Solution (continued) c. Create an Iterator to iterate through the collection that is returned by the session bean. Typecast the object in the Iterator to EmployeesLocalDTO, retrieve the values, and print the values. Repeat this for all the objects in the collection.
Iterator empIter = empColl.iterator(); System.out.println(" PRINTING EMPLOYEE_ID, FIRST_NAME, LAST_NAME OF EMPLOYEES IN THE DEPARTMENT " ); while(empIter.hasNext()) { EmployeesLocalDTO emp = (EmployeesLocalDTO)empIter.next(); System.out.println(emp.getEmployeeId()+" "+ emp.getFirstName()+" "+emp.getLastName()); }

d. Invoke the getDepartmentID()method to get the department ID of the employee with employee_id 118. Note that this method in turn invokes the getDepartments_departmentId() method of the Employees bean.
System.out.println("PRINTING DEPTNO OF THE EMPLOYEE : " + empdeptSession.getDepartmentID(new Long(118)));

11. Right-click EmpdeptSession and select Run. 12. Right-click EmpdeptSessionClient and select Run. Sample Output: PRINTING EMPLOYEE_ID, FIRST_NAME, LAST_NAME OF EMPLOYEES IN THE DEPARTMENT 120 Matthew Weiss 121 Adam Fripp 122 Payam Kaufling 123 Shanta Vollman 124 Kevin Mourgos ...... PRINTING DEPTNO OF THE EMPLOYEE: 30

Oracle 10g: Build J2EE Applications A-69

Practice 16-1 Solution In this practice, you create a simple message-driven bean to receive messages from an OC4J JMS queue, and modify a JSP to send messages to the EJB. Open the practice16.jws workspace in the practice16 directory. The workspace contains the two projects webtier and businesstier, along with their respective solution projects webtiersoln and businesstiersoln. 1. Create the log message table used by the Logmessages entity to store messages that are sent to the MDB that you create. Use SQL*Plus to execute logmessages.sql from the directory: <JDEV_HOME>\jdev\mywork\practice16.
Run SQL*Plus and connect to the database with your user name ORAx and password oracle. In SQL*Plus execute the follow line: SQL> @ E:\jdev1012\jdev\mywork\practice16\logmessages.sql

2. Now modify some OC4J configuration files to use OC4J JMS. a. Create a new queue and data source reference. Open a browser and navigate to http://localhost:1810. Enter the username ias_admin and the password welcome1. Click on the home instance page. b. Click the Administration tab and the Advanced Properties link. Click the jms.xml link to add a queue and queue connection factory. c. Create a new queue named "jms/Queue/Queue1" with a location of "jms/Queue/Queue1". Provide the queue connection factory location as "jms/Queue/QCF". It is important that you type these entries and do not copy and paste from another location. Click Apply and then click OK. When prompted to restart OC4J, click Yes.
The XML elements that should be added inside the root element are: <queue name="jms/Queue/Queue1" location="jms/Queue/Queue1"></queue> <queue-connection-factory location="jms/Queue/QCF"></queue-connectionfactory>

d. Next create a new data source. From the home instance page, click the Data Sources link. Click Create and enter these details: Name: LogDS Description: log Data Source Class: com.evermind.sql.DriverManagerDataSource JDBC URL: The URL provided to you by your instructor JDBC Driver: oracle.jdbc.driver.OracleDriver In Datasource Username: Username: oraxx (as provided to you by your instructor) Use a cleartext password of oracle

Oracle 10g: Build J2EE Applications A-70

Practice 16-1 Solution (continued) In JNDI Locations: Location: jdbc/LogCoreDS Transactional location: jdbc/xa/LogXADS EJB location: jdbc/LogDS Leave all other fields blank or set to the default. e. Click Create and restart the server when prompted. 3. Create a simple MDB to accept a message from an OC4J JMS queue, and store the message text as a record in a log table by using the Logmessages entity bean provided. a. In the businesstier project, create a new Enterprise JavaBean of the MDB type. Define the bean name as MessageLogger.
Here is the code generated by JDeveloper for MessageLoggerBean. package businesstier.impl; import javax.ejb.MessageDrivenBean; import javax.jms.Message; import javax.jms.MessageListener; import javax.ejb.MessageDrivenContext; public class MessageLoggerBean implements MessageDrivenBean, MessageListener { private MessageDrivenContext context; public void ejbCreate() { } public void onMessage(Message msg) { } public void ejbRemove() { } public void setMessageDrivenContext(MessageDrivenContext ctx) { this.context = ctx; } }

b. In the onMessage() method of the bean, process only the TextMessage objects from the queue, and ignore other message type objects. Get the message string by using the getText() method of the TextMessage object, and use the getLongProperty() method of the TextMessage object to get the value of a property named msgid in a Long object variable. Note: Be sure to import javax.jms.TextMessage.
Oracle 10g: Build J2EE Applications A-71

Practice 16-1 Solution (continued)


package businesstier.impl; ... import javax.jms.TextMessage; ... public void onMessage(Message msg) { System.out.println("onMessage() in MessageLoggerBean called"); TextMessage textMessage = null; if (msg instanceof TextMessage) { try { textMessage = (TextMessage) msg; String text = ((TextMessage) textMessage).getText(); Long id = new Long(textMessage.getLongProperty("msgid")); System.out.println("onMessage() received text: " + text); } catch (Exception e) { System.out.println("onMessage() Exception: " + e.getMessage()); } } else { System.out.println("Error:Message of wrong type: " + msg.getClass().getName()); } }

4. Associate the MDB with the OC4J JMS resource provider, the JMS queue from which it receives messages, and the entity bean used to save the message to the log table. a. Open the EJB Module Editor, expand the MessageLogger bean node, select the EJB Local References section, and click the Add button. Select Logmessages from the Auto-create Reference to the EJB drop-down menu. Note: This action adds a getLogmessagesLocalHome() method in the MessageLoggerBean class to access the entity beans local home interface, and a <ejb-local-ref> element to the ejb-jar.xml file.
Changes in the ejb-jar.xml file: <ejb-jar> <enterprise-beans> ... <message-driven> <description>Message Driven Bean</description> <display-name>MessageLogger</display-name> <ejb-name>MessageLogger</ejb-name> ...

Oracle 10g: Build J2EE Applications A-72

Practice 16-1 Solution (continued)


<ejb-local-ref> <ejb-ref-name>ejb/local/Logmessages</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <local-home>businesstier.LogmessagesLocalHome</local-home> <local>businesstier.LogmessagesLocal</local> <ejb-link>Logmessages</ejb-link> </ejb-local-ref> ... </message-driven> </enterprise-beans> Changes in the MessageLoggerBean.java class: package businesstier.impl; import javax.ejb.MessageDrivenBean; import javax.jms.Message; import javax.jms.MessageListener; import javax.ejb.MessageDrivenContext; import businesstier.LogmessagesLocalHome; import javax.naming.InitialContext; import javax.naming.NamingException; public class MessageLoggerBean implements MessageDrivenBean, MessageListener { private MessageDrivenContext context; ... private LogmessagesLocalHome getLogmessagesLocalHome() throws NamingException { final InitialContext context = new InitialContext(); return (LogmessagesLocalHome)context.lookup( "java:comp/env/ejb/local/Logmessages"); } }

b. Select the Destination node and check "Specify Message Driven Destination". Set the Destination Type to javax.jms.Queue and the Subscription Durability to Durable. Click OK to close the window. c. Copy the contents of addLogMessage.txt file in the <JDEV_HOME>\jdev\mywork\practice16 directory into the MessageLoggerBean class. This code provides the method to save the text message in the database table by creating an instance of the Logmessages entity bean. Note: Import the following packages: java.sql.Timestamp, java.util.Date, and javax.ejb.CreateException.

Oracle 10g: Build J2EE Applications A-73

Practice 16-1 Solution (continued)


package businesstier.impl; import javax.ejb.MessageDrivenBean; import javax.ejb.CreateException; import java.sql.Timestamp; import java.util.Date; ... public class MessageLoggerBean implements MessageDrivenBean, MessageListener { private MessageDrivenContext context; ... private void addLogMessage(Long id, String text) { System.out.println("addLogMessage() in MessageLoggerBean called"); // Create Logger entity bean instance and commit the row try { Timestamp ts = new Timestamp(new Date().getTime()); LogmessagesLocalHome logMessageHome = getLogmessagesLocalHome(); System.out.println("Creating *new* log record with id : " + id + " text: " + text); logMessageHome.create(id, ts , text); System.out.println("Done! Check log message table"); } catch (NamingException ne) { System.out.println("onMessage() NamingException: " + ne.getMessage()); } catch (CreateException ce) { System.out.println("onMessage() CreateException: " + ce.getMessage()); } } ... }

d. In the MessageLoggerBean onMessage() method, call the addLogMessages() method as the last line of the try block. Supply the long msgid property value obtained from the message and the text message string as arguments.
public void onMessage(Message msg) { System.out.println("onMessage() in MessageLoggerBean called"); TextMessage textMessage = null; if (msg instanceof TextMessage) Oracle 10g: Build J2EE Applications A-74

Practice 16-1 Solution (continued)


{ try { textMessage = (TextMessage) msg; String text = ((TextMessage) textMessage).getText(); Long id = new Long(textMessage.getLongProperty("msgid")); System.out.println("onMessage() received text: " + text); addLogMessage(id, text); } catch (Exception e) { System.out.println("onMessage() Exception: " + e.getMessage()); } } else { System.out.println("Error:Message of wrong type: " + msg.getClass().getName()); } }

e. Define the OC4J JMS resources used by the MDB, and map the logical JMS resource to the OC4J JMS resources. Right-click orion-ejb-jar.xml and select Properties. In the OC4J EJB Deployment Descriptor window, select the MessageLogger section under Enterprise JavaBeans. In the Connection Factory Location field enter: jms/Queue/QCF, and in the Destination Location enter: jms/Queue/Queue1. These are OC4J JMS queue connection factories and queue resources you defined in step 2b.
Changes to orion-ejb-jar.xml: <orion-ejb-jar> <enterprise-beans> <message-driven-deployment name="MessageLogger" connection-factory-location = "jms/Queue/QCF" destination-location="jms/Queue/Queue1"/> ... </enterprise-beans> ... </orion-ejb-jar>

5. Compile the files in the businesstier project and correct any syntax errors. Right-click ejb-jar.xml and select Create EJB JAR Deployment Profile from the menu, and enter MessageLoggerEJB.deploy as the file name. Click OK, then click OK again to close the window.
Oracle 10g: Build J2EE Applications A-75

Practice 16-1 Solution (continued) 6. Expand the webtier project and open the SendMessage.jsp in the code editor. You now add the code to send a message to the OC4J JMS queue. a. SendMessage.jsp is invoked from an HTML form action generated by the LoginServlet. In SendMessage.jsp, you should construct the string message to contain the request parameter values (obtained from the form fields) for empid, jobid, and msg, concatenated into a space-separated list. b. Write code to create a QueueConnectionFactory object by using the JNDI name of jms/Queue/QCF, and Queue object by using the JNDI name of jms/Queue/Queue1. Create a QueueConnection, a QueueSession, and a TextMessage object by setting the text of the TextMessage object to the string formatted in the previous step. Prior to sending the message, use the message object setLongProperty() method to set a property named msgid to the value of msgId variable, which holds a unique message ID obtained from an Oracle sequence. Finally, write the code to send the TextMessage to the queue.
Changes to SendMessage.jsp are: <% out.println("Sending message ..."); QueueConnectionFactory connectionFactory = (QueueConnectionFactory) new InitialContext().lookup( "java:comp/env/jms/Queue/QCF"); QueueConnection qconn = connectionFactory.createQueueConnection(); QueueSession queueSession = qconn.createQueueSession( false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) new InitialContext().lookup( "java:comp/env/jms/Queue/Queue1"); QueueSender sender = queueSession.createSender(queue); TextMessage message = queueSession.createTextMessage(); message.setJMSType("TextMessage"); message.setLongProperty("msgid", msgId); message.setText(request.getParameter("empid") + " " + request.getParameter("jobid") + " " + request.getParameter("msg")); sender.send(message); sender.close(); queueSession.close(); %>

c. Change the username and password in the doPost() method of LoginServlet.java and in the database tags in SendMessage.jsp to utilize your username and password.

Oracle 10g: Build J2EE Applications A-76

Practice 16-1 Solution (continued) 7. Create the logical JMS resources used in the JSP in the J2EE deployment descriptor. a. Right-click web.xml and select Properties. Select the Resource References section to create logical resources by clicking the Add button. Create a reference with a name field jms/Queue/QCF and Resource Type field javax.jms.QueueConnectionFactory. b. Click the Add button again to create a second reference with a jms/Queue/Queue1 name field and a javax.jms.Queue Resource Type field.
Changes to web.xml are: <web-app> ... <resource-ref> <res-ref-name>jms/Queue/QCF</res-ref-name> <res-type>javax.jms.QueueConnectionFactory</res-type> <res-auth>Container</res-auth> </resource-ref> <resource-ref> <res-ref-name>jms/Queue/Queue1</res-ref-name> <res-type>javax.jms.Queue</res-type> <res-auth>Container</res-auth> </resource-ref> ... </web-app>

8. Compile the files in the webtier project and correct any syntax errors. Right-click web.xml and select Create WAR Deployment Profile, and then enter the file name LogMessageApp.deploy. Click OK. In the Profile Dependencies section, select the check box next to the MessageLoggerEJB.deploy entry. Then click the OK button to close the window. 9. Right-click LogMessageApp.deploy and deploy the application (including the dependent MessageLoggerEJB) to the OracleAS10g connection. Note that it could take several minutes to deploy the application. 10. Run the Web application to test the logic by entering one of the following URLs in your Web browser: http://localhost/logmessage/ or http://localhost/logmessage/loginservlet. Usernames and passwords are listed below. Hint: Use the Show Messages hypertext link in the application window to view messages written to the LOGMESSAGES table by the MDB. 100 102 203 King De Haan Mavris

Oracle 10g: Build J2EE Applications A-77

Practice 17-1 Solution The purpose of this practice is to create JSP clients for the EJBs that you have written in previous practices. Within practice17ske.jws, there are two projects: businesstier.jpr and webtier.jpr (the solution files are contained in practice17soln.jws). businesstier.jpr contains the Employee session EJB that you developed in practice 12, as well as the UpdateEmployee entity EJB that you created in practice 14. The webtier project contains the LoginServlet that you created in practice 5. In this practice, you put together all the knowledge to create a complete J2EE application. 1. Modify LoginServlet to test a user who logs in. In this practice, company employees are using the application. Thus, change the LoginServlet to verify the login for an employee, rather than a customer. a. In the init() method, change the data source lookup to jdbc/hrDS.
ds = (DataSource)ic.lookup("jdbc/hrDS");

b. In the doGet() method, change the heading for the human resources application and change the forms fields to accept the employee ID and employee name.
out.println("<html>"); out.println("<head><title>Login to Human Resources</title></head>"); out.println("<link rel=stylesheet href=\"css/oracle.css\" media=\"screen\"/>"); out.println("<body>" + "<form method=\"post\" " + "action=" +servleturi + ">" + "<h1 align=\"center\">Welcome to the Human Resources Application </h1>" + "<div align=\"center\">" + "<p>&nbsp;</p><p>&nbsp;</p>" + "<table border=0><tr><td><h4>Employee Id:</h4></td>" + "<td><input type=\"text\" name=\"empId\"></td></tr>" + "<tr><td><h4>Employee Name:</h4></td>" + "<td><input type=\"text\" name=\"empName\"></td></tr>" + "</table><p>" + "<input type=\"submit\" name=\"Submit\" value=\"Login\">" + "<input type=\"reset\" name=\"Reset\" value=\"Reset\">" + "</p></div></form>"); out.println("</body></html>");

2. Modify the verifyCustomer() and getOrders() methods to verifyEmployee() and getRoles(). Only employees who have a valid login will be accepted, and only employees who have an administrator role will be allowed to insert new employees (who will be added later). a. Change verifyCustomer() to verifyEmployee(), and return a jobid from this method. Pass in a connection, employee_id, and employee_name as arguments to this method. The jobid will be used to check for the administrator roles in the getRoles() method.
public synchronized String verifyEmployee(Connection conn, String employee_id, String employee_name) throws SQLException Oracle 10g: Build J2EE Applications A-78

Practice 17-1 Solution (continued) b. Change the statement to select the employee_id, last_name, and job_id from the EMPLOYEES table where the last_name is the employee_name passed to this method, and where employee_id is the employee ID passed to this method.
String jobid = null; Statement stmt = conn.createStatement(); String verifyquery = "select employee_id, last_name, job_id from employees " + "where last_name like '" + employee_name + "'" + " and employee_id like " + employee_id;

c. In the while loop, set the value of jobid to the job_id from the query. Remove the code for checking the custid value.
while (rs.next()) { jobid = rs.getString(3); } rs.close(); return jobid; }

d. Change getOrders() to getRoles(). This method will return a Boolean value, indicating whether the employee is an administrator. It will accept the connection and the job ID from the verifyEmployee() method.
public synchronized boolean getRoles(Connection conn, String job_id) throws SQLException {

e. Create a variable for this method, initialized to null, to store the value of the string returned from the query.
String jobId = null;

f. Change the prepareStatement() method (in the init() method) to select job_id from the JOBS table where the job_id is equal to the argument passed to the method. In the getRoles() method, use the setString() method to pass in the argument.
ps = conn.prepareStatement("SELECT job_id " + "FROM jobs " + "WHERE job_id = ?"); Oracle 10g: Build J2EE Applications A-79

Practice 17-1 Solution (continued)


ps.setString(1, job_id);

g. In the while loop, set the value of the variable created in step e. to the job ID that is returned from the query.
while (rs.next()) { jobId = rs.getString("JOB_ID"); }

h. If the value equals HR_REP, AD_PRES, or AD_VP, return true. Otherwise, return false.
// Close the result set object rs.close(); if ((jobId.equals("HR_REP")) || (jobId.equals("AD_PRES")) || (jobId.equals("AD_VP"))) { return true; } else { return false; }

3. Create a new method to forward the request to a JSP in the application: a. Name the method gotoPage(). It should accept an address (as string) and the HttpServletRequest and HttpServletResponse objects, and then throw the ServletException and IOException exceptions.
public void gotoPage (String address, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

b. Create a variable of type RequestDispatcher and use getServletContext().getRequestDispatcher() to assign the value of the address passed to the method.
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(address);

c. Forward the request and response by using the forward method of the RequestDispatcher variable.
dispatcher.forward(request, response); }

Oracle 10g: Build J2EE Applications A-80

Practice 17-1 Solution (continued) 4. Modify the doPost() method to include the new functionality: a. Modify the id and name variables to retrieve the value of the parameters from the doGet() methods form.

String id = request.getParameter("empId"); String name = request.getParameter("empName");

b. Create a string variable initialized to false to store a flag if the employee is an administrator.
String adminflag = "false";

c. In the try/catch block, store the return value of verifyEmployee(conn, id, name)in a string variable.
try { String jobid = verifyEmployee(conn,id,name);

d. If this variable is not null, then verify that the getRoles() method returns true.
if (jobid != null) { if (getRoles(conn, jobid)) {

e. If getRoles() returns true, then set the variable that you created in step b to true and use the setAttribute() method of the request object to create an attribute named adminflag with a value of the variable.
adminflag = "true"; request.setAttribute("adminflag", adminflag); }

f. Whether or not getRoles() returns true, the user will be able to see a list of employees. Set a request attribute to store the value of the id variable to an attribute named empid.
request.setAttribute("empid", id);

g. Call the gotoPage() method by passing in ViewEmployees.jsp as the address, and the request and response objects.
Oracle 10g: Build J2EE Applications A-81

Practice 17-1 Solution (continued)


gotoPage("ViewEmployees.jsp", request, response); }

h. If the variable created in step c is null, the employees login is invalid.

else { out.println("Invalid login. Please try again."); }

i. Eliminate the code in the method for viewing the orders, because this functionality is no longer required. j. Compile LoginServlet.java. 5. Create an EJB reference for the Employee EJB that you created in practice 12: a. Right-click web.xml in the WEB-INF folder of the webtier project and select Properties. b. Select EJB references and add a new reference. c. Supply the name as Employee, the home interface as businesstier.EmployeeHome, the remote interface as businesstier.Employee, and ensure that the type is session. Click OK. d. Open web.xml in the editor to view this reference. You can now access the EJB by using the reference java:comp/env/Employee.
<ejb-ref> <ejb-ref-name>Employee</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <home>businesstier.EmployeeHome</home> <remote>businesstier.Employee</remote> </ejb-ref>

6. Create a client for the Employee EJB: a. Navigate to EmployeeBean.java in the businesstier project. A method called getEmployeesInDept() has been added to this EJB to retrieve a vector of employees in a given department. Note that the EmployeeDetails class has been modified to retrieve the values of the id, fname, lname, email, hiredate, and jobid arguments. b. Create a new JSP in the webtier project named ViewEmployees. c. Rename the title for the JSP.
<title>View Employees</title>

Oracle 10g: Build J2EE Applications A-82

Practice 17-1 Solution (continued) d. Import the following: businesstier.Employee, businesstier.EmployeeHome, javax.naming.*, javax.ejb.CreateException, javax.rmi.PortableRemoteObject, java.rmi.RemoteException, java.util.*, businesstier.EmployeeDetails
<%@ page contentType="text/html;charset=windows-1252" import="businesstier.Employee, businesstier.EmployeeHome, javax.naming.*, javax.ejb.CreateException, javax.rmi.PortableRemoteObject, java.rmi.RemoteException, java.util.*, businesstier.EmployeeDetails" %>

e. In a declaration, create an instance variable to hold an object of Employee type.


<%! private Employee employee = null;

f. Still in the declaration, override the jspInit() method. Use a try/catch block to look up the Employee EJB by using the reference that you created in step 5.d., catching CreateException, NamingException and RemoteException. Hint: Use page 6 of this lesson as an example.
public void jspInit() { try { InitialContext ic = new InitialContext(); Object objref = ic.lookup("java:comp/env/Employee"); EmployeeHome home = (EmployeeHome)PortableRemoteObject.narrow(objref, EmployeeHome.class); employee = home.create(); } catch (RemoteException re) { re.printStackTrace(); } catch (NamingException ne) { ne.printStackTrace(); } catch (CreateException ce) { ce.printStackTrace(); } } %> Oracle 10g: Build J2EE Applications A-83

Practice 17-1 Solution (continued) g. Outside the declaration, create a variable to retrieve the value of the employee ID that is stored in the request object.
<% int empid = 0;

h. Retrieve the value of the employee ID that you set in step 4.f., by using request.getAttribute(). Assign it to an int variable. You must cast this String value to an Integer.
empid = Integer.parseInt(request.getAttribute("empid").toString());

i. Initialize an object of EmployeeDetails type to null.


EmployeeDetails emp = null;%>

j. Create a 3 row, 4 column HTML table and insert headers in the first row to display the employee id, first name, last name, and e-mail.
<table> <td>ID</td><td>First Name</td><td>LastName</td><td>Email</td>

k. In the source code editor, add a scriptlet tocreate an Enumeration of the getEmployeesInDept() methods elements.
<% Enumeration enum = employee.getEmployeesInDept(empid).elements();

l. While there are more elements in the enumeration, advance through the EmployeeDetails object that you created in step d by using the nextElement() method. Cast the return to the object that you created in step h.
while (enum.hasMoreElements()) { emp = (EmployeeDetails) enum.nextElement(); %>

m. Navigate to the second row of the HTML table and between <td> elements, retrieve the values of the id, first name, last name, and e-mail by using the methods from the EmployeeDetails object.
<tr> <td><%= <td><%= <td><%= <td><%= </tr>

emp.getId() %></td> emp.getFirstName() %></td> emp.getLastName() %></td> emp.getEmail() %></td>

Oracle 10g: Build J2EE Applications A-84

Practice 17-1 Solution (continued) n. Close the while loop.


<% }

o. Verify whether the employee is an administrator. Use request.getAttribute() to retrieve the value of adminflag. If this attribute is not equal to null, then check if the value is true. If the value is true, then create an href link in the third table row to AddEmployees.jsp. You create AddEmployees.jsp in the next step.
if (request.getAttribute("adminflag")!= null) { if (request.getAttribute("adminflag").toString().equals("true")) { %> <tr> <td><a href="AddEmployees.jsp">Insert</a></td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <% }} %> </tr>

p. Compile the businesstier project and ViewEmployees.jsp. 7. Create AddEmployees.jsp. This JSP allows an administrator to insert a new employee by using the entity bean that you created in practice 14. a. Create AddEmployees.jsp in the webtier project. b. Rename the title for the JSP.
<title>Insert Employee Details</title>

c. This JSP provides a form for completing the employee details and submits to itself. Verify whether the insert parameter is null. If it is null, then create a form as follows: i. The action for the form returns the request to this JSP. ii. Create an HTML table containing seven rows and two columns. iii. In the first column, create a text label to describe the data entered, such as Enter an Employee Id:. The second column must be a text field, with the name attribute set to empid, fname, lname, email, hdate, and jobid. These text fields do not contain any values. iv. Create the Insert button in the last row. v. After the last row, create a hidden value to provide the insert parameter as true. Hint: Use the HTML tags in the component palette for easy table and form object creation.
Oracle 10g: Build J2EE Applications A-85

Practice 17-1 Solution (continued)


<%if (request.getParameter("insert")==null) { %> <form action="AddEmployees.jsp"> <table> <tr> <td>Employee Id: </td><td><input type="text" name="empid"></td> </tr> <tr> <td>Employee First Name: </td><td><input type="text" name="fname"></td> </tr> <tr> <td>Employee Last Name: </td><td><input type="text" name="lname"></td> </tr> <tr> <td>Email: </td><td><input type="text" name="email"></td> </tr> <tr> <td>Hire Date: </td><td><input type="text" name="hdate"></td> </tr> <tr> <td>Job Id: </td><td><input type="text" name="jobid"></td> </tr> <tr><td><input type="submit" value="Insert"/></td></tr> <input type="hidden" name="insert" value="true" > </table> </form>

d. If the insert parameter is not null, and if it is true, then the user has entered data into the form. Thus, you need to insert this data by using the UpdateEmployees EJB. This time, utilize the OJSP EJB tag library to access the bean. Check for the insert parameter condition and retrieve the values of each of the text items from the form. You must use Integer.parseInt() to parse the empid value.
<% } else { int id String String String String String %> if (request.getParameter("insert").equals("true")) = Integer.parseInt(request.getParameter("empid")); fname = request.getParameter("fname").toString(); lname = request.getParameter("lname").toString(); email = request.getParameter("email").toString(); hdate = request.getParameter("hdate").toString(); jobid = request.getParameter("jobid").toString();

Oracle 10g: Build J2EE Applications A-86

Practice 17-1 Solution (continued) e. Create a reference to the EJB in the web.xml file as in step 5, this time providing businesstier.UpdateEmployeeHome as the home interface, and businesstier.UpdateEmployee as the remote interface. Give the reference a name and specify that this bean is an Entity bean.
<ejb-ref> <ejb-ref-name>UpdateEmployee</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <home>businesstier.UpdateEmployeeHome</home> <remote>businesstier.UpdateEmployee</remote> </ejb-ref>

f. In AddEmployees.jsp, place your cursor beneath the scriptlet containing the retrieval of the form values, and select the OJSP EJB category from the component palette. g. Use the UseHome tag to create a reference to the UpdateEmployees EJB. Supply an ID of entityhome, a type of businesstier.UpdateEmployeeHome, and the location as java:comp/env/<yourrefname>, where <yourrefname> is the reference name that you provided in step e.
<EJB:useHome id="entityhome" type="businesstier.UpdateEmployeeHome" location="java:comp/env/UpdateEmployee" />

h. In a scriptlet, call the create() method of UpdateEmployee by using the entityhome reference. Pass in the values retrieved from the form submission.
<%entityhome.create(id, fname, lname, email, hdate, jobid); %>

i. Supply some text to notify the user that the employee has been added, and close out the condition.
Employee Inserted! <%}%>

8.

Compile the businesstier and webtier projects and run LoginServlet for testing. Employees who are administrators are listed below. Note that there is a database constraint that employee IDs and e-mail addresses must be unique. Employee ID 100 101 102 203 Last Name King Kochhar De Haan Mavris

Oracle 10g: Build J2EE Applications A-87

Practice 17-2 Solution In this practice, you deploy the application that you created in Oracle Application Server 10g. 1. Create an EJB JAR file for the businesstier project. a. Right-click businesstier and select New. b. Expand the General category and click Deployment Profiles. Select EJB JAR File. c. Accept the default deployment profile name. d. Specify the enterprise application name as hrejb. e. Right-click the deployment profile and select Deploy to JAR file. 2. Create a WAR file for the webtier project. a. Right-click webtier and select New. b. From the Deployment Profiles category, select WAR File. c. Accept the default deployment profile name and click OK. d. Specify the context root as /hrapp and click OK. e. Right-click the deployment profile and select Deploy to WAR file. 3. Create an EAR file for the application: a. Right-click webtier and select New. b. From the Deployment Profiles category, select EAR File. c. Accept the default deployment profile name and click OK. d. Name the application hr. e. In the Application Assembly category, include the deployment profiles that you created in steps 1 and 2 and click OK. f. Right-click the deployment profile and select Deploy to EAR file. 4. Deploy the application by using Oracle Enterprise Manager Application Server Control Console: a. Navigate to http://localhost:1810 and supply the username as ias_admin and the password as welcome1. b. Select home to open the OC4J home instance page. c. Click the Applications tab and click the Deploy EAR File button. d. Browse for the application1.ear file. By default this will be in <JDEV_HOME>\jdev\mywork\practice17ske\webtier\deploy. Supply a name of practice17 for the application name and click Continue. e. Verify whether the URL binding for this application is /hrapp, and click Next. This means that you can access the application by using this shortened name. f. Enter jdbc/hrCoreDS for the JNDI location name and click Next. In practice 2, you have already mapped this data source in OC4J. g. Click Next on the following page because there is no user security defined for this application. h. Click Deploy to deploy the application. 5. Test the application by accessing the following URL: http://localhost/hrapp/loginservlet

Oracle 10g: Build J2EE Applications A-88

Practice 18-1 Solution 1. Identify three features of Web services. a. Self-describing business function b. Interfaces for a client to invoke a business function c. Service oriented d. Component based e. Language dependent
a, c, d

2. Which three of the following can be exposed as Web services with Oracle Application Server 10g? a. Stateless/stateful Java classes b. C programs c. PL/SQL stored procedures d. Stateless session EJBs e. Stateful session EJBs
a, c, d

3. SOAP is: (Choose two correct answers.) a. A heavyweight protocol b. An XML-based protocol c. Always layered over HTTP d. Request oriented and response oriented
b, d

4. Which three of the following statements are true regarding a SOAP message? a. It should have Envelope as top-level element. b. If Envelope is not present, Header should be the top-level element. c. If Header is present, then it should immediately follow the Envelope element. d. It should have a Body, but need not have a Header element. e. It should have an Envelope, Body, and Header, irrespective of their order.
a, c, d

Oracle 10g: Build J2EE Applications A-89

Practice 18-1 Solution (continued) 5. Match the elements of a SOAP message in column A to the appropriate statements given in column B. A 1. Envelope 2. Header 3. Body B a. Is a mandatory element that contains methodspecific information b. Is the top-level element in the SOAP message and contains namespace declarations c. Is an optional element that encapsulates data not specific to the method

1-b, 2-c, 3-a

6. WSDL is used for: (Choose two correct answers.) a. Locating a Web service b. Describing a Web service c. Invoking a Web service d. Sending messages
a, b

7. UDDI is: (Choose one correct answer.) a. Universal Directory Difference Information b. Universal Discovery Directory Interface c. Universal Description, Discovery, and Integration
c

8. Which of the following statements regarding UDDI are true? (Choose three correct answers.) a. An online electronic registry b. Specification for description and discovery c. A registry with key and value pair d. Uses WSDL to describe a service e. Enables search on only one criteria
a, b, d

Oracle 10g: Build J2EE Applications A-90

Practice 19-1 Solution The purpose of this practice is to expose a stateless session EJB as a Web service. You expose the ValidateCard session bean created in practice 12 as a Web service. Perform the following steps to expose the validate(String s) method of the ValidateCard session bean as a Web service. 1. Expose the ValidateCard session bean as a Web service: a. Open the workspace practice12oneske.jws. You can use this workspace if you have successfully completed practice12-1. Otherwise, use practice12onesoln.jws. b. Right-click the project; select New. Choose Web Services from the Business node of Categories and select Java Web Service from Items. c. Click OK. You see the Web Service Publishing Wizard. Click Next. d. Browse to select the ValidateCard remote interface. Click Next. e. Select the validate(java.lang.String) method and click Next. In the Web Service Endpoint change the Web Server Port to 8988, because the embedded OC4J runs on port 8988. JDeveloper picks the port number from here and generates the WSDL file. The endpoint in the WSDL file has the same port number. Click Next and then Click Finish. f. Note that the Web service, MyWebService1, and the Webservices.deploy files are generated. 2. Generate a client to test the Web service with embedded OC4J. a. Right-click the Web service and select Generate Sample Java Client. b. The sample client is generated. Check the port number in the String endpoint in the client application. c. Edit the client and add the following line to the try block of the main method:
System.out.println(stub.validate("BN349672A"));

3. Run the Web service and the client application: a. Right-click the Web service and select Run. Note: Check the port on which embedded OC4J runs and make sure that the string endpoint in the client application (created in step 2.b.) has the same port number, or change the port number in the client program. b. Right-click the client application and select Run. You should see the following line displayed in the Log window: THANKYOU FOR PROVIDING YOUR CUSTOMER CARD NUMBER Note: If you see any SOAP exceptions when you run the client application, then it is because of port conflicts. 4. Deploy the Web service to Oracle Application Server 10g by performing the following steps: a. Right-click the WebServices.deploy file in the System-Navigator and select Deploy to <connection> if a connection to Oracle Application Server 10g already exists. Otherwise, select Deploy and then select New Connection. You see the Connection Wizard. Click Next. b. Type Connection1 for Connection Name, select Oracle Application Server 10g from the Connection Type drop-down menu. Click Next.
Oracle 10g: Build J2EE Applications A-91

Practice 19-1 Solution (continued) c. Provide username and password. Click Next. d. Check the Enterprise Manager OC4J HTTP port and specify the Oracle Home directory. Click Next. e. Type welcome for the Remote Method Invocation (RMI) password and click Next. Click the Test Connection button to test your connection. Wait to see the status Success and then click Finish. f. You see the deployment messages in the Log window. Wait for the process to complete. g. Start Internet Explorer, type the following URL to go to the Enterprise Manager Application Server Control: http://localhost:1810. Enter User Name and Password. h. Click home under System Components. Click the Applications link. You will find a link for your application in the Deployed Applications list. Click the link to see the details of the deployed application. You will see the WebServices link under Web Modules. i. Note the URL binding for this application and the name of the application. In this example, the URL binding is /practice12oneske-validatecardcontext-root and the name is MyWebService1. j. You can now access the Web service with the URL http://localhost/practice12oneske-validatecard-contextroot/MyWebService1. k. You will see the Web Services home page for this service. l. Click the validate link. Enter the string BN349672A in the text field and click Invoke. m. You can see the SOAP response from the Web service.

Oracle 10g: Build J2EE Applications A-92

Practice 20-1 Solution In this practice, you are provided with most of the application code. The goal of this practice is to use J2EE declarative security mechanisms to protect access to different parts of the application. You use programmatic techniques to limit the information about an employees salary displayed to the application user (depending on the role of the user). Note: The application in this practice originates from the practice in lesson 17. Understanding the Application Open the practice20.jws workspace in the practice20 directory. There are two projects: The secure project, containing the files you will modify The securesoln project, containing the solutions for this practice Expand the secure project, and take approximately two minutes to examine the content of the following files used to configure the application security credentials: The orion-application.xml file is an OC4J applicationspecific deployment descriptor that identifies the location of the application-specific user and group data in the jazn-data.xml file. It also grants read access to the namespace to the staff role. The jazn-data.xml file contains all the users and roles for this application. This file was created by using the JAZN Admintool provided with OC4J, where each username is derived from the EMAIL column of the EMPLOYEES table, and their passwords are all set to oracle. This file defines two roles: - The managers role, which is only granted to employees in the database who have the following job IDs: AD_PRES, AD_VP, HR_REP, FI_MAN - The staff role, which is granted to all other employees. The managers role has been added as a member of the staff role because all managers are also staff. The application provides a default index.html page that is not protected, allowing users to access a common welcome page. The only hypertext link on the index page leads to the GetEmployee.jsp page, which must be password protected. The user should log in using a valid name and the password oracle. The GetEmployee.jsp uses an entity bean to retrieve information about an employee, and presents a page that allows users to add new employees or query employees by department. When employees are queried, the user is able to update or delete the employee record. Your task is to declaratively allow only managers to create and delete employees, and update employee salaries. This is achieved through a combination of using Web and EJB authorization techniques covered in this lesson. Practice Steps 1. Deploy the application to observe the default behavior. a. Compile the secure project and then right-click EmployeesWeb.deploy and deploy the application to your OracleAS10g connection. EmployeesWeb.deploy has a profile dependency on EmployeesEJB.deploy to ensure that the EJB is deployed as part of the enterprise application. b. Enter the following URL: http://localhost/secure. Note: You will find that the application has no login mechanism, and defaults to a user called JCHEN, who can perform all tasks.
Oracle 10g: Build J2EE Applications A-93

Practice 20-1 Solution (continued) 2. Create Web application security roles by using the actual role names defined in the jazndata.xml file. a. In the secure project, right-click web.xml and select the Properties menu option to display the Web Application Deployment Descriptor editor. b. Click the Security Roles section, and then click the Add button to create security roles for managers and staff. c. Select the Preview XML section to examine the <security-role> elements added to the web.xml file. Note: Do not close the Web Application Deployment Descriptor editor window.
<web-app> ... <security-role> <role-name>managers</role-name> </security-role> <security-role> <role-name>staff</role-name> </security-role> ... </web-app>

3. Enable basic authentication to be used by the OC4J container. a. Click Login Configuration and click the HTTP Basic Authentication option button, and enter Employee Application in the Realm field. b. Select the Preview XML section to examine the <login-config> element added to the web.xml file. Note: Do not close the Web Application Deployment Descriptor editor window.
<web-app> ... <login-config> <auth-method>BASIC</auth-method> <realm-name>Employee Application</realm-name> </login-config> ... </web-app>

4. Create two security constraints for the application, by defining two Web resources and their associated URL patterns and appropriate role authorizations. a. Select the Security Constraints section and click the New button. Click the Add button to create a constraint with the Web resource name GetEmployee. b. Select the GetEmployee Web resource name that you created in the previous step, and in the URL Patterns tabbed page add the following URL: /GetEmployee.jsp. c. Select the Authorization tab and select the check boxes next to the managers and the staff roles. The managers role must also be selected, otherwise the J2EE container does not recognize users with the managers role, but only their staff role.
Oracle 10g: Build J2EE Applications A-94

Practice 20-1 Solution (continued)


<web-app> ... <security-constraint> <web-resource-collection> <web-resource-name>GetEmployee</web-resource-name> <url-pattern>/GetEmployee.jsp</url-pattern> </web-resource-collection> <auth-constraint> <role-name>managers</role-name> <role-name>staff</role-name> </auth-constraint> </security-constraint> ... </web-app>

d. Select the Security Constraints section and click the New button. Click the Add button to create a second security constraint with the Web resource name: MaintainEmployee. e. Select the MaintainEmployee Web resource name, and add the following URL patterns: /Add* and /Delete*, and in the Authorization tabbed page for this second constraint, select only the check box next to the managers role. f. Select the Preview XML section to examine the two <security-constraint> elements added to the web.xml file.
<web-app> ... <security-constraint> <web-resource-collection> <web-resource-name>GetEmployee</web-resource-name> <url-pattern>/GetEmployee.jsp</url-pattern> </web-resource-collection> <auth-constraint> <role-name>managers</role-name> <role-name>staff</role-name> </auth-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name>MaintainEmployee</web-resource-name> <url-pattern>/Add*</url-pattern> <url-pattern>/Delete*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>managers</role-name> </auth-constraint> </security-constraint> ... </web-app>

g. Click the OK button to close the Web Application Deployment Descriptor editor window.
Oracle 10g: Build J2EE Applications A-95

Practice 20-1 Solution (continued) 5. Redeploy the application by using the EmployeesWeb.deploy file to your OracleAS10g connection. Before you run the application, close all Web browser windows. Then start the Web browser and enter the following URL: http://localhost/secure. 6. Click the Get Employees hypertext link to start the application. You should be prompted for a username and password in a dialog box, which has the Realm name of Employee Application. Test your application behavior with two different usernames. Use one user as a staff member only, and the other as a manager. Hint: The following users are staff members only: jchen, ngreenbe, pfay, jwhalen. The following users are managers: ldehaan, sking, nkochhar, smavris. All users have the password oracle. Alternatively, check the jazn-data.xml file in your project for other names with the staff and managers roles. 7. At this stage, all users will be able to update other employees salaries. You now modify the EJB to allow only users with the managers role to update an employees salary. a. In the secure project, right-click ejb-jar.xml and select Properties. b. In the EJB Module Editor, select the Security Roles node and click the Add button to create the managers security role entry. c. Select the Preview XML section to observe the <security-role> element added inside the <assembly-descriptor> element.
<ejb-jar> ... <assembly-descriptor> <security-role> <role-name>managers</role-name> </security-role> </assembly-descriptor> ... </ejb-jar>

d. Click Method Permissions and click the Add button to create a method permission. e. In the Create Method Permission window, shuttle the managers role to the Chosen Security Role Names area, and select the void setSalary(java.lang.Long) entry from the list in the Methods area. Then click the OK button. f. Select Preview XML and observe the <method-permission> element added inside the <assembly-descriptor> element of the bean.
<ejb-jar> ... <assembly-descriptor> <security-role> <role-name>managers</role-name> </security-role> <method-permission> <role-name>managers</role-name> <method> <ejb-name>Employees</ejb-name> Oracle 10g: Build J2EE Applications A-96

Practice 20-1 Solution (continued)


<method-intf>Local</method-intf> <method-name>setSalary</method-name> <method-params> <method-param>java.lang.Long</method-param> </method-params> </method> </method-permission> </assembly-descriptor> ... </ejb-jar>

g. Click the OK button to close the EJB Module Editor and apply the changes that you have made. 8. Redeploy the application with EmployeesWeb.deploy to your OracleAS10g application server connection. Close all your Web browser windows. Then start the Web browser and enter the following URL: http://localhost/secure and test the modification of an employees salary as a user using the managers role, and as a user with the staff role. Hint: Close the browser between login sessions. Optionally, if you have time, then you can perform the following: 9. Programmatically access and display authentication information for users after they log in. a. Open the GetEmployee.jsp file in the Code Editor, and locate the following HTML tags: <hr> <h3>Security Information</h3> <!-- Enter code here for security information --> <hr> Replace the HTML comment line <! Enter code here --> with output that resembles the following four lines of information, each with a JSP expression after the word shown: <b>Principal:</b> <%= %><br> <b>Staff:</b> <%= %><br> <b>Manager:</b> <%= %><br> <b>User :</b> <%= %><br> b. In the JSP expression for Principal, display the string information about the java.security.Principal object. Hint: Use request.getUserPrincipal().
... <hr> <h3>Security Information</h3> <b>Principal: </b><%= request.getUserPrincipal() %><br> <hr> ...

Oracle 10g: Build J2EE Applications A-97

Practice 20-1 Solution (continued) c. In the JSP expression for Staff display true if the user making the request is a member of the staff role, otherwise display false. Hint: Use request.isUserInRole(...).
... <hr> <h3>Security Information</h3> <b>Principal: </b><%= request.getUserPrincipal() %><br> <b>Staff: </b><%= request.isUserInRole("staff") %><br> <hr> ...

d. In the JSP expression for Manager, display true if the user making the request is a member of the managers role; otherwise display false. Hint: Use request.isUserInRole(...).
... <hr> <h3>Security Information</h3> <b>Principal: </b><%= request.getUserPrincipal() %><br> <b>Staff: </b><%= request.isUserInRole("staff") %><br> <b>Manager: </b><%= request.isUserInRole("managers") %><br> <hr> ...

e. In the JSP expression for the user information display the remote username. Hint: Use request.getRemoteUser().
... <hr> <h3>Security Information</h3> <b>Principal: </b><%= request.getUserPrincipal() %><br> <b>Staff: </b><%= request.isUserInRole("staff") %><br> <b>Manager: </b><%= request.isUserInRole("managers") %><br> <b>User: </b><%= request.getRemoteUser() %><br> <hr> ...

f. Compile the GetEmployee.jsp file to eliminate syntax errors. 10. Programmatically prevent the current user from seeing another employees salary when obtaining the result list after finding employees by department ID. a. Edit GetEmployeeByDept.jsp in the Code Editor. b. Search for the following JSP code: <td><%= emp.getSalary() %></td> in the file and modify this line to display the salary as a string if the current user has the managers role. Otherwise display the string n/a ("not available").

Oracle 10g: Build J2EE Applications A-98

Practice 20-1 Solution (continued)


... <td><%= (request.isUserInRole("managers") ? emp.getSalary().toString() : "n/a") %></td> ...

c. Compile the GetEmployeeByDept.jsp file to eliminate syntax errors. 11. Finally, deploy the EmployeesWeb.deploy application profile to the OracleAS10g connection. Test the application changes starting with the following URL: http://localhost/secure. Hint: Close the browser windows between the staff and managers user login sessions.

Oracle 10g: Build J2EE Applications A-99

Practice 21-1 Solution The goal of this practice is to get some experience working with container-managed transactional attributes. The application that you are using here is identical to the one that you used in the previous lesson, without all the security constraints. You still require a valid login, but all users have access to all functions, because security is not the objective of this lab. 1. Open practice21.jws in the practice21 directory, and test the application with default transaction attributes: a. Deploy the application by using the ManageTxApp.deploy file. b. Start your browser and enter the URL http://localhost/managetx to run the application. Log in as any user, for example jchen, ngreenbe, or ldehaan, with the password oracle. c. Create a new employee in department 10. Use an employee ID of 900, enter your first name and last name in the first name and last name fields, respectively, and enter a job type of IT_PROG. Enter values for all fields. d. Return to the Welcome employee page, and find all employees in department 10. e. Click the Update link and make a change to the first name and last name, and delete the last letter from the job type. This job type is invalid and generates an exception for the operation of changing the job type. But what happens to the changes to the first name and last name?
The first name and last name changes are saved in the record, even though an exception occurs when updating the invalid job id. The name changes are committed because the EJB methods have a default transaction attribute of Required. This means a transacation, for each method, will be started if one does not exist. Note: You can check the row changes using SQL*Plus or the employee query form in the application.

2. Edit the EJB and mark all methods with a transaction attribute of Required. a. Right click ejb-jar.xml and select Properties. Click Container Transactions and click the Add button to add a transaction entry. In the Create Container Transaction Entry window select the Required transaction attribute. Click Add Method, select Employees in EJB Name and select * in the methods area. Click OK. Click OK again to close the window. b. Select Preview XML to observe the <assembly-descriptor> element inside <container-transaction>. Click OK to close the window.
<ejb-jar> ... <assembly-descriptor> <container-transaction> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>*</method-name> </method> Oracle 10g: Build J2EE Applications A-100

Practice 21-1 Solution (continued)


<trans-attribute>Required</trans-attribute> </container-transaction> ... </ejb-jar>

c. Redeploy the application. d. Run the application and search for employees in department 10. Attempt to update your record again. What happens this time?
The name changes are saved. This is the same as the default case.

3. Edit the EJB and mark all methods with a transaction attribute of NotSupported. a. Right click ejb-jar.xml and select Properties. Select Container Transactions and click the Transaction Attribute field value in the existing entry. Pick the NotSupported entry from the drop-down menu. b. Select Preview XML to observe the <assembly-descriptor> element inside <container-transaction>. Click OK to close the window.
<ejb-jar> ... <assembly-descriptor> <container-transaction> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>*</method-name> </method> <trans-attribute>NotSupported</trans-attribute> </container-transaction> ... </ejb-jar>

c. Redeploy the application. d. Run the application and search for employees in department 10. Attempt to update your record again. What happens this time?
The changes are still applied to the database row, because a transaction for method is created in an unspecified context due to the absense of an existing transaction.

4. Edit the EJB module and change the existing transaction attribute entry to mark only the setXXX() methods with an attribute value of Mandatory. Select Preview XML and note the changes. Click OK to close the window. Hint: Select all the setXXX() methods.

Oracle 10g: Build J2EE Applications A-101

Practice 21-1 Solution (continued)


<ejb-jar> ... <assembly-descriptor> <container-transaction> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>setEmployee_id</method-name> <method-params> <method-param>java.lang.Long</method-param> </method-params> </method> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>setFirst_name</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </method> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>setLast_name</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </method> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>setEmail</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </method> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>setPhone_number</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </method> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>setHire_date</method-name> <method-params> <method-param>java.sql.Timestamp</method-param> </method-params> </method> <method> <ejb-name>Employees</ejb-name> Oracle 10g: Build J2EE Applications A-102

Practice 21-1 Solution (continued)


<method-intf>Local</method-intf> <method-name>setJob_id</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </method> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>setSalary</method-name> <method-params> <method-param>java.lang.Long</method-param> </method-params> </method> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>setCommission_pct</method-name> <method-params> <method-param>java.lang.Long</method-param> </method-params> </method> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>setDepartment_id</method-name> <method-params> <method-param>java.lang.Long</method-param> </method-params> </method> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>setEmployees_manager_id_</method-name> <method-params> <method-param>java.util.Collection</method-param> </method-params> </method> <method> <ejb-name>Employees</ejb-name> <method-intf>Local</method-intf> <method-name>setEmployees_manager_id</method-name> <method-params> <method-param>managetx.EmployeesLocal</method-param> </method-params> </method> <trans-attribute>Mandatory</trans-attribute> </container-transaction> ... </ejb-jar>

Oracle 10g: Build J2EE Applications A-103

Practice 21-1 Solution (continued) a. Redeploy the application. b. Run the application and search for employees in department 10. Attempt to update your record again. What is the result? Hint: Using Notepad, look for an exception at the end of the file called <ORACLE_HOME>\opmn\logs\OC4J~home~default_island~1.
The changes are not applied to the database row, and the application receives an exception. Due to the exception handling in the application you do not see the exception message. You can see the actual exception details if you open the application.log file in <ORACLE_HOME>\j2ee\home\applicationdeployments\ManageTxApp\home_default_island_1 in Wordpad.

5. Modify UpdateEmployee.jsp to use client-demarcated transactions by starting a UserTransaction before calling the entity bean methods to update the employee fields.
else if (request.getParameter("action").equals("Update")) { String fname = request.getParameter("fname"); String lname = request.getParameter("lname"); String email = request.getParameter("email"); String jobid = request.getParameter("jobid"); String salary = request.getParameter("salary"); String deptid = request.getParameter("deptid"); Context ctx = new InitialContext(); UserTransaction ut = (UserTransaction) ctx.lookup("java:comp/UserTransaction"); ut.begin(); if (emp != null) { if (!fname.equals(emp.getFirst_name())) emp.setFirst_name(fname); if (!lname.equals(emp.getLast_name())) emp.setLast_name(lname); if (!email.equals(emp.getEmail())) emp.setEmail(email); if (!jobid.equals(emp.getJob_id())) emp.setJob_id(jobid); if (!salary.equals(emp.getSalary().toString())) emp.setSalary(new Long(salary)); if (!deptid.equals((emp.getDepartment_id()!= null) ? emp.getDepartment_id().toString(): "null")) emp.setDepartment_id(new Long(deptid)); %> <b>Employee Updated using Web transaction!</b><br> <% ut.commit(); } else { out.println("Error: emp not found"); ut.rollback(); } } Oracle 10g: Build J2EE Applications A-104

Practice 21-1 Solution (continued) Hint: Import javax.naming.* and javax.transaction.* to look up a UserTransaction. a. Redeploy the application. b. Run the application, search for employees in department 10. Attempt to update your record again. What happens this time?
The requested changes are made to the database row. If you get an exception from any of the called methods between the start and end of the transaction all changes are rolledback. You can test an exception scenario by entering an invalid job id, like XXXX, in the appropriate field of the update employee form.

Oracle 10g: Build J2EE Applications A-105

Practice 21-1 Solution (continued) Optionally, if you have time, then you can perform the following: 6. Create a new stateful session EJB called MaintainEmployee, and set the transactions to be bean managed so that you can create a user transaction to demarcate the transaction boundaries. Make sure that you only use the local interfaces.
// MaintainEmployeeLocalHome.java package managetx; import javax.ejb.EJBLocalHome; import javax.ejb.CreateException; public interface MaintainEmployeeLocalHome extends EJBLocalHome { MaintainEmployeeLocal create() throws CreateException; } // MaintainEmployeeLocal.java package managetx; import javax.ejb.EJBLocalObject; public interface MaintainEmployeeLocal extends EJBLocalObject { } // MaintainEmployeeBean.java package managetx; import javax.ejb.SessionBean; import javax.ejb.SessionContext; public class MaintainEmployeeBean implements SessionBean { private SessionContext context; public public public public void void void void ejbCreate() {} ejbActivate() {} ejbPassivate() {} ejbRemove() {}

public void setSessionContext(SessionContext ctx) { this.context = ctx; } }

a. Add a component method called updateEmployee() that receives the following arguments: java.lang.Long employee_id, java.lang.String first_name, java.lang.String last_name, java.lang.String email, java.lang.String job_id, java.lang.Long salary, java.lang.Long department_id, and returns a java.lang.String.
Oracle 10g: Build J2EE Applications A-106

Practice 21-1 Solution (continued)


// MaintainEmployeeLocal.java package managetx; import javax.ejb.EJBLocalObject; public interface MaintainEmployeeLocal extends EJBLocalObject { String updateEmployee(Long employee_id, String first_name, String last_name, String email, String job_id, Long salary, Long department_id); } // MaintainEmployeeBean.java package managetx; import javax.ejb.SessionBean; import javax.ejb.SessionContext; public class MaintainEmployeeBean implements SessionBean { private SessionContext context; public public public public void void void void ejbCreate() {} ejbActivate() {} ejbPassivate() {} ejbRemove() {}

public void setSessionContext(SessionContext ctx) { this.context = ctx; } public String updateEmployee(Long employee_id, String first_name, String last_name, String email, String job_id, Long salary, Long department_id) { return null; } }

b. In the MaintainEmployee bean, create a local EJB reference to the entity bean called Employees.
// MaintainEmployeeBean.java package managetx; import javax.ejb.SessionBean; import javax.ejb.SessionContext; import managetx.EmployeesLocalHome; import managetx.EmployeesLocal; import javax.naming.InitialContext; import javax.naming.NamingException; Oracle 10g: Build J2EE Applications A-107

Practice 21-1 Solution (continued)


public class MaintainEmployeeBean implements SessionBean { private SessionContext context; public public public public void void void void ejbCreate() {} ejbActivate() {} ejbPassivate() {} ejbRemove() {}

public void setSessionContext(SessionContext ctx) { this.context = ctx; } public String updateEmployee(Long employee_id, String first_name, String last_name, String email, String job_id, Long salary, Long department_id) { return null; } private EmployeesLocalHome getEmployeesLocalHome() throws NamingException { final InitialContext context = new InitialContext(); return (EmployeesLocalHome) context.lookup( "java:comp/env/ejb/EmployeesLocal"); } }

c. Implement the updateEmployee() method to look up the UserTransaction interface by using java:comp/UserTransaction, and start the transaction. Note: Import javax.transaction.UserTransaction.
... import javax.transaction.UserTransaction; ... public String updateEmployee(Long employee_id, String first_name, String last_name, String email, String job_id, Long salary, Long department_id) { String result = "Employee Updated"; UserTransaction ut = null; try { ut = context.getUserTransaction(); ut.begin(); } catch (Exception e) { Oracle 10g: Build J2EE Applications A-108

Practice 21-1 Solution (continued)


e.printStackTrace(); result = e.getMessage(); } return result; }

d. Modify the updateEmployee() method to look up the entity bean by using the getEmployeesLocalHome() method that was added when you created the local EJB reference. Note: Import managetx.EmployeesLocal.
public String updateEmployee(Long employee_id, String first_name, String last_name, String email, String job_id, Long salary, Long department_id) { String result = "Employee Updated"; UserTransaction ut = null; try { ut = context.getUserTransaction(); ut.begin(); EmployeesLocalHome empHome = this.getEmployeesLocalHome(); EmployeesLocal emp = empHome.findByPrimaryKey(employee_id); } catch (Exception e) { e.printStackTrace(); result = e.getMessage(); } return result; }

e. Add code to updateEmployee(). Change the columns corresponding to the arguments by calling the appropriate set methods of the entity bean instance that you found. Enclose this code in a try/catch block and return the string Employee Updated if successful. Otherwise, return the exception message text. Hints: Copy or look at the code in the UpdateEmployee.jsp file. Make sure you use the user transaction object to commit the transaction on success or roll back when there is a failure.
public String updateEmployee(Long employee_id, String first_name, String last_name, String email, String job_id, Long salary, Long department_id) { String result = "Employee Updated"; UserTransaction ut = null; try Oracle 10g: Build J2EE Applications A-109

Practice 21-1 Solution (continued)


{ ut = context.getUserTransaction(); ut.begin(); EmployeesLocalHome empHome = this.getEmployeesLocalHome(); EmployeesLocal emp = empHome.findByPrimaryKey(employee_id); if (!first_name.equals(emp.getFirst_name())) emp.setFirst_name(first_name); if (!last_name.equals(emp.getLast_name())) emp.setLast_name(last_name); if (!email.equals(emp.getEmail())) emp.setEmail(email); if (!job_id.equals(emp.getJob_id())) emp.setJob_id(job_id); if (!salary.toString().equals(emp.getSalary().toString())) emp.setSalary(salary); if (!department_id.toString().equals( (emp.getDepartment_id()!= null) ? emp.getDepartment_id().toString(): "null")) emp.setDepartment_id(department_id); ut.commit(); } catch (Exception e) { try { ut.rollback(); } catch (Exception txe) {} e.printStackTrace(); result = e.getMessage(); } return result; }

7. Modify the web.xml file to add a local EJB reference with a JNDI name of ejb/local/MaintainEmployee for the MaintainEmployee session bean. Note: Do not overwrite the EJB local reference for Employees entity bean.
<web-app> ... <ejb-local-ref> <ejb-ref-name>ejb/local/MaintainEmployee</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <local-home>managetx.MaintainEmployeeLocalHome</local-home> <local>managetx.MaintainEmployeeLocal</local> <ejb-link>MaintainEmployee</ejb-link> </ejb-local-ref> </web-app>

8. Modify UpdateEmployee.jsp to create a MaintainEmployee EJB instance by using the JNDI name created in the previous step. a. Replace the code that uses the entity bean to update the employee by calling the session beans updateEmployee() method.

Oracle 10g: Build J2EE Applications A-110

Practice 21-1 Solution (continued)


else if (request.getParameter("action").equals("Update")) { String fname = request.getParameter("fname"); String lname = request.getParameter("lname"); String email = request.getParameter("email"); String jobid = request.getParameter("jobid"); String salary = request.getParameter("salary"); String deptid = request.getParameter("deptid"); MaintainEmployeeLocal maintEmp = null; %> <EJB:useHome id="maintEmpHome" type="managetx.MaintainEmployeeLocalHome" location="java:comp/env/ejb/local/MaintainEmployee" local="true" /> <% maintEmp = maintEmpHome.create(); %> <%= maintEmp.updateEmployee(empId, fname, lname, email, jobid, new Long(salary), new Long(deptid)) %> <% }

b. Redeploy the application. c. Run the application, search for employees in department 10. Attempt to update your record again. What is the result?
The changes to the record updated are successfully made, as the session bean creates the transaction context in which the entity bean method execute for a complete transaction. Note: The solution file for this part is in the managetxsoln.jpr project, and the file is called UpdateEmployeeWithSessionBean.jsp. To use this implementation in the solution: 1) Rename UpdateEmployee.jsp to UpdateEmployee_Web.jsp 2) Rename UpdateEmployeeWithSessionBean.jsp to UpdateEmployee.jsp 3) Deploy the application and run it again.

Oracle 10g: Build J2EE Applications A-111

Schema Descriptions

Copyright 2005, Oracle. All rights reserved.

Order Entry Schema CUSTOMERS CUSTOMER_ID CUST_FIRST_NAME CUST_LAST_NAME CUST_ADDRESS PHONE_NUMBERS NLS_LANGUAGE NLS_TERRITORY CREDIT_LIMIT CUST_EMAIL ACCOUNT_MGR_ID CUST_GEO_LOCATION STATUS NUMBER(6) VARCHAR2(20) VARCHAR2(20) CUST_ADDRESS_TYP PHONE_LIST_TYP VARCHAR2(3) VARCHAR2(30) NUMBER(9,2) VARCHAR2(30) NUMBER(6) MDSYS.SDO_GEOMETRY VARCHAR2(10)

To Product Media Schema

ORDERS ORDER_ID ORDER_DATE ORDER_MODE CUSTOMER_ID ORDER_STATUS ORDER_TOTAL SALES_REP_ID PROMOTION_ID NUMBER(12) TIMESTAMP(6) VARCHAR2(8) NUMBER(6) NUMBER(2) NUMBER(8,2) NUMBER(6) NUMBER(6)

PRODUCT_INFORMATION NUMBER(6) PRODUCT_ID VARCHAR2(50) PRODUCT_NAME PRODUCT_DESCRIPTION VARCHAR2(2000) NUMBER(2) CATEGORY_ID NUMBER(1) WEIGHT_CLASS INTERVAL WARRANTY_PERIOD NUMBER(6) SUPPLIER_ID VARCHAR2(20) PRODUCT_STATUS NUMBER(8,2) LIST_PRICE NUMBER(8,2) MIN_PRICE VARCHAR2(50) CATALOG_URL

ORDER_ITEMS ORDER_ID LINE_ITEM_ID PRODUCT_ID UNIT_PRICE QUANTITY DISCOUNT_UNIT_PRICE NUMBER(12) NUMBER(3) NUMBER(6) NUMBER(8,2) NUMBER(8) NUMBER(8,2)

Oracle 10g: Build J2EE Applications B-2

Human Resources Schema JOB_HISTORY EMPLOYEE_ID START_DATE END_DATE JOB_ID DEPARTMENT_ID NUMBER(6) DATE DATE VARCHAR2(10) NUMBER(4) JOB_ID JOB_TITLE MIN_SALARY MAX_SALARY JOBS VARCHAR2(10) VARCHAR2(35) NUMBER(6) NUMBER(6)

EMPLOYEES EMPLOYEE_ID FIRST_NAME LAST_NAME EMAIL PHONE_NUMBER HIRE_DATE JOB_ID SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID NUMBER(6) VARCHAR2(20) VARCHAR2(25) VARCHAR2(25) VARCHAR2(20) DATE VARCHAR2(10) NUMBER(8,2) NUMBER(2,2) NUMBER(6) NUMBER(4)

DEPARTMENTS DEPARTMENT_ID DEPARTMENT_NAME MANAGER_ID LOCATION_ID NUMBER(4) VARCHAR2(30) NUMBER(6) NUMBER(4)

COUNTRIES COUNTRY_ID COUNTRY_NAME REGION_ID CHAR(2) VARCHAR2(40) NUMBER

LOCATIONS LOCATION_ID STREET_ADDRESS POSTAL_CODE CITY STATE_PROVINCE COUNTRY_ID NUMBER(4) VARCHAR2(40) VARCHAR2(12) VARCHAR2(30) VARCHAR2(25) CHAR(2)

REGIONS REGION_ID REGION_NAME NUMBER VARCHAR2(25)

Oracle 10g: Build J2EE Applications B-3

____________________ C Oracle JDeveloper 10g Quick Reference ____________________

Oracle JDeveloper 10g Quick Reference


When you start JDeveloper in Windows (jdevw.exe), you see the following components: A Menu and toolbar for managing files A System Navigator (the default location is the top-left corner of the integrated development environment [IDE]): This displays the files that you have opened. An Applications Navigator (the same location as System Navigator): This displays applications and logical groupings of projects in the application. Applications Navigator organizes the projects in terms of higher-level logical components. In System Navigator, you work closely with files. In Applications Navigator, you work with logical groupings. A Connections Navigator: This displays your connections to application server, database, and so on. You can define new connections and edit existing connections from this navigator. A Structure Pane (the default location is below the System Navigator): This displays the structure of a file, allowing quick access to a files various methods, imports, and other content. The Code Editor window that displays the code of the selected file A Message window that contains details about the compilation, running, and debugging of a file. If you do not see the message window, then click View menu and then click Log.

Creating New Files


In Oracle JDeveloper 10g, workspaces and projects are used to organize the files that you need for your application. You can have multiple workspaces open in the Navigator. To effectively work with files in JDeveloper, projects are used to work with individual files, whereas workspaces are used to manage one or more projects. Therefore, you must have a workspace before you can create projects. Creating a new workspace and project From the JDeveloper main menu, select File > New. The New Gallery opens. In the Categories tree, expand the General node and select Workspaces. In the Items list, double-click Workspace. In the Create Workspace dialog box, enter the name and location of the new workspace, and make sure that the Add a New Empty Project check box is selected. For more information, press F1 or click Help from within the dialog box. Click OK to close the dialog box. In the Create Project dialog box, enter the name and location of the new project. Click OK to close the dialog box and return to the Navigator. Alternatively, to bypass the New Gallery, right-click Workspaces in the System Navigator and select New Workspace to create a workspace. Creating a new empty project and adding it to the selected workspace In the System Navigator, select the workspace within which the project will appear. From the main menu, choose File > New, or right-click and choose New. The New Gallery opens. In the Categories tree, select General. In the Items list, double-click Empty Project. In the New Project dialog box, enter the projects path and file name. To select an existing directory, click Browse. Click OK. To alter project properties for this particular project, right-click the file name and select Project Settings. Alternatively, to bypass the New Gallery, select the workspace in the Navigator, right-click, and choose New Empty Project.
Oracle 10g: Build J2EE Applications C-2

Note that the default directory path stores workspace and project files in a folder named mywork within the JDeveloper directory structure. You can also choose to store your files outside this structure, by specifying a directory in the dialog box. Creating a new empty class and adding it to a project In the System Navigator, select the project, package, or directory within which the class will appear. Right-click and select New Java Class. Alternatively, you can select File > New. The New Gallery opens. In the Categories tree, select General. In the Items list, double-click Java Class. In the New Class dialog box, enter the class name, the package name, and the class to extend. Select attributes as needed. For more information, press F1 or click Help from within the dialog box. Click OK to close the dialog box. A new empty class appears in the selected project. Creating a new servlet and adding it to a project In the System Navigator, select the project. From the JDeveloper main menu, select File > New. The New Gallery opens. In the Categories tree, expand the Web Tier node and select Servlets. In the Items list, double-click HTTP Servlet. Follow the steps in the wizard to complete the new servlet. For more information, press F1 or click Help from within the wizard. Creating a new JSP and adding it to a project In the System Navigator, select the project. From the JDeveloper main menu, select File > New. The New Gallery opens. In the Categories tree, expand the Web Tier node and select JavaServer Pages (JSP). In the Items list, double-click JSP Page. Enter the details for the new JSP, and click OK. Creating a new Enterprise JavaBean and adding it to a project In the System Navigator, select the project. From the JDeveloper main menu, select File > New. The New Gallery opens. In the Categories tree, expand the Business Tier node and select Enterprise JavaBeans (EJB). In the Items list, double-click the type of EJB you want to create. Follow the steps in the wizard to finish creating the EJB. For more information at any time, press F1 or click Help from within the wizard.

Opening and Modifying Files


Opening an existing workspace and adding it to the Navigator In the System Navigator, select the Workspaces node. From the main menu, select File > Open, or click the Open icon in the toolbar. In the Open dialog box, make sure that the Add to project <project name> check box is selected. Navigate to the workspace file and select it. Be sure that the file type field either specifies .jws files or allows all types to be displayed. Click Open. The workspace is now added to the list of workspaces in the Navigator. Opening an existing project and adding it to a workspace In the System Navigator, select the workspace to which the project will be added. From the main menu, select File > Open, or click the Open icon in the toolbar. In the Open dialog box, make sure that the Add to project <project name> check box is selected. Navigate to the project file and select it. Be sure that the file type field either specifies .jpr files or allows all types to be displayed. Click Open. The project is now added to the selected workspace.
Oracle 10g: Build J2EE Applications C-3

Adding existing files from the file system or archive file in the System Navigator, select File > Open from the main menu, or Click the Add to icon choose Projects > Add to <your project> from the main menu. Editing the project settings Right-click the project and select Project Properties from the context menu. Defining a new database connection From the main menu, select File > New, or right-click and choose New. The New Gallery opens. In the Categories list, expand the General node and select Connections. In the Items list, doubleclick Database Connection to open the Connection Wizard. Click Next. On the Type page, enter a name for the connection and select a type from the drop-down list. The type you select here determines the information that you will be able to enter later. Click Next. On the Authentication page, enter a username, a password, and, optionally, a role. Click Next. On the Connection page, enter the connection details as requested, which vary depending upon the connection type. Note that when you are working with third-party Java Database Connectivity (JDBC) drivers, you can register a new driver directly from this page. Click Next. On the Test page, click Test Connection. JDeveloper checks the connection by using the information you provided. If the test succeeds, a success message appears in the status text area. If the test does not succeed, an error appears. When the test succeeds, click Finish. The Connection Wizard closes. The new connection name appears under the Database node in the Navigator. Alternatively, to bypass the New Gallery, expand the Connections node in the Navigator, select Database, right-click, and choose New Connection. Creating an application server connection For deployment to local DCM, the Oracle Application Server 10g must be installed on the same machine as JDeveloper or JDeveloper must be installed on a machine that is one of the nodes in an Oracle Application Server 10g cluster. To create a connection to an Oracle Application Server 10g instance via Distributed Configuration Management (DCM): In the Connections Navigator, right-click Application Server. Choose New Application Server Connection from the context menu. The Connection Wizard Welcome page is displayed. Click Next. Enter a Connection Name for this connection. In the Connection Type list, select Oracle Application Server 10g. Click Next. Provide the username and password for authentication. Click Next. In the Remote Servers Oracle Home Directory field, enter the Oracle Home location. Click Next and provide the Remote Method Invocation (RMI) server information. Click Next. Click the Test Connection button to test your connection. Click Finish when you see the message success.

Oracle 10g: Build J2EE Applications C-4

BMP Entity EJBs J2EE Connector Architecture

Copyright 2005, Oracle. All rights reserved.

BMP Bean: Example


The example in this lesson creates a BMP entity bean with the following components: Remote interface: JobsBMP Home interface: JobsBMPHome Bean class: JobsBMPBean Primary key class: JobsBMPPK Exception class: JobSalException Deployment descriptor: ejb-jar.xml Client for the JobsBMP bean: JobsBMPClient

Copyright 2005, Oracle. All rights reserved.

BMP Bean: Example The entity bean example that is used in this lesson is based on the JOBS table. The JOBS table is a relational table that contains the job_id, job_title, min_salary, and max_salary columns. The description of this table and other tables used in this course are detailed in Appendix B.

Oracle 10g: Build J2EE Applications D-2

Remote Interface: JobsBMP


... public interface JobsBMP extends EJBObject { void incrMinSal(double amt) throws JobSalException, RemoteException; void incrMaxSal(double amt) throws RemoteException; String getJobTitle()throws RemoteException; void setJobTitle(String title)throws RemoteException; double getMinSal()throws RemoteException; void setMinSal(double amt)throws RemoteException; double getMaxSal()throws RemoteException; void setMaxSal(double amt)throws RemoteException; }

Copyright 2005, Oracle. All rights reserved.

Remote Interface: JobsBMP.java The first component that is discussed is the remote interface. The code in the slide shows the remote interface JobsBMP. The container implements this interface, and the implemented object is EJBObject, which is used by the clients to invoke bean methods. The interface should import javax.ejb.EJBObject and java.rmi.RemoteException. The two import statements are necessary because the remote interface extends the EJBObject interface and the methods declared throw RemoteException. All methods that are defined in an interface are public by default. The remote interface declares two business methods (highlighted in blue) incrMinSal() and incrMaxSal() to increase the minimum and maximum salaries by the specified amount. The incrMinSal()method throws a user-defined exception JobSalException in addition to the remote exception. The JOBS table contains the following columns: job_id, job_title, min_salary, and max_salary. The remote interface declares the accessor and mutator methods (highlighted in red) for the job_title, min_salary, and max_salary columns. Note: In this lesson, we use remote interfaces. Although an EJB can define both local and remote interfaces, it is not a common practice. If you are in doubt, define remote access to the bean because of scalability and isolation.
Oracle 10g: Build J2EE Applications D-3

Home Interface: JobsBMPHome


... public interface JobsBMPHome extends EJBHome { JobsBMP create() throws RemoteException, CreateException; JobsBMP create(String id, String title, double minSal, double maxSal) throws CreateException,RemoteException; JobsBMP findByPrimaryKey(JobsBMPPK primKey) throws FinderException, RemoteException; Collection findByMaxSalLimit (double salLimit) throws FinderException, RemoteException; double getAvgMaxSal() throws JobSalException, RemoteException; }

Copyright 2005, Oracle. All rights reserved.

Home Interface: JobsBMPHome The slide shows the code for the home interface JobsBMPHome. This interface is implemented by the Enterprise JavaBeans (EJB) server and the implemented object is the home object. This object is the factory that is responsible for creating EJB objects. The home interface should import javax.ejb.EJBHome, java.util.Collection, and java.rmi.RemoteException. The home interface extends the EJBHome interface. All the methods declared in the home interface must throw the RemoteException exception. java.util.Collection is imported because one of the methods in the home interface (findByMaxSalLimit()) has Collection as its return type. You have already learned that a client uses the home interface reference to create, find, or destroy entity objects. The home interface shown in the slide contains the create() and find() methods. The home interface declares a single create()method that takes the parameters that are necessary for creating a record in the underlying JOBS database table. This method throws the CreateException exception. You should define a corresponding ejbCreate() method in the bean class.

Oracle 10g: Build J2EE Applications D-4

Home Interface: JobsBMPHome (continued) JobsBMPPK is the primary key class that is used in this example. You will see the class definition later in this lesson. An instance of this class is passed as parameter to the findByPrimaryKey()method. The findByPrimaryKey()method finds an entity bean that can be uniquely identified with the given key value, and returns a reference of the beans remote interface. The findByMaxSalLimit() method takes a salary limit value as parameter and returns the records that have the maximum salary more than the specified value. Because this may result in more than one row, the return type of this method is Collection. If they cannot find an entity bean instance with the matching value, then the finder methods throw FinderException. getAvgMaxSal()is a home method that is not specific to any particular bean instance. It obtains the average of the max_salary column of the JOBS table. This method throws the user-defined exception JobSalException.

Oracle 10g: Build J2EE Applications D-5

Primary Key Class: JobsBMPPK

import java.io.Serializable; public class JobsBMPPK implements Serializable { public String jobId; public JobsBMPPK(String id) { this.jobId = id; } public boolean equals(Object job) {...} public int hashCode() { return super.hashCode(); } public String toString() { return jobId; } }

Copyright 2005, Oracle. All rights reserved.

Primary Key Class: JobsBMPPK Because the JobsBMPPK primary key class implements the java.io.Serializable interface, the package must be imported. The jobId instance variable is used to locate specific JobsBMP entities or records in the database. This jobId variable maps to the equivalent attribute in the JobsBMPBean bean class that is defined later in this lesson. The EJB specification requires that the fields in the primary key class be declared public. The constructor sets the primary key value to the specified parameter value. The mandatory equals() method compares two cached entity beans by using the primary key to determine whether the two represent the same row in the database. The mandatory hashCode() method stores the primary key internally as a hashtable. The above mandatory methods are invoked only by the container.

Oracle 10g: Build J2EE Applications D-6

User-Defined Exception: JobSalException


public class JobSalException extends Exception { public JobSalException() { super(); } public JobSalException(Exception e) { super(e.toString()); } public JobSalException(String s) { super(s); } }

Copyright 2005, Oracle. All rights reserved.

User-Defined Exception: JobSalException The example in the slide shows the code to create a JobSalException user-defined exception. The incrMinSal(double amt) method throws the JobSalException exception if you try to increase min_salary such that it becomes greater than max_salary. This exception takes a string value as its parameter and passes it to the Exception class. This exception is raised at various locations in the bean class implementation. There are overloaded constructors to throw the exception with a specific string from any method in the bean class.

Oracle 10g: Build J2EE Applications D-7

Bean Class: JobsBMPBean


... public class JobsBMPBean implements EntityBean { public String id; public String jobTitle; public double maxSal; public double minSal; private Connection conn = null; private EntityContext context; private PreparedStatement ps = null; private ResultSet rset = null; public JobsBMPBean() { System.out.println("New bean instance created"); } ...

Copyright 2005, Oracle. All rights reserved.

Bean Class: JobsBMPBean The code in the slide is part of the bean class implementation JobsBMPBean. The bean implements the EntityBean interface. You import the following packages that are required for an entity bean to perform Java Database Connectivity (JDBC) operations and to access other classes and interfaces that are used in the bean implementation: The javax.ejb package for the interfaces and classes: EntityBean, EntityContext, and ObjectNotFoundException. The java.sql package for the Connection, PreparedStatement, and ResultSet classes are required for performing SQL operations for persistence management. The javax.sql package for using the data source. The java.util package for supporting the Collection type, which is the return type of the home and finder methods in this example. The javax.naming package for looking up the resources such as DataSource. Instance variables are declared for holding the context of the entity bean instance, the connection to the database, and the fields of the JOBS table. The no-arg constructor prints a message indicating that a new bean instance is created.
Oracle 10g: Build J2EE Applications D-8

Bean Class: JobsBMPBean


... public JobsBMPPK ejbCreate(String id, String title, double minSal, double maxSal) { try { this.id = id; this.jobTitle = title; this.minSal = minSal; this.maxSal = maxSal; conn = getConnection(); ps = conn.prepareStatement("INSERT INTO jobs VALUES(?,?,?,?)"); ps.setString(1, id); ps.setString(2, jobTitle); ps.setDouble(3, minSal); ps.setDouble(4, maxSal); ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } finally { closeConnection(); } return new JobsBMPPK(id); } ...

Copyright 2005, Oracle. All rights reserved.

Bean Class: JobsBMPBean (continued) The code in the slide shows the implementation of the ejbCreate()method. The ejbCreate()method corresponds to the create()method that is declared in the home interface. The ejbCreate() method takes values for the job ID, job title, minimum salary, and maximum salary as parameters. A row is inserted into the table with these details. This method returns the primary key type, JobsBMPPK corresponding to the inserted row.

Oracle 10g: Build J2EE Applications D-9

create() and ejbCreate()


EJB Container 1 create() EJB Object Client 5 EJB object 2 ejbCreate() Home object primary key 4
Entity Bean instance

Table in database
Copyright 2005, Oracle. All rights reserved.

create() and ejbCreate() The ejbCreate() method in the bean class returns the primary key, whereas the create()method in the home interface returns a reference to the EJB object (JobsBMP). 1. The client requires an EJB object to invoke the methods on the bean. Therefore, the client invokes the create()method. 2. The home object is the factory for creating EJB objects. When a client invokes the create()method, the home object in turn invokes the ejbCreate()method of the bean to create an instance of the bean. The bean instance is created to represent database data. 3. This bean instance should be uniquely identified by the container so that it can be searched or removed from the pool of instances. Therefore, when the ejbCreate()method is invoked by the home object, the bean returns a primary key to the container. 4. After the home object has the primary key, it generates an EJB object. 5. The generated EJB object is returned to the client so that the business methods can be invoked. Therefore, the ejbCreate()method in the bean class returns the primary key, whereas the create()method in the home interface returns a reference to the EJB object.
Oracle 10g: Build J2EE Applications D-10

Bean Class: JobsBMPBean


public void ejbPostCreate(String id, String title, double minSal, double maxSal) { } public JobsBMPPK ejbFindByPrimaryKey(JobsBMPPK primKey) { try { conn = getConnection(); ps = conn.prepareStatement( "SELECT job_id FROM jobs WHERE job_id = ?"); ps.setString(1, primKey.toString()); rset = ps.executeQuery(); if (!rset.next()) { throw new ObjectNotFoundException("no job with job ID " + primKey); } ps.close(); } catch (Exception e) { ... } finally { closeConnection(); } return primKey; }

Copyright 2005, Oracle. All rights reserved.

Bean Class: JobsBMPBean The ejbPostCreate()method is called after the ejbCreate()method. Your bean must have one ejbPostCreate()for each ejbCreate()method. You can implement this method to perform any explicit initialization, for setting transaction-related parameters, and so on. The ejbFindByPrimaryKey()method takes the primary key as a parameter. The JOBS table is searched to locate the row with the given job_id as primary key. If the row with the given job_id is not found, then the ObjectNotFoundException exception, which is a subclass of the FinderException exception, is thrown with a message that the job with the given job_id is not found. If the row is found, then the primary key is returned from the method. The method in the example is only testing for a nonexistent row. You can add code to test for more than one matching record found in the table. Finally, the connections are closed.

Oracle 10g: Build J2EE Applications D-11

Bean Class: JobsBMPBean


public void ejbActivate() { } public void ejbPassivate() { } public void setEntityContext(EntityContext ctx) { this.context = ctx; } public void unsetEntityContext() { this.context = null; } public void ejbRemove(){ JobsBMPPK jobId = (JobsBMPPK)context.getPrimaryKey(); try { conn = getConnection(); ps = conn.prepareStatement("DELETE FROM jobs WHERE job_id = ?"); ps.setString(1, jobId.toString()); ps.executeUpdate(); } catch (Exception e1) {...} finally { closeConnection(); } }

Copyright 2005, Oracle. All rights reserved.

Bean Class: JobsBMPBean (continued) The code in the slide shows the callback methods in the bean class. The setEntityContext()method initializes the context of the bean instance. This method associates the bean with context information and is invoked only once by the container when the bean is initialized. The unsetEntityContext() method releases the resources that are not needed by the bean instance when it is destroyed and dissociates the bean from its environment context. The ejbActivate() and ejbPassivate() methods have null implementation, and are invoked by the container before and after an entity bean is swapped out and into the temporary storage. The ejbRemove() method is invoked by the container to remove a bean instance when the client invokes the remove() method on the home object. Because a bean instance can be assigned to a different entity object after it reaches the pool of instances, the method should ensure that it is removing the correct instance. The jobId is obtained from the getPrimaryKey() method of the entity context that is saved with the setEntityContext() method. Then, the JOBS table is searched to find existing records matching with the given primary key, and any such records are deleted. The RemoveException exception is thrown if an attempt is made to remove an EJB object that is not allowed to be removed by the enterprise bean or the container.
Oracle 10g: Build J2EE Applications D-12

Bean Class: JobsBMPBean

public void ejbLoad() { JobsBMPPK key=(JobsBMPPK)context.getPrimaryKey(); this.id = key.jobId; try { conn = getConnection(); ps = conn.prepareStatement( "SELECT job_title,min_salary, max_salary " + "FROM jobs WHERE job_id = ? "); ps.setString(1, id); rset = ps.executeQuery(); rset.next(); jobTitle = rset.getString("job_title"); minSal = rset.getDouble("min_salary"); maxSal = rset.getDouble("max_salary"); } ... }

Copyright 2005, Oracle. All rights reserved.

Bean Class: JobsBMPBean (continued) The code in the slide shows the ejbLoad() method. This method is developed by the bean developer in a BMP entity bean. This method loads the data that is saved within the persistent storage into the bean. The container invokes this method within a transaction when the data should be reinitialized from the database. This normally occurs after the transaction begins. You obtain jobId from the getPrimaryKey() method of the entity context that is saved with the setEntityContext() method. You then search the JOBS table to find the record that matches the given primary key. Next, you load this record into the instance variables that are declared at the beginning of the bean class implementation definition.

Oracle 10g: Build J2EE Applications D-13

Bean Class: JobsBMPBean

public void ejbStore() { JobsBMPPK key= (JobsBMPPK)context.getPrimaryKey(); String id = key.jobId; try { conn = getConnection(); ps = conn.prepareStatement( "UPDATE jobs SET job_title=?, min_salary=?, max_salary=? WHERE job_id = ?"); ps.setString(1, jobTitle); ps.setDouble(2, minSal); ps.setDouble(3, maxSal); ps.setString(4, id); ps.executeUpdate(); } ... }

Copyright 2005, Oracle. All rights reserved.

Bean Class: JobsBMPBean (continued) The code in the slide shows the ejbStore() method. This method stores the data that is represented by the in-memory entity bean instance into the persistent storage. The container invokes this method immediately before a transaction commits, or when the bean is removed, to save the existing values of the persistent data. The ID is obtained from the getPrimaryKey() method of the entity context that is saved with the setEntityContext() method. Then the JOBS table is searched to find existing records that match the given primary key and any such records are updated. In the above example, all the columns except for one are being modified. If only a few columns are to be modified, then the bean can optimize the update by specifying the column names in the UPDATE statement.

Oracle 10g: Build J2EE Applications D-14

Bean Class: JobsBMPBean


public void incrMinSal(double amt) throws JobSalException { if ((minSal + amt) > maxSal) { throw new JobSalException ("You cannot increase min salary to be more than " + maxSal);} else { minSal += amt; } } public void incrMaxSal(double amt) { maxSal += amt; } public String getJobTitle() { return jobTitle; } public void setJobTitle(String title) { this.jobTitle = title; } public double getMinSal() { return minSal; }

Copyright 2005, Oracle. All rights reserved.

Bean Class: JobsBMPBean (continued) The code in the slide shows the implementation for business methods, accessor methods, and mutator methods of the bean class implementation JobsBMPBean. These methods are declared in the remote interface of the bean. The incrMinSal()method increases the minimum salary by the specified amount. If adding the amount increases the minimum salary beyond the the maximum salary for the job, then the method throws the user-defined JobSalException exception. The incrMaxSal()method increases the maximum salary for the job by the specified amount. The getxxx methods return the value of the variable, for which they are defined. The setxxx methods set the value of the variable with the value specified in the parameter.

Oracle 10g: Build J2EE Applications D-15

Bean Class: JobsBMPBean


public void setMinSal(double amt) { this.minSal = minSal; } public double getMaxSal() { return maxSal; } public void setMaxSal(double amt) { this.maxSal = maxSal; } private Connection getConnection() throws SQLException { DataSource ds=null; try { Context ctx = new InitialContext(); ds=(DataSource)ctx.lookup("java:comp/env/jdbc/hrDS"); } catch (NamingException e) { System.out.println("Could not get connection"); e.printStackTrace(); throw new SQLException(e.getMessage()); } return ds.getConnection(); }

Copyright 2005, Oracle. All rights reserved.

Bean Class: JobsBMPBean (continued) The code in the slide shows the accessor methods for the minSal and maxSal variables. The getConnection()method is used to obtain a connection to the data source for manipulating the database. The data source is defined in the data-sources.xml file and the mapping can be specified in the deployment descriptor. The method obtains an initial context and looks up the data source with that context. The data source in the example is called hrDS. The method returns the connection by invoking the getConnection() method on the DataSource object. If there is an error in obtaining the connection, then the method throws an exception. The DataSource object is from the javax.sql package. The name of this object must match the name that is shown in the <ejb-location> element of the datasources.xml file.

Oracle 10g: Build J2EE Applications D-16

Bean Class: JobsBMPBean

private void closeConnection () { try { if (rset != null) rset.close();} catch (Exception e) {...} try { if (ps != null) ps.close();} catch (Exception e) {...} try { if (conn != null) conn.close(); } catch (Exception e) {...} }

Copyright 2005, Oracle. All rights reserved.

Bean Class: JobsBMPBean (continued) The closeConnection() method is invoked at the end of each method that uses the SQL connection obtained through getConnection(). It closes the prepared statement and the connection. Therefore, the container is able to reuse the connection.

Oracle 10g: Build J2EE Applications D-17

Bean Class: JobsBMPBean

public double ejbHomeGetAvgMaxSal() throws JobSalException { try { conn = getConnection(); ps = conn.prepareStatement ("SELECT AVG(max_salary) as AvgMax FROM jobs"); rset = ps.executeQuery(); if (rset.next()) return rset.getDouble("AvgMax"); } catch (Exception e) { e.printStackTrace(); throw new JobSalException(); } finally { closeConnection(); } throw new JobSalException ("Error in the method"); }

Copyright 2005, Oracle. All rights reserved.

Bean Class: JobsBMPBean (continued) The ejbHomeGetAvgMaxSal()method is the implementation of the home method getAvgMaxSal(). The home method in the bean class has a prefix of ejbHome and the method name is capitalized. This method obtains a connection and uses JDBC calls to retrieve the average of the max_salary column of the JOBS table. This method is not specific to any particular bean instance. Finally, the connections are closed by invoking the closeConnection()method.

Oracle 10g: Build J2EE Applications D-18

Bean Class: JobsBMPBean


public Collection ejbFindByMaxSalLimit

(double salLimit) { Vector v = null; try { v = new Vector(); conn = getConnection(); ps = conn.prepareStatement ("SELECT job_id FROM jobs WHERE max_salary > ? "); ps.setDouble(1,salLimit); rset = ps.executeQuery(); while (rset.next()) { String id = rset.getString("job_id"); v.addElement(new JobsBMPPK(id)); } } catch (Exception e) {...} finally { closeConnection(); } return v; } }
Copyright 2005, Oracle. All rights reserved.

Bean Class: JobsBMPBean (continued) The slide shows the code for the ejbFindByMaxSalLimit() method. It takes a salary limit as parameter. This method corresponds to the findByMaxSalLimit() method that is declared in the home interface of the bean. The JOBS table is searched to locate the rows in which max_salary is greater than the given salary limit. If no rows are found, then FinderException is thrown. Because there can be more than one row satisfying the search condition, the results are collected into a Vector. Each result is converted into a primary key before being added to the Vector, and the Vector is returned from the method.

Oracle 10g: Build J2EE Applications D-19

Deployment Descriptor
... <ejb-jar> <enterprise-beans> <entity> <ejb-name>JobsBMP</ejb-name> <home> demos.JobsBMPHome</home> <remote>demos.JobsBMP</remote> <ejb-class>demos.JobsBMPBean</ejb-class> <persistence-type>Bean</persistence-type> <prim-key-class>demos.JobsBMPPK </prim-key-class> <reentrant>False</reentrant> <resource-ref> <res-ref-name>jdbc/hrDS</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Application</res-auth> </resource-ref> </entity> ...

Copyright 2005, Oracle. All rights reserved.

Deployment Descriptor The slide shows the <entity> tag of the deployment descriptor for the JobsBMP example. The <entity> tag indicates that the deployment descriptor is for an entity bean. The logical name for the EJB is given as JobsBMP in the <ejb-name> element. The remote home and remote interface names are given along with their packages names. If the bean has local interfaces (can be in addition to the remote interfaces), those references should also be added to the <entity> tag. The value Bean for the <persistencetype> element indicates that the entity bean is a bean-managed persistence bean. The <prim-key-class> element shows that JobsBMPPK is the primary key class. The <reentrant> flag is set to false because the JobsBMP bean does not call itself. The <resource-ref> element indicates that the SQL data source hrDS is authenticated by the container. This data source specified in the <res-ref-name> element is generally the value of an <ejb-location> element in the data-sources.xml file. The value for the <res-auth> element can be either container or Application. This element specifies whether authorization to the resource must be performed by the container or programmatically through the application.

Oracle 10g: Build J2EE Applications D-20

Deployment Descriptor

... </enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>JobsBMP</ejb-name> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar>

Copyright 2005, Oracle. All rights reserved.

Deployment Descriptor (continued) Note that the deployment descriptor contains two main tags. One is the <enterprisebeans> tag (which holds information about the bean, the persistence, and the data source information). The other is the <assembly-descriptor> element that describes the transaction properties of the BMP bean. A transaction is a series of database operations that execute as a single unit. In case of transactions, all the operations must be successfully completed, followed by a commit operation. Otherwise, there is a rollback. Transactions can be bean-managed transactions (BMT) or container-managed transactions (CMT). You learn about these in the next few slides. The <container-transaction> tag of the <assembly-descriptor> element contains all the transaction attributes of the bean. The methods for which the transaction must be managed are specified in the <method> tag. A value * for <method-name> indicates that the container must manage transactions for all methods in the bean. The value Required for <trans-attribute> indicates that the bean always runs in a transaction.

Oracle 10g: Build J2EE Applications D-21

Creating Data Source data-sources.xml


<?xml version="1.0" standalone='yes'?> ... <data-sources> <data-source class="com.evermind.sql.DriverManagerDataSource" name="OracleDS" location="jdbc/OracleCoreDS" xa-location="jdbc/xa/OracleXADS" ejb-location="jdbc/hrDS" connectiondriver="oracle.jdbc.driver.OracleDriver" url="jdbc:oracle:thin:@localhost:1521:orcl" username="hr" password="hr" inactivity-timeout="30" /> </data-sources>

Copyright 2005, Oracle. All rights reserved.

Creating Data Source data-sources.xml You have already learned about data sources. Data sources provide logical definitions of databases. A bean developer uses logical representation of a database in the bean class, which the deployer maps to physical data sources. Data sources are published in the Java Naming and Directory Interface (JNDI) tree and are bound to the java:comp/env JNDI. Java 2, Enterprise Edition (J2EE) applications use published DataSource objects by performing lookup via JNDI using the published name, and use connection methods to connect to the database. Global data sources are defined in $OC4J_HOME/config/data-sources.xml. Each data source is specified with an XML tag. Application-specific data source files are specified by using the <datasources> tag in the orion-application.xml file. The data source that is specified in the <res-ref-name> element of the ejb-jar.xml deployment descriptor corresponds to a <ejb-location> element in the datasources.xml file. The two elements need not have the same name. If the names of these two elements are different, then you need to map the elements through the orion-ejbjar.xml file.

Oracle 10g: Build J2EE Applications D-22

Creating Data Source data-sources.xml (continued) The jdbc/hrDS data source is configured in the data-sources.xml file, as shown in the slide. The URL for the JDBC connection and the username and password to access the database schema are also specified. The default port number and SID on NT are 1521 and ORCL. Oracle Application Server 10g Containers for J2EE (OC4J) ships with a default JDBC port number 5521. The username and the password are those of the schema being used. The various attributes specified in the data-sources.xml file are as follows: The class attribute in the XML file defines the DataSource class to use. The name attribute is used to identify this data source and defaults to a value of Location if none is supplied. The location attribute defines the logical name for the data source and returns a data source as specified in the class attribute. The connection-driver attribute defines the JDBC driver for this data source. The ejb-location attribute specifies the logical name for the EJB CMP data source and supports pooling and transactional semantics. The xa-location (mandatory if ejb-location is present) attribute specifies the logical name for the transaction-enabled data source. Data sources are mapped by using OC4J descriptors <resource-ref-mapping>.

Oracle 10g: Build J2EE Applications D-23

Client Class: JobsBMPClient


import javax.ejb.*; import java.rmi.RemoteException; import java.sql.*; import java.util.*; import javax.naming.*; public class JobsBMPClient { public static void main(String[] args) { JobsBMP jobs = null; try { Context context = getInitialContext(); JobsBMPHome jobsBMPHome = (JobsBMPHome) PortableRemoteObject.narrow (context.lookup("JobsBMP"),JobsBMPHome.class); JobsBMP jobsBMP; jobsBMP = jobsBMPHome.create ("job_dev", "Bean Developer", 3000, 5000); ...

Copyright 2005, Oracle. All rights reserved.

Client Class: JobsBMPClient The code in the slide is a stand-alone client JobsBMPClient. This client obtains the initial context for the home object. The client invokes the create()method to create a bean with the job ID job_dev.

Oracle 10g: Build J2EE Applications D-24

Client Class: JobsBMPClient


... jobsBMP.incrMinSal( 200.0 ); System.out.println ("min_salary after incrementing " + jobsBMP.getMinSal( )); jobsBMP.incrMaxSal( 600.0 ); System.out.println ("max_salary after incrementing " + jobsBMP.getMaxSal( )); System.out.println("printing job_title "+ jobsBMP.getJobTitle( )); Collection col=jobsBMPHome.findByMaxSalLimit(15000); Iterator it = col.iterator(); while (it.hasNext()) { JobsBMP jobSals = (JobsBMP)it.next(); System.out.println(jobSals.getMaxSal()); } } catch(Throwable ex) {...} } ...

Copyright 2005, Oracle. All rights reserved.

Client Class: JobsBMPClient (continued) Various methods are invoked on the bean instance to test the methods. The client increases the minimum salary by 500 and invokes the accessor method to display the minimum salary. The client uses the findByMaxSalLimit() method and searches for rows from the underlying database whose maximum salary is more than 15,000. The rows are stored in an iterator and an exception is thrown if there are no matching rows.

Oracle 10g: Build J2EE Applications D-25

Overview of J2EE Connector Architecture


The J2EE Connector Architecture (JCA) enables J2EE components to interact with Enterprise Information Systems (EISs) such as:
Enterprise resource planning (ERP) Mainframe transaction processing Databases and nonrelational systems, and so on

JCA simplifies the integration of diverse EISs. Adherence to the JCA specification makes an EIS implementation portable across compliant J2EE servers.

Copyright 2005, Oracle. All rights reserved.

Overview of J2EE Connector Architecture The J2EE Connector Architecture (JCA) is a required J2EE 1.3 API defining a standard architecture for connecting the J2EE platform components (such as Enterprise JavaBeans) to heterogeneous Enterprise Information Systems (EISs). Examples of EISs include ERP, mainframe transaction processing, database systems, and legacy applications that are not written in the Java programming language. Each EIS requires only one JCA implementation that adheres to the J2EE Connector Specification. Adherence to the specification makes the implementation portable across compliant J2EE servers.

Oracle 10g: Build J2EE Applications D-26

OC4J J2EE Connector Architecture


Basic J2EE Connector Architecture:
OC4J
Application Contract

J2EE Application Component

System Contracts (Quality of Service)

Resource Adapter Enterprise Information System

Copyright 2005, Oracle. All rights reserved.

OC4J J2EE Connector Architecture The slide shows how OC4J implements the standard Java Connector Architecture (JCA). A resource adapter is a J2EE component implementing JCA for a specific EIS. The resource adapter mediates communication between the J2EE component (by using JCA) and the associated Enterprise Information System. The resource adapter implements two kinds of contracts for the JCA application component: Application Contract, which defines the interfaces or API through which the J2EE component accesses the EIS. The API, provided by the resource adapter, can either be the standard Common Client Interface (CCI), or an API specific to the type of a resource adapter and its underlying EIS. System Contracts, also known as Quality of Service (QoS) contracts that provide access to the following services managed by the J2EE container: - Connection services for pooling connections to the EIS - Transaction services to enable use of a transaction manager for distributed transactions - Security services for authentication, authorization, and secure communication with the EIS

Oracle 10g: Build J2EE Applications D-27

What Is a Resource Adapter?


It is a driver used by a client application to connect to a specific EIS. OC4J provides support for two J2EE 1.3 types:
A stand-alone resource adapter, which is found in a Resource Adapter Archive (RAR) file for use by all deployed applications An embedded resource adapter, which is bundled in an EAR file for a specific enterprise application

Examples of resource adapters:


JDBC or SQL for Java (SQLJ) drivers for database connections ERP adapter to connector a specific ERP

Copyright 2005, Oracle. All rights reserved.

What Is a Resource Adapter? A resource adapter is a driver used by an application server or an application client to connect to a specific EIS. Examples of resource adapters are JDBC or SQLJ drivers to connect to a relational database, an ERP resource adapter to connect to an ERP system, and a TP resource adapter to connect to a TP monitor. J2EE 1.3 requires application servers to support both stand-alone and embedded resource adapters. Stand-alone resource adapters, manifested in the form of a stand-alone Resource Adapter Archive (RAR) file, is available to all deployed applications. The following is an example of the contents of a RAR file.
/META-INF/ra.xml /META-INF/oc4j-ra.xml /howto.html /images/icon.jpg /ra.jar /win.dll

Note: The list of files in a RAR can vary. Embedded resource adapters are added to enterprise application archive (EAR), and is only available to the J2EE application with which it is packaged.
Oracle 10g: Build J2EE Applications D-28

Resource Adapter Deployment Descriptors


OC4J provides the following deployment descriptors for resource adapters: ra.xml: A standard J2EE deployment descriptor for developing an adapter oc4j-ra.xml: Contains deployment configurations for deploying an adapter to OC4J oc4j-connectors.xml One oc4j-connectors.xml file: Contains a list of stand-alone resource adapters deployed. It is located in the ORACLEAS_HOME/j2ee/home/config directory.

Copyright 2005, Oracle. All rights reserved.

Resource Adapter Deployment Descriptors In the previous pages, you should have noticed an ra.xml and an oc4j-ra.xml file contained in the RAR file. The ra.xml is a standard J2EE deployment descriptor for developing against a resource adapter. The oc4j-ra.xml contains deployment configurations for deploying resource adapters to OC4J. It contains EIS connection information as specified in the deployment descriptor of the resource adapter (ra.xml), the JNDI name to be used, connection pooling parameters, and resource principal mappings (<security-config> elements). In each OC4J instance, there should be one oc4j-connectors.xml file, located in the ORACLEAS_HOME/j2ee/home/config directory, listing all the stand-alone resource adapters that have been deployed in this OC4J instance. For example:
<oc4j-connectors> <connector name="myEIS" path="eis.rar"> <native-library>lib</native-library> </connector> </oc4j-connectors>

Oracle 10g: Build J2EE Applications D-29

Deploying Stand-Alone Resource Adapters


When deploying stand-alone adapters: Give the resource adapter a unique name, to simplify future operations such as removal of a deployed resource adapter Deploy in one of the following two ways:
Using the Admin command-line tool (admin.jar) Manually through directory manipulation, by expanding the .rar file contents into a userspecified directory name <connector-name> below the ORACLEAS_HOME/j2ee/home/<connector directory> (which defaults to ORACLEAS_HOME/j2ee/home/connectors)

Copyright 2005, Oracle. All rights reserved.

Deploying Stand-Alone Resource Adapters When deploying stand-alone resource adapter archives in OC4J, assign it a unique name for future operations such as removal of a deployed resource adapter. Resource adapters can be deployed in OC4J in one of the following two ways: By using the Admin command-line tool (admin.jar) Manually through manipulation of directories The Admin tool requires a -deployconnector switch, for example:
java -jar admin.jar ormi://host admin password -deployconnector -name myname -file myconnector.rar

OC4J decompresses the .rar file into a <connector-directory>/<connectorname> directory below the ORACLEAS_HOME/j2ee/home directory for the OC4J instance. If the directory does not exist, it will be created. A new attribute connectordirectory should be added to the <application-server> element in the application-server.xml file to specify the path used for the storage of stand-alone resource adapters. The default directory is ../connectors relative to the OC4J config directory. In the above example, OC4J decompresses myconnector.rar into a directory called ORACLEAS_HOME/j2ee/home/connectors/myname. The deployment tool must also verify the transaction levels, and whether the authentication specified in the deployment descriptor of the resource adapter (ra.xml) is supported by OC4J.
Oracle 10g: Build J2EE Applications D-30

Deploying Embedded Resource Adapters


Embedded resource adapters are packaged and deployed inside an Enterprise Application Archive (EAR) file. Each application (from an EAR file) has one oc4jconnectors.xml file. The application oc4j-connectors.xml file lists all the resource adapters deployed in the EAR file. The oc4j-connectors.xml file is automatically generated if not already included in the EAR file.

Copyright 2005, Oracle. All rights reserved.

Deploying Embedded Resource Adapters Embedded resource adapters are packaged inside an Enterprise Application Archive (EAR) file. If a resource adapter archive (for example, myconnecter.rar) is packaged in an EAR file (that is, myapp.ear), then the application is deployed in OC4J, in the directory ORACLEAS_HOME/j2ee/home/applications/myapp/myconnecter_rar. Each application deployed in an OC4J instance containing resource adapters, should have one oc4j-connectors.xml file located in the directory ORACLEAS_HOME/j2ee/home/application-deployments/<app-name>/. The oc4j-connectors.xml file contains the list of resource adapters for a Web application packaged in an EAR file (one entry for each resource adapter). The name and path of the oc4j-connectors.xml file is defined in a new element called <connectors> inside the <orion-application> element in orionapplication.xml. If no <connectors> element is specified in orionapplication.xml, then the default file will be called oc4j-connectors.xml. Assume that an oc4j-connectors.xml file that specifies a deployment name myRA, is in the .ear file. The generated oc4j-ra.xml file will be located in the ORACLEAS_HOME/j2ee/home/application-deployment/myapp/myRA/ directory. If omitted from the EAR file, an oc4j-connectors.xml file is created in the ORACLEAS_HOME/j2ee/home/application-deployment/myapp/ directory.
Oracle 10g: Build J2EE Applications D-31

Common Client Interface (CCI) API


CCI is defined by the J2EE Connector Architecture specification as: A set of interfaces and classes to allow a J2EE component to perform data access operations with an EIS Main interfaces and classes are:
ConnectionFactory Connection Interaction RecordFactory Record

(Use Suns Java J2EE Tutorial for more information.)


Copyright 2005, Oracle. All rights reserved.

Common Client Interface (CCI) API The J2EE Connector Architecture specification defines the Common Client Interface (CCI) API. CCI defines a set of interfaces and classes with methods that allow a client application to perform data access operations with the EIS. The main interfaces and classes are: ConnectionFactory: To create Connection instances to an EIS Connection: Representing a specific connection to the EIS Interaction: Used to execute the EIS functionality, such as a stored procedure RecordFactory: Creates Record instances for an application component Record: A superclass for the following types of instances: MappedRecord, IndexedRecord, or ResultSet. An IndexedRecord is an ordered collection based on the java.util.List interface. A client or application component uses the CCI API to establish a connection to the EISs resource manager by using the ConnectionFactory interface. The Connection object created is used for interactions with the EIS. The component accesses data from an EIS by using an Interaction object through the details specified in an InteractionSpec object. When data is read from (or written to) the EIS tables (or file structures), it uses one of the Record instance types, either a MappedRecord, IndexedRecord, or ResultSet.
Oracle 10g: Build J2EE Applications D-32

Anda mungkin juga menyukai