Oracle Application Server 10g: J2EE Deployment and Administration by Michael Wessler et al. Apress © 2004 (596 pages) ISBN:1590592352

Ideal for anyone wanting to stay ahead in the world of Oracle’s application servers, this focused, no-frills guide will help you get J2EE applications up and running on 10g.

Table of Contents Oracle Application Server 10g—J2EE Deployment and Administration Chapter 1 - Overview of Features, Editions, and Releases Chapter 2 - Developing with Oracle 10g As Chapter 3 - OC4J Installation and Runtime Behavior Chapter 4 - General Server Configuration Chapter 5 - Configuring JNDI and JDBC Services Chapter 6 - Configuring Java Message Service Chapter 7 - Security Chapter 8 - Using JavaMail and Java APIs for XML Chapter 9 - J2EE Application Deployment Chapter 10 - Web Applications Chapter 11 - Enterprise JavaBeans Chapter 12 - J2EE Connectors Chapter 13 - Configuring Web Services Chapter 14 - Application Clients Chapter 15 - Architecture and Deployment Topologies Chapter 16 - Installation and Administration Chapter 17 - Configuring J2EE Services Chapter 18 - Deploying Applications Chapter 19 - Configuring Web Caching Chapter 20 - Configuring Enterprise Security Chapter 21 - Configuring Clustering and Failover Appendix A - Server Configuration Files and Document Type Declaration Appendix B - Deployment Descriptors and Document Type Declaration Appendix C - Command-Line Utility Usage Appendix D - Debugging Tips List of Figures List of Tables List of Sidebars

Oracle Application Server 10g—J2EE Deployment and Administration MICHAEL WESSLER WITH ERIN MULDER, ROB HARROP, AND JAN MACHACEK

Copyright © 2004 by Michael Wessler, Erin Mulder, Rob Harrop, and Jan Machacek All rights reserved. No part of this work may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage or retrieval system, without the prior written permission of the copyright owner and the publisher. ISBN (pbk): 1-59059-235-2 Printed and bound in the United States of America 9 8 7 6 5 4 3 2 1 Trademarked names may appear in this book. Rather than use a trademark symbol with every occurrence of a trademarked name, we use the names only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark. Lead Editor: Tony Davis Technical Reviewers: Jeremy Smith and Jakob Hammer-Jakobsen Editorial Board: Steve Anglin, Dan Appleman, Ewan Buckingham, Gary Cornell, Tony Davis, Jason Gilmore, Chris Mills, Steve Rycroft, Dominic Shakeshaft, Jim Sumser, Gavin Wray Project Manager: Beth Christmas Copy Edit Manager: Nicole LeClerc Copy Editor: Mark Nigara Production Manager: Kari Brooks Production Editor: Kelly Winquist Compositor: Diana Van Winkle, Van Winkle Design Group Proofreaders: Linda Seifert, Katie Stence, Greg Teague Indexer: Valerie Perry Artist: Diana Van Winkle, Van Winkle Design Group Book Designer: Diana Van Winkle, Van Winkle Design Group Cover Designer: Kurt Krames Manufacturing Manager: Tom Debolski

Distributed to the book trade in the United States by Springer-Verlag New York, Inc., 233 Spring Street, 6th Floor, New York, NY 10013 and outside the United States by Springer-Verlag GmbH & Co. KG, Tiergartenstr. 17, 69112 Heidelberg, Germany. In the United States: phone 1-800-SPRINGER (1-800-777-4643), fax 201-348-4505, e-mail [email protected], or visit http://www.springer-ny.com. Outside the United States: fax +49 6221 345229, e-mail [email protected], or visit http://www.springer.de. For information on translations, please contact Apress directly at 2560 Ninth Street, Suite 219, Berkeley, CA 94710. Phone 510-549-5930, fax 510-549-5939, e-mail [email protected], or visit http://www.apress.com. The information in this book is distributed on an "as is" basis, without warranty. Although every precaution has been taken in the preparation of this work, neither the author(s) nor Apress shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the information contained in this work. The source code for this book is available to readers at http://www.apress.com in the Downloads section. To my grandmother Alma Johnson; for always being incredibly supportive and loving. —Michael Wessler About the Authors

MICHAEL WESSLER received his BS in computer technology from Purdue University in West Lafayette, IN. He is an Oracle Certified Database Administrator for Oracle 8 and 8i, an Oracle Certified Web Administrator for 9iAS, and a 10g Database Technician. He has administered Oracle databases on Windows NT, and various flavors of UNIX and Linux, including clustered Oracle Parallel Server (OPS) environments. He also performs database and SQL/PLSQL tuning for applications. Michael has worked in many IT shops ranging from small dot-com Internet startups to large governmental agencies and corporations. Michael, who is currently consulting at the Department of Defense, is a technical manager for Perpetual Technologies, Inc. In addition to Oracle DBA consulting, Michael has worked extensively as an Oracle 9iAS web application server administrator. Currently, he manages multiple web applications for the

Department of Defense and consults at various government agencies and in the private sector. Michael also frequently lectures on 9iAS and teaches Oracle performance-tuning classes. Michael can be reached at [email protected] or via his website at http://mike.wessler.name. Michael is the author of Oracle DBA on Unix and Linux (SAMS, 2002). He has also coauthored Oracle Unleashed, Second Edition (SAMS, 1997), Unix Primer Plus, Third Edition (Waite Group Press, 2000), COBOL Unleashed (SAMS, 1998), and Unix Unleashed, Fourth edition (SAMS 2002). Michael Wessler authored Chapters 9, 15–21, and the appendixes.

ERIN MULDER has been working with Java since the earliest releases. In recent years, she has helped deliver many successful Java and J2EE applications, including real-time energy usage visualization, network management for video-on-demand servers, financial market analysis, federal government accounting, and contracts management. She uses a combination of open source and commercial tools, and specializes in making them work well together. Erin has also been a technical editor for several publications and has made presentations on a variety of topics at Java User Groups and JavaOne conferences. She is a software architect with Chariot Solutions, a Java consulting company in Philadelphia. Erin Mulder authored Chapters 3 and 4 and contributed material to Chapters 1–14.

ROB HARROP is the lead software architect of UK-based development house, Cake Solutions Limited (www.cakesolutions.net). At Cake Solutions, Rob leads a team of six developers who work on enterprise solutions for a variety of clients including the Department of Trade and Industry, the Metropolitan Police, and NUS Services Limited. Rob and Cake Solutions specialize in both .NET and J2EE-based development, and Rob has been involved with .NET since the alpha stages. Rob is the author of Pro Jakarta Velocity: From Professional to Expert (Apress, not yet published), and coauthor of Pro Jakarta Struts, Second Edition (Apress, 2004) and Pro Visual Studio .NET (Apress, not yet published). In his limited spare time, Rob enjoys playing with different technologies, his current favorites being Groovy and aspect-oriented programming. Rob is a committer on the open-source Spring project (www.springframework.org), a Java and .NET application framework built around the principle of Dependency Injection. When not sitting in front of the computer, Rob usually has his head buried in a book and prefers the fantasy parodies of Terry Pratchett's Discworld. Rob Harrop authored Chapters 6–8 and 13, and contributed material to Chapters 1, 2, and 5.

JAN MACHACEK is lead programmer of UK-based software company Cake Solutions Limited, where he has helped design and implement enterprise-level applications for a variety of UK- and US-based clients. In his spare time, he enjoys exploring software architectures, nonprocedural and AI programming, and playing with computer hardware. As a proper computer geek, Jan loves the Star Wars and The Lord of the Rings series. Jan lives in Manchester in the UK and can be reached at [email protected]. Jan Machacek authored Chapter 12 and contributed material to Chapters 10, 13, and 14. About the Technical Reviewers JER SMITH entered the high-technology world in 1993 when a friend convinced him to install Linux .99 and OS/2 2.1 over Windows 3.1 on his Packard Bell computer. In Salt Lake City, UT, he owns Anagnosis (not-not-know) Consulting, a system integration and UNIX education company. He's currently working with the Department of Veteran's Affairs building's next generation Javabased clinical information systems. JAKOB HAMMER-JAKOBSEN (born 1965) holds an MA in economic and political science and an MA in computer science. As a student, Jakob was developing student administrative programs

for the university in Oracle version 5 and 6. After finishing school Jakob joined the original European distributor of Oracle TPI International, and worked as a system programmer for five years at large-scale Danish and European Oracle installations. For three years Jakob was a member of Oracle Premium Services in Denmark, which was part of Cary Millsap's system performance group network, as a principal senior analyst. After leaving Oracle in 2001, he joined Miracle A/S where he has been working with system architecture, optimization, and programming for the last four years. Jakob also spent a year in Sydney, Australia, where he founded Miracle Australia Pty Limited. He is a member of the OakTable network. Acknowledgments I would like to thank the following people who have been a wonderful help in writing this book as well as in my career. Jim Burcham, for getting me involved in Oracle application server and 9iAS in the beginning (at least, I think I thank him for that!). His guidance and logical engineering approach frequently "saves the day" for multiple systems and helps me solve many problems. Tige Chastain for his invaluable help in the arena of operating systems and networking. He's always the guy I call first for help when I have tough Linux and UNIX questions. Dan Wilson for showing me how to look at problems at a deeper integrated systems level rather than just looking at problems on the surface. His ability to architect and size systems has made my life easier. Ryan Stevens, Ron Plew, and Chris Zeis from Perpetual Technologies for providing multiple opportunities in the technical consulting world. Thanks guys! My family, especially my parents Jon and Barb, for always being supportive of my education, career, and writing. Jamie Miller, for her remarkable support and assistance while I was writing this. To my good friends Erik and Kalynn (and now Luke!), John and Dana, Jeff and Lindsey, TC and Colleen, and Ben, for being understanding whenever I disappear for a few months to write. I also would like to thank the wonderful professionals I've been able to work with at Apress: Tony Davis, Beth Christmas, Mark Nigara, and Kelly Winquist. —Michael Wessler I would like to thank Mom, Dad, the folks at Chariot, and especially Aaron for all the support and encouragement. I would also like to thank Tony Davis, Mark Nigara, Kelly Winquist, and Beth Christmas. —Erin Mulder

Chapter 1: Overview of Features, Editions, and Releases Overview So you're ready to start evaluating Oracle Application Server 10g, but find yourself lost in a sea of editions, releases, and non-J2EE features. In this chapter, we'll cut through the marketing hype and look at exactly what each version has to offer. In particular, we'll cover the following: How to choose between the Java, Standard, and Enterprise Editions How to make sense of the release numbers Which J2EE technologies are standard in all application servers Which features are specific to Oracle 10g AS Some of the non-J2EE features in 10g AS such as Oracle HTTP Server (OHS), Oracle Internet Directory (OID), Single Sign-On (SSO), Web Cache, and Clustering

Choosing an Edition Like most web application servers, Oracle 10g AS is available in a number of different editions, ranging from a small development-only J2EE server, to the full-fledged Enterprise installation. All of these include the basic J2EE containers (called Oracle 10g AS Containers for J2EE or OC4J), which provide support for Servlets, JavaServer Pages (JSPs), Enterprise JavaBeans (EJBs) and other standard J2EE technologies. Other, larger and more expensive versions include additional non-J2EE features such as Oracle's modified Apache web server, longtime Oracle products such as Portal, Forms, Reports, and Discoverer, Oracle's Identity Management products such as Oracle Internet Directory and SSO, and advanced features for high-performance and highavailability sites such as Web Cache and Clustering. There's no one size fits all so it's important to tailor the edition to the needs of your application. Here's a list of the editions of 10g AS that are available: OC4J Standalone (Oracle Application Server Containers for J2EE). This pure-Java, development-oriented edition supports all of the J2EE technologies with very little overhead. Instead of formal management or monitoring tools, it relies on commandline and file-based configuration. Its small installation size and memory footprint make it ideal for developer workstations. However, it's not intended for use in production systems. If you do choose to use it in production, you still must purchase one of the three editions described in this list. This version of the product is the primary focus of the development and deployment chapters of this book (Chapters 2–14). Java Edition. This low-end commercial edition includes all of the OC4J Standalone features and adds a web-based management tool, a more robust HTTP server (based on the open-source Apache web server), support for non-J2EE object-relational mapping through TopLink, and five licenses for JDeveloper, a full-featured Java IDE. Standard Edition. This edition includes everything found in the Java edition and adds Portal, SSO, and Content Management capabilities. While the Java Edition is well suited for independent J2EE applications, these more advanced features allow you to link lots of different applications across an enterprise system, presenting one common view to users (often through an Enterprise Information Portal or EIP). Enterprise Edition. This high-end edition includes everything found in the Standard Edition and adds web caching (Oracle Web Cache), enterprise integration (including Oracle SSO), directory services (OID), data analysis and reporting (Business Intelligence through Oracle Reports and Discoverer), and Oracle Forms. Additionally,

this version provides the ability to implement clustered J2EE instances fronted by Web Cache, which provides the maximum load-balancing and high-availability benefits. These features give you additional scalability, interoperability and real-time analysis while being the deployment vehicle for longtime Oracle products such as Forms, Reports, and Discoverer. This Enterprise Edition generally requires an infrastructure database (provided with the product installation) to support the advanced features. It's this product that is the focus of the administration chapters of this book (Chapters 15– 21). The following table gives you a quick comparison of the cost, size, and features of each edition, at the time of writing (June 2004). Each of the features listed will be described in more detail later in this chapter. Table 1-1: Comparison of Oracle 10g AS Editions Feature

OC4J Standalone

Java Edition

Standard Edition

Enterprise Edition

List price

Included with each of the other editions

$5,000/CP U

$10,000/CPU

$20,000/CPU

Download size

28 MB

Over 500 MB

Not individually downloadable

Over 2 GB

Configuration type

Manual

Enterprise Mgr

Enterprise Mgr

Enterprise Mgr

J2EE containers

Yes

Yes

Yes

Yes

HTTP server

Yes

Yes

Yes

JDeveloper

Yes

Yes

Yes

TopLink

Yes

Yes

Yes

Application Server Control

Yes

Yes

Yes

Portal

Yes

Yes

Single Sign-On

Yes

Yes

Content Management

Yes

Yes

Web Caching

Yes

Integration

Yes

Oracle Internet Directory

Yes

Discoverer

Yes

Reports Service

Yes

Personalization

Yes

Table 1-1: Comparison of Oracle 10g AS Editions Feature

OC4J Standalone

Java Edition

Standard Edition

Wireless

Enterprise Edition Yes

Deciding Which Features You Need In the end, the Standard and Enterprise offerings are just convenient package deals on a number of extra, (non-J2EE) add-on products. Thus, when choosing an edition, your first step should be to decide which of these add-on products you actually need. Then you should compare the bundled Oracle options with competing products from other vendors to determine which are the most appropriate and cost effective for your needs. For example, if you'll be running a number of intranet applications within Oracle 10g AS and would like users to be able to use the same username and password for each of them, then you'll probably be interested in SSO functionality. In this case, one option is to purchase the Oracle 10g AS Standard Edition and use the built-in Oracle SSO features. However, if Oracle SSO doesn't meet your needs, then you can always stay with the Oracle 10g AS Java Edition and buy a thirdparty SSO integration product such as RSA ClearTrust. One important factor to consider is your overall commitment to the Oracle 10g AS platform. Pure J2EE applications are very portable, but as you begin integrating additional Oracle products, you may become "locked in" to Oracle 10g AS and find it harder to migrate to other application servers. If you think that you may eventually move to another vendor, like BEA or IBM, then it may be worthwhile to choose third-party add-on products that integrate well with multiple application servers. On the other hand, if you're sure that your applications will be running on Oracle for years to come, then the integrated management and discount pricing of the Oracle add-on products may save a lot of time and money. This is especially true for companies that already use Oracle for their database. One of the compelling arguments for choosing Oracle 10g AS, if you already use Oracle databases, is the tight integration of the database with the application server, and the performance and administrative benefits that this can bring. The following criteria in Table 1-2 may be helpful when making your decision. Table 1-2: Tips for Choosing an Oracle 10g AS Edition If You're Building and Deploying…

Consider…

One J2EE application

Java Edition

Several unrelated J2EE applications

Java Edition

Corporate intranet or portal

Standard Edition (or third-party portal and SSO products)

Applications that integrate with many external systems or business partners

Enterprise Edition (or third-party integration products)

Oracle PL/SQL Web Toolkit

Standard or Enterprise Edition

Oracle Portal

Standard or Enterprise Edition

Oracle Forms, Reports, Discoverer

Enterprise Edition using Oracle Business Intelligence option

High-traffic e-commerce sites

Enterprise Edition using Oracle Web Cache

Table 1-2: Tips for Choosing an Oracle 10g AS Edition If You're Building and Deploying…

Consider…

High availability sites

Enterprise Edition using Clustering features

Applications that need to tie into enterprisewide identity management systems

Enterprise Edition (or third-party LDAP and SSO products)

Applications available to wireless devices

Enterprise Edition (or third-party wireless gateways)

Choosing a Release Version Oracle Application Server release numbering is unconventional. Whereas most application server vendors raise the major version numbers incrementally with every large release, Oracle tries to coordinate versioning across its entire product line. This means that major overhauls to the J2EE containers may only warrant a small incremental update to the Oracle 10g AS platform (for example, from 9.0.2 to 9.0.3). Consequently, it's dangerous to assume that J2EE configuration files will be compatible between these minor releases. Tip

Version 9.0.2 only supports the J2EE 1.2 family of specifications (with a few exceptions), whereas 9.0.3 is J2EE 1.3 compatible. The current 9.0.4 release is also J2EE 1.3 compatible.

Furthermore, some releases only include a subset of the Oracle 10g AS services. For example, version 9.0.3 updates only J2EE and TopLink and requires an existing 9.0.2 installation for enterprise features like Clustering and Advanced Security. This book focuses on the 9.0.4 release, which is a complete platform upgrade. The official name is "Oracle 10g Application Server (Version 9.0.4)" or as we refer to it: 10g AS. Although the name is 10g AS, the product version is 9.0.4, which can be confusing. The following is a historical overview of the product versions and will be useful as we describe upgraded features throughout this book.

OAS Oracle Application Server, written by Oracle and ending with the OAS 4.0.8.2 release. This product had problems and was ultimately dropped from the product line.

iAS First release of Oracle's Internet Application Server, based on Oracle 8i technology and the Apache web server using JServ. This was a complete rewrite of the OAS software. Oracle wisely incorporated proven products (such as Apache) within iAS rather than trying to "reinvent the wheel." Java was implemented via JServ in this product.

9iAS v1 The release of Internet Application Server based on Oracle 8i technology and Oracle Developer 6i. Though it still used Apache and JServ, Internet Application Server did allow for the integration with the first versions of OC4J Standalone via Apache ProxyPass directives. This product was the first version to see widespread use. It represents product versions 1.0.2 and 1.0.2.2.2 and is still in use supporting Developer 6i applications.

9iAS v2 This release represented a fundamental change in architecture for the product line. It was the first to fully integrate OC4J within the product directly for the support of J2EE applications and indirectly as a means to support other components such as Oracle Forms and Reports. Though previous versions of the product attempted to integrate the components, this 9iAS v2 release represents the first truly successful integration of all the components such as Application Server Control (ASC), OHS, and OC4J. However, like most major initiatives there were problems. Most of the issues with 9iAS v2 involved very stringent (and often impractical) installation requirements, slow response from ASC, and the instability of Oracle Reports, OID issues, and miscellaneous bugs. While this product certainly was usable for production systems and had its good points, it did have problems, especially for the first projects that used it. This product encompassed two versions: 9.0.2 and 9.0.3. It's still in use as of this writing, although new projects are upgrading to 10g AS and current projects are upgrading to 10g AS.

10g AS The initial release of 10g AS is actually the long-awaited patch release of 9.0.4. It's more evolutionary than revolutionary, although it does include some new features especially within the area of security and Identity Management. While 9iAS v2 had its quirks, the 10g AS product is very solid. It fixes the problems on 9iAS v2 and uses Java 1.4. Thus far it appears to be stable, solid, and reasonable to work with assuming you understand Java, Oracle, and web server administration. This book is written for the 9.0.4 (10g AS) release. Tip

What does it take to be an Enterprise Edition 10g AS administrator? Obviously, it depends a lot on the nature of the project (J2EE, Oracle, Apache, and so on), but so far we've found that it takes a hybrid administrator who either knows or can quickly learn the following: Apache, J2EE and Orion, Oracle development products, intermediate Oracle Database Administration (DBA), security, systems architecture and planning, and network telecommunications. If that sounds like a lot, it's because it is a lot of topics to understand. Managing 10g AS requires the skills of an Oracle DBA, web administrator, developer (J2EE or PL/SQL), systems administrator, and network administrator. This wide range of skills is necessary because the product touches so many different areas. Most successful candidates are either from the system administration or database administration realms, but the most important factors are the ability to learn new technologies and do some problem solving.

J2EE Features Every J2EE application server needs to provide "J2EE containers" that allow developers to build and deploy web applications, EJBs, J2EE Connectors, and application clients. It must also implement all of the supporting J2EE technologies such as Java Message Service (JMS) and Java Database Connectivity (JDBC). Oracle 10g AS 9.0.4 supports J2EE version 1.3, which requires support for the following specifications listed in Table 1-3.

Table 1-3: J2EE 1.3 Technologies Specification

Version

Servlet

2.3

JavaServer Pages

1.2

Enterprise JavaBeans

2.0

J2EE Connector

1.0

Java Transaction API

1.0.1b

JDBC

2.0

Java Message Service

1.0.2b

Java Naming and Directory Interface

1.2.1

JavaMail

1.2

The following sections briefly describe the major J2EE technologies. Later chapters will discuss the configuration and deployment of these components in detail.

Servlets and JavaServer Pages Java Servlets are server-side Java classes that respond to HTTP requests. JSPs use a combination of Java scriptlets, custom tags, and markup (HTML, WML, XML, and so on) to render an HTTP response. The two technologies are often used together to build web applications based on a Model-View-Controller (MVC) design. In this common setup (also called a "Model 2 architecture"), the Servlets parse incoming requests, execute business logic, update data objects and pass control to JSPs, which display the results. Chapter 10 covers the configuration and deployment of web applications.

Enterprise JavaBeans EJBs are business components that can take advantage of container-managed security, transactions, persistence, remoting, and other J2EE services. There are three types of EJBs: entity beans, session beans, and message-driven beans. Entity beans correspond to rows of data in a database and are often used strictly for data access. Session beans contain complex business logic and often manage one or more entity beans or database tables. Message-driven beans respond to messages posted asynchronously to JMS topics or queues. See Chapter 11 for more information about the configuration and deployment of EJBs.

Java Message Service JMS allows J2EE components to communicate asynchronously through topics (publish/subscribe) and queues (point-to-point). This is very useful for throttling requests, kicking off long-running processes, or responding to asynchronous events. Chapter 6 covers the configuration and use of JMS.

Java Database Connectivity and J2EE Connectors JDBC data sources allow for easy interaction with relational databases. J2EE Connectors allow interaction with other types of external systems. Both support transactions and allow for changes across several systems that will be committed or rolled back together. Chapter 5 discusses the

configuration and use of JDBC data sources. Chapter 12 covers the configuration, deployment, and use of J2EE Connectors.

Transactions Transactions allow developers to prevent data corruption by ensuring that related changes to databases and other systems are committed or rolled back together. J2EE provides the Java Transaction API (JTA) for programmatic initiation of transactions, and it also allows EJB transaction settings to be configured declaratively inside the EJB deployment descriptor. See Chapter 11 for information on configuring declarative transactions.

Security J2EE supports both programmatic security (manually checking permissions from within code) and declarative security (configuring which roles should be able to access which components and methods). Most applications will need both, and both rely on the same underlying security architecture, described in Chapter 7. Security for the Application Server is covered in detail in Chapter 20.

Other J2EE Services J2EE includes a number of other services and APIs that simplify programming but don't require significant server configuration. In particular, Chapter 5 discusses Java Naming and Directory Interface (JNDI), and Chapter 8 covers JavaMail and the Java APIs for XML (JAX).

Non-J2EE Components In addition to the basic J2EE services, the full Oracle 10g AS Enterprise Edition offers a number of non-J2EE components that support the product as a whole. It's critical to understand that 10g AS is more than just a renamed Orion J2EE server. 10g AS is a tightly integrated web application server built on the Apache web server (modified and renamed OHS), using the Orion J2EE application server (modified by Oracle and renamed OC4J), a Lightweight Directory Access Protocol (LDAP), which is renamed Oracle OID, as well as advanced features, include Oracle Web Cache and Oracle Clustering, for those sites requiring maximum performance and reliability. These components are described in great detail in Chapters 15–21 and on Oracle websites (http://otn.oracle.com), so we'll only take a brief look at each here. 10g AS also includes a mix of longtime Oracle products such as Oracle Portal, Forms, Reports, Discover, and the PL/SQL Web Toolkit, as well as useful Java development tools such as TopLink and JDeveloper. We'll briefly cover these here, in order to give you a complete overview of what Oracle 10g AS can provide, but we don't cover them in any detail in this book.

Oracle HTTP Server All commercial editions of Oracle 10g AS include OHS—an extended version of the popular Apache web server. This server relies on proven Apache code to handle all incoming HTTP and HTTPS requests, dispatching them appropriately to OC4J or other resources through the standard Apache "mod" architecture. (The OC4J Standalone development edition handles HTTP requests directly from the web container.) OHS adds the following enhancements to the underlying Apache server: Integration with OC4J. Requests for web application resources are passed through the

OC4J web container, and session-aware load balancing and failover are supported across multiple OC4J instances. Integration with Oracle 10g AS Single Sign-On. Allows the web server to authenticate users through SSO and passes the credentials through to web applications. High availability and load-balancing optimizations. Requests can be distributed among a cluster of web servers and application servers, while respecting user sessions. Servers that fail are automatically detected and restarted. Note

To accommodate companies who already have investments in Netscape's NES or Microsoft's IIS, this functionality is also made available as plug-ins for those web servers.

Web Cache Oracle 10g AS Web Cache sits in front of web and application servers and serves up cached content in response to HTTP/S requests, and only hits those servers for new or expired content. This caching layer can dramatically improve the performance of certain types of web applications. Until recently, it was very difficult for dynamic applications to take advantage of web caching. When just about every page includes a personalized greeting or account detail, traditional caching proxies won't do. Oracle has solved this problem by implementing the Edge Side Includes (ESI) standard. In particular, the Java version of this standard (JESI), allows JSP developers to easily mark certain parts of a page as dynamic and permit the rest to be cached. When a request comes in, the dynamic parts are executed and the full page is reassembled at the Web Cache layer. Oracle 10g AS Web Cache also supports the following: Rules-based and programmatic invalidation of cached content Delivery of specific cached content based on user characteristics Clustering of cache servers Load balancing and throttling Form-based or client certificate authentication (but not basic authentication) Hierarchical caching (across diverse geographical locations) The configuration of Oracle 10g AS Web Cache will be covered in Chapter 19. For applications that need to perform significant post-processing on cached data, Oracle 10g AS also includes a Java Object Cache and Web Object Cache, which can be directly manipulated through published APIs. Documentation is available for each on the Oracle Technology Network (OTN) website.

Application Server Control The web-based Oracle Enterprise Manager (OEM) for 10g AS has been renamed Application Server Control (ASC). This product is a web-based administrative console for the Oracle 10g AS platform that allows you to manage and monitor all of the components included in your installation. In particular, this tool is often used to configure new OC4J instances, deploy J2EE applications to them, and monitor performance. It's similar to the management consoles provided for WebLogic and WebSphere. Alternatively, you can use command-line tools to perform or automate many of the same

administrative tasks. Note

OC4J Standalone instances cannot be managed through the OEM website, but rather only through manual updates to a collection of XML configuration files (see Chapter 4). These same files should not be directly edited in a commercial edition.

The configuration of applications and server processes through ASC (formally Enterprise Manager) will be covered in Chapters 16 and 17.

Single Sign-On The term Single Sign-On or SSO refers to the idea that users should only authenticate once to access most of the applications they use on a daily basis. This reduces the number of passwords each user must remember, and the number of systems that need to be updated whenever privileges change, thus improving both security and productivity. Oracle 10g AS Standard and Enterprise Editions provide SSO functionality for web-based applications. SSO is unavailable for nonweb applications. The first time a user tries to access a protected application, the OHS will redirect her to the SSO server, which will check her credentials against an OID repository. If the logon is successful, she is given an encrypted cookie, which will automatically authenticate her to any application protected by Oracle 10g AS SSO. Similarly, when she signs off, the SSO server can ensure that all her application sessions are terminated. Applications deployed within Oracle 10g AS can easily take advantage of SSO. However, it's often necessary to authenticate to external legacy or partner applications, some of which need to continue maintaining their own usernames and passwords. Fortunately, the SSO server can also store these additional credentials for each user and pass them on to the external system at the appropriate time. If additional features are needed (such as authenticating via a SecureID access card), you can also integrate third-party security frameworks like RSA ClearTrust, which provide a greater range of authentication types.

Content Management SDK The Oracle Content Management SDK is a database-backed file system that supports indexing, versioning, fine-grained access control, notification, and other content management features. Users can interact directly with the repository through a variety of out-of-the-box clients. At the same time, developers can work with a Java API to build custom parsers, renderers, user interfaces, clients, and more. Under the covers, all documents are stored as LOBs in an Oracle database and can be configured to work with most Oracle text options. Out-of-the-box clients are provided for FTP, SMB, WebDAV, IMAP4, AFP, and NFS. Documentation for the Oracle Content Management SDK is available on the OTN website (see http://otn.oracle.com/documentation/cm_sdk.html).

Integration Oracle 10g AS Integration provides an infrastructure for integration between enterprise applications both inside and outside the corporate firewall. Like other J2EE-based Integration servers, it provides a number of out-of-the-box J2EE Connectors for communication with common systems (such as SAP and PeopleSoft). It also supports web services interfaces and provides a

complete workflow system to control how data is routed, transformed, and processed once it's received. More information about Oracle 10g AS Integration is available on the OTN website (see http://download-east.oracle.com/docs/cd/B10464_01/integrate.htm).

Oracle Internet Directory OID is an LDAP directory built on top of the Oracle database. It's used to store user identity, authentication, and authorization information for enterprise applications. It can be used as the sole user repository, or linked to other directories, like iPlanet, throughout the enterprise. The latter option is useful when integrating with existing systems (such as human resources) or when a corporation has already standardized on a different directory server. Oracle 10g AS SSO relies on OID to coordinate authentication across multiple applications (see Chapter 20).

JDeveloper JDeveloper is an integrated development environment (IDE) for Java that's designed to accelerate Java and J2EE application development for the Oracle 10g AS platform. Like BEA's WebLogic Workshop and IBM's WebSphere Application Developer, JDeveloper provides wizards to automatically generate many of the standard and server-specific deployment descriptors. It also incorporates a variety of timesaving features, including the following: Design wizards for J2EE 1.3 components Embedded OC4J server Web service development wizards UML class and activity diagrams with round-trip code generation Swing and Abstract Window Toolkit (AWT) user-interface designer JSP viewer Support for the Struts web application framework Integration with Ant, JUnit, CVS and other popular development tools Advanced debugger and profiler Though it's missing some of the cutting-edge advances and portability found in independent IDEs like Eclipse and IntelliJ/IDEA, it offers more complete modeling, user-interface design, and OC4J server integration. This can be ideal for development teams committed to Oracle 10g AS. All three commercial Oracle 10g AS editions include five or more JDeveloper licenses.

TopLink TopLink is an object-relational mapping tool that's designed to quickly and easily persist Java objects to a relational database like Oracle. Unlike EJB container-managed persistence, it allows developers to map arbitrary relationships and to persist any plain old Java objects (POJO), not just entity beans. It can also help to reduce dependencies between Java code and the underlying data schema. The features include the following: Graphical workbench for mapping objects to database tables

Support for complex relationships, including subselects Flexible query capabilities, allowing SQL, EJB-QL, and Java object-based expressions Support for multiple application servers, databases, and architectures Caching options to improve performance Overall, TopLink is a useful tool that offers flexible, high-performance object relational mapping (ORM) capabilities. A point of interest with TopLink is that the EJB 3.0 specification looks set to use a POJO-based ORM model for persistence. This has been brought about mainly by the success of the opensource Hibernate project (www.hibernate.org), a project that is very similar to TopLink. TopLink is included with every commercial edition of Oracle 10g AS and can also be downloaded through the OTN website.

Portal Oracle 10g AS Portal provides a framework for the creation of enterprise portals that provide corporate users a single destination for all of their daily business. Individual portlets can be designed to allow access to just about any enterprise application or web service, and can be arranged in custom pages that maximize each user's productivity. Of course, it's important to understand the difference between a portal framework and the components built upon it. Out of the box, Oracle 10g AS Portal provides everything you need to build and manage a basic enterprise portal with dozens of portlets for document management, collaboration, syndication, and reporting. From this point, you can choose to integrate your own portlets and applications, purchase prebuilt components from Oracle, or in many cases, do a little of both. In general, portlets developed for one portal server aren't compatible with others. However, the Java Community Process (JCP) has recently finalized a common Portlet API (Java Specification Request 168), which will hopefully lead to increased portability in the future. More information about Oracle10g AS Portal is available on the OTN website (see http://download-east.oracle.com/docs/cd/B10464_01/portal.htm).

Discoverer Discoverer is a user-friendly tool that lets end users build ad hoc queries and reports against corporate databases and data warehouses. More information is available on the OTN website (see http://otn.oracle.com/documentation/discoverer.html).

Reports Oracle 10g AS Reports is a more sophisticated report writer (aimed at developers, not end users) that supports both web-based and printable reports in a variety of formats. More information is available on the OTN website (see http://otn.oracle.com/documentation/reports.html).

Forms Oracle Forms is a Rapid Application Development (RAD) environment that lets developers create useful database-centric applications for minor business needs. Though it isn't ideal for complex enterprise applications, it can be appropriate for low-traffic, timesaving tools. The latest release

includes web delivery through a Java API and may be integrated with SSO and other Oracle 10g AS services. More information about Oracle Forms is available on the OTN website (see http://otn.oracle.com/documentation/9i_forms.html).

Personalization Oracle 10g AS Personalization analyzes the behavior of anonymous and logged-in users and adjusts content based on a tunable recommendation engine. It's most useful for e-commerce and portal applications. More information about Oracle 10g AS Personalization is available on the OTN website (see http://otn.oracle.com/products/personalization/index.html).

Wireless Oracle 10g AS Wireless supports the development and deployment of browser-based applications, voice-based applications, messaging, and J2ME applications for wireless devices. Along with an enterprise-class wireless gateway, it also includes a developer toolkit that integrates especially well with Oracle's JDeveloper IDE, allowing developers to quickly develop applications for the most common wireless platforms. More information about Oracle 10g AS Wireless is available on the OTN website (see http://otn.oracle.com/products/iaswe/index.html).

Summary In this chapter, you've seen that Oracle Application Server is available in three commercial editions: Java, Standard, and Enterprise. The Java Edition includes everything necessary for the development and deployment of J2EE applications. The Standard and Enterprise Editions bundle additional web application server components to support both J2EE and non-J2EE applications, traditional Oracle products (for example Portal, Forms, Reports, and Discoverer), highperformance and high-availability sites with Web Cache and Clustering, and Oracle Single SignOn with OID integration. Whether your system is large or small, there's likely an Oracle 10g AS configuration to meet those needs. As with BEA WebLogic and IBM WebSphere, Oracle would like you to buy into its complete application server "platform." The more you use and depend on server-specific add-ons like Oracle SSO and Web Cache, the more likely it is that you'll stay with the Oracle application server product line for years to come. This integration offers many benefits, especially for shops that are already deeply entrenched in the Oracle product line. You may well decide that it's worth the risk of getting locked in to a certain vendor in order to take advantage of all these integrated features. However, for pure J2EE applications, you may determine that a smaller J2EE OC4J Standalone installation is more appropriate. Whichever commercial edition you choose, you'll also get licenses for OC4J Standalone (the developer-oriented edition) and JDeveloper (Oracle's Java IDE). Both of these can greatly speed up the development of J2EE applications. In Chapter 2, you'll look at a variety of development strategies, customized to support the Oracle-specific features that you'll need later. In Chapters 15–21, we'll cover the architecture, administration, and features available for the full Enterprise Edition 10g AS server.

Chapter 2: Developing with Oracle 10g As Overview So you've chosen which edition of 10g AS you'll be running in the production environment for your application, but the decision still remains which edition to use for development and testing. During the course of this chapter we'll address the nuances of each edition and explore how requirements for development differ from requirements for testing. Specifically this chapter covers the following: Choosing an edition for development Choosing an edition for testing Strategies for development and testing How to migrate J2EE components developed for other application servers

Choosing an Edition for Developers When choosing which edition to use for development you need to consider a wide variety of factors.

Consider Application Requirements The first factor to consider is just how many of the value-added features of the chosen production environment your application will be using. If you have a team of developers who are building an application that relies heavily on functionality specific to Oracle 10g AS, then it would probably be a wise idea to give developers the same edition for developing that you intend to use in production. In this case you should avoid the temptation to provide a single development server for the entire development team. Each developer needs to be free to work on code independently of changes made by other team members. If your developers only have OC4J on their workstations and are relying on access to a shared server for application-critical features, you'll likely come across numerous clashes as developers refactor, debug, and improve code. On the flip side, if you're building an application that's based solely on J2EE standards, or a mix of J2EE standards and open-source libraries and frameworks, then you would probably be best served by choosing OC4J. The biggest benefit of OC4J is that it's simple for a developer to manage independently of the administrator. There's no complex installation, no interaction with the Oracle Infrastructure—just a small ZIP file and a completely platform-independent, 100 percent Java container. As a Linux user Erin has a particular fondness for OC4J because its pure Java nature allows her to run it unhindered on her SuSE laptop. There is of course a happy medium between the two different extremes that's much more likely to appear in a real-world scenario. In many cases the choice to use 10g AS will be based on the availability of a certain feature or features. In this case it may still be possible to use OC4J on the developer workstations, since it may be possible to defer the integration of proprietary features such as Single Sign-On and Web Caching, until the end of the project. Alternatively, it may be that you can limit the interaction with the proprietary features to a particular developer or small group of developers, in which case a shared-server approach might be acceptable. In the end this is a common-sense decision and you need to choose the solution that best fits your development environment.

Consider Developer Experience It's also important to consider the developer experience when choosing which edition of 10g AS to develop against. If you're expecting your development teams to work with an edition of the application server that makes it difficult for them to do their job and causes their productivity to drop, then expect to have an angry group of coders banging on your door! This is perhaps the hardest factor to gauge, as it depends greatly on your knowledge of your development team. If your development team is just you then you're quite fortunate, but chances are that you will not be that lucky and you'll have to take everyone's needs into consideration. OC4J is a simple option for developers. It provides them with all the required J2EE functionality with a minimal amount of fuss. A developer will have no problem maintaining his own OC4J installation—this may not be true of either Java Standard Edition or Enterprise Edition. The Java Standard and Enterprise Editions will obviously take up more memory on a developer workstation, and this may cause noticeable slowdown on under-configured machines. This problem may be compounded if your developers run other memory or CPU-intensive applications on their machines. However, on an adequately equipped machine, the performance hit will be negligible. Perhaps the most important difference for developers is the difference in startup time. On a sample Pentium 4 2.5 GHz machine with 1.5 GB RDRAM, OC4J takes approximately 2 seconds to startup, whereas the Java edition of 10g takes 12 to 14 seconds—up to six and seven times longer. When you stop and start the application server regularly during the day this can be an annoying inconvenience. Your decision in this area will be based on which environment your developers are more comfortable working in. If your developers prefer to have Enterprise Edition running on their local machines, then let them. However, if they only want to use OC4J, then you should strive to facilitate this.

Setting Up the Development Environment The development edition that you choose may have an impact on how you set up the development environment. Many companies like to promote standardized configurations for their machines, but Erin prefers to allow developers to customize workstation configurations to their liking—that way they can work in an environment that's both comfortable and familiar. If you decide to use OC4J for development then the installation process is trivial and you can pretty much leave the developers to set up their own machines. Note

If you're unfamiliar with Oracle 10g AS installation, you should check out Chapters 3, 15, and 16, where installation is covered in full for OC4J and the full editions.

However, if you're using Java Standard or Enterprise Edition you may wish to produce a standard base workstation installation using a tool such as Norton Ghost. This way you reduce the administration burden for the development environment, and you can quickly recover an installation if one of the machines becomes corrupted. In summary, choosing an edition of 10g AS to use for development purposes is an important one and can have a large impact on the development of your application. Use the previous recommendations as a guideline, but your decision should also be based around what is best for your project and your team.

Choosing an Edition for Testing Choosing which edition to use for testing is much easier than choosing an edition for development. In short, your test environment should match the production environment as closely possible. Of course that's a bit of a wide-reaching statement because different kinds of testing will require different kinds of environments.

Running Unit Tests In general, unit tests will be run by individual developers on their workstation, which means that the edition used for development will be the one used to run unit tests. However, it's often useful to run the unit tests as part of some automated nightly testing procedure. In this case these automated tests should be run on the edition that you intend to use for production. This is especially useful if you're developing on a different edition because it enables you to catch any incompatibilities between editions as soon as possible.

Running Integration Tests When you have multiple developers working on a project it's important to run integration tests in addition to unit tests. Although a unit test typically exercises one small piece of functionality, integration tests are necessary to ensure that all of the components link together correctly. Thus, they often test entire use cases from end to end. To ensure that the test results are as accurate as possible, you should make certain that the edition of 10g AS used to run integration tests is the same edition that you'll use for production. This is often a requirement anyway because some of the components requiring testing may only be available on the production edition.

Running Performance Tests Running performance tests is an important part of building an application and you should run them frequently. Indeed, you should run the performance tests as often as you run integration tests. Many teams will leave performance testing until the end of a project but this is not the best approach. By running tests regularly, say daily, any noticeable differences in performance can be attributed to work that was carried out during that day's development. You'll almost certainly want to use the same edition of 10g AS for performance testing that you will for production in order to ensure that your performance figures are as accurate as possible. It's also important to try to use the same (or equivalent) hardware so that you can measure performance in absolute terms. For example, if you're building an application for a client, part of the acceptance criteria for the application may be a guarantee that no page takes longer than three seconds to load for a broadband user. To ensure that you can hit this goal in production, you'll need to test on your production servers or at least a similar configuration. Of course, if you can easily hit your goals on less powerful machines, then there's a good chance you'll be able to hit them in production. However you should take great care to ensure that other factors such as clustering or network overhead will not affect the performance of your application. It's also important to consider a typical workload when testing. In general, you want to test your application using a workload that's more demanding than you expect the application will generally experience. In that way you can get a feel for how the application will perform when it's really being pushed. Avoid the temptation to just test a particular micro-feature; instead, try to test the performance of whole use cases and run different use cases in parallel. In this way you can mimic more closely a real world workload, which is especially useful in highlighting any spurious problems with performance or threading.

Environmental Considerations When configuring the development and test environments it's important to try and avoid overlap. If developers are using a different edition of 10g AS, then it's often useful to give them access to a server running the production edition. You should, however, avoid the temptation to use the same server for testing. The testing should be carried out on the same configuration each time. By allowing developers direct access to the testing server it becomes very difficult to ensure that this happens. Problems can arise when a developer makes a change in the test environment that other team members are unaware of. The test environment should match the production environment as closely as possible and as such once it's set up there should be no need to make changes. Any changes you do make may result in code that works in the test environment but not in the production environment.

Strategies for Development It would take another book to discuss this topic fully, but there are a few considerations for development strategy that are important to discuss here. First, how will developers actually build the application? Will they use an IDE such as Borland's JDeveloper or JBuilder? Will they use a simple text editor such as vi or emacs along with command-line compiler? Will they use shell scripts or Apache Ant for the build process? Many shops will try to place constraints on what software their developers use to build software, but we find this to be extremely counterproductive. Developers tend to be very familiar with one or two IDEs or editors and will have a cursory knowledge of a few others. Although any good developer will be able to familiarize herself with a new IDE or editor within hours, she will not be at her most productive for considerably longer than that. So while Oracle JDeveloper 10g might be considered a natural choice when building applications for Oracle 10g AS, each member of your team will probably be best served using the environment with which he or she is most familiar. Note

Since this book focuses on 10g AS, we won't go into too much detail on JDeveloper. However you should check out Harshad Oak's Oracle JDeveloper 10g (Apress) for a full discussion on the use of JDeveloper for developing J2EE applications.

If your teams want to use JDeveloper, then let them. If they want to use IntelliJ, Eclipse, or SlickEdit, let them. We advise that you don't place too much stock on the integration between JDeveloper and 10g AS. Features such as the ability to debug applications running inside a 10g AS container are nice additions to JDeveloper, but they're available in other IDEs as well. Note

If you're using JBuilder, then you can download a plug-in for 10gAS from the Oracle website at http://otn.oracle.com/software/products/ias/htdocs/utilsoft.h tml. Eclipse users should check out MyEclipse (www.myeclipseide.com), which has Connectors for a wide variety of application servers, including Oracle 10g AS.

You should also be wary of relying too much on in-container debugging and unit testing. If you're unable to debug and test the majority of application functionality separate from the container, then you should consider refactoring your code to enable this. Choosing how to build the application is also an important consideration. We find that it's best to make the build process as structured and standard as possible. Allowing different developers to use different build methods can lead to disaster because you have different configurations and builds of the same application floating around in your environment. For this purpose we prefer to

use Apache Ant (http://ant.apache.org), which provides predefined tasks for most of the actions needed to build an application. We've also found it useful to automate the starting and stopping of the application server using the task in Ant.

Strategies for Testing Application testing should be largely automated. Although you'll need to perform some testing manually, such as usability testing, much of the unit, integration, and performance testing can be automated. The main reasons for automating testing are to decrease workload and increase repeatability. Although automating tests requires effort up front, it's largely a one-time effort, whereas manual testing requires effort each time you test. Automated tests will also reproduce the same actions faithfully each time they're run, whereas humans are likely to deviate from the plan, especially in complex test cases. You can use any approach that you like to automate unit and integration testing but you'll probably find it useful to utilize a testing framework such as JUnit to ease the burden of test writing. Although JUnit (www.junit.org) is primarily designed for unit testing, it's equally suited to integration tests—you simply need to reduce the granularity of the tests. Even web interfaces can be easily tested using JWebUnit (http://jwebunit.sourceforge.net), a very useful JUnit extension. Performance and load testing aren't quite as simple. You first need to define what you're testing and obtain some performance figures for it. We find that Apache JMeter (http://jakarta.apache.org/jmeter) is a useful tool for this as it allows us to save our tests so that we can replay them anytime. If a test shows a bottleneck you need to find out where that bottleneck exists. For this it's important to be accurate and not just guess at where you think the bottleneck lies because you'll be end up wasting time fixing bugs that don't exist. Invest in a good profiler such as Borland's Optimizeit (www.borland.co.jp/optimizeit/) or Quest Software's JProbe (www.quest.com), and run the performance test again, this time using the profiler to monitor the application server. Although it's important that developers run tests on their local workstations, it's just as important that all tests are run centrally. Indeed, this is the only way of effectively running your integration tests. Scheduling tests to be run each night is a relatively simple job—with effective use of Ant and scheduled tasks you can run all tests overnight and have a nice report delivered to a developer's mailbox the next morning.

Strategies for Deployment In terms of strategic planning, application deployment is often the most overlooked area of the development cycle. Many teams will leave deployment planning until the day before they're due to deploy and hope for the best. When a problem arises during deployment there's a rush to fix it and no real effort to diagnose where the problem came from. A better approach is to automate as much of the deployment process as possible. This is especially useful if you're deploying the application regularly to a test server because you can test your deployment script as part of the test process. Using this approach also ensures that the application is deployed in exactly the same way for testing as it is for production. Another benefit of automated deployment is that it reduces the barriers to giving the client early beta releases of the application to play with. This way you can start to gather user feedback early and start responding to that feedback right away. Most deployment can be scripted using shell scripts, however we find that it's preferable to use something like Ant as much as possible. In that way we can keep as much of our automation together and reuse automated steps such as the compile step between different automated

processes.

Accessing J2EE Applications By default, OC4J Standalone exposes web applications on port 8888 using their configured context paths. For example, when deploying a web application that uses the context "examples", you can usually access it at http://localhost:8888/examples/. If you're using Java Standard or Enterprise Edition, then you can access web-application content via port 7777 instead of 8888. In general, dynamic pages will take a few seconds to compile and load the first time they're visited, but they should respond quickly to subsequent requests. The HTTP listener port and default web application can be easily changed with the http-web-sites.xml configuration file. Other J2EE components can be accessed through Remote Method Invocation (RMI) and the Java Message Service (JMS) as appropriate. Within OC4J Standalone, the default RMI port is 23791 and the default JMS port is 9127. These can also be easily configured through rmi.xml and jms.xml, respectively. A full list of the ports used by Oracle 10g AS along with their recommended port ranges can be found online at http://downloaduk.oracle.com/docs/cd/B10464_02/core.904/b10376/portnums.htm#g698804. Later chapters will cover these settings in detail. In particular, Chapter 7 describes how to access a secured J2EE component from a client application.

Summary Choosing an edition of 10gAS to use for development is a difficult process. In the end, this choice should be driven by application need and developer preference. Remember that developers have to work with the chosen edition day in day out—it's preferable all around if they're comfortable with it. At the same time, it's important to remember that developers need access to a server running the production edition—separate from the server used for testing. As with development server software, it's preferable to let the developers choose which editor or IDE they wish to use for development. A dependence on certain features in JDeveloper such as in-container debugging can point to an application whose logic is too closely coupled to the container. You should consider refactoring the application to facilitate out-of-container testing before you consider outfitting everyone with a copy of JDeveloper. In any development team there are substantial benefits to be gained from automation, and the effect is only multiplied in environments with multiple developers and multiple test and production servers. Use automation aggressively—if you have to perform a task related to the project that might need performing again, then automate that process—it will save you substantial amounts of time in the future.

Chapter 3: OC4J Installation and Runtime Behavior Overview OC4J Standalone Edition is a fast, lightweight J2EE development server that takes only minutes to install and run. In this chapter, we'll cover the following: Downloading and installing OC4J Standalone Edition Starting, stopping, and restarting the server Basic server architecture and runtime behavior, including classloading, default ports, and memory usage

Installing the Standalone Server OC4J Standalone has been certified to run under J2SE 1.3.1, 1.4.1, and/or 1.4.2 (depending on the platform). In most cases, applications developed using the standalone developer version will be deployed in production on a full Oracle Application Server 10g installation, so it's important to consider the requirements of each (see Chapter 1 for more information about the platforms supported by the full 10g Server). However, OC4J Standalone may be licensed for production use if the full version of Oracle Application Server 10g isn't needed. Before installing OC4J Standalone to a development machine, check that the intended host meets the requirements listed in Table 3-1. Table 3-1: OC4J Standalone Minimum Requirements Operating system

Any, subject to JDK availability

Disk space

At least 64 MB (plus development space)

Memory

At least 64 MB (256+ MB recommended for most enterprise projects)

Connectivity

Access to the Internet or to a copy of the standalone installation package (oc4j_extended.zip)

While OC4J is certified for Sun's Java Development Kit (JDK) (and JRockit, in the case of Linux on Intel), other JDKs such as IBM and Blackdown may work. Where possible, however, it's best to stick with a certified JDK for ease of support. Table 3-2 shows the certified minimum JDK releases. Table 3-2: OC4J Standalone Minimum JDK Support Platform

JDK Version

Red Hat Linux

1.4.2 or JRockit 8.1 SP1

UnitedLinux

1.4.2 or 1.3.1_06

Windows

1.4.1_05 or 1.3.1_06

Solaris

1.4.1_05

Table 3-2: OC4J Standalone Minimum JDK Support Platform

JDK Version

HP-UX

1.4.1_05 or 1.3.1_06

Downloading and Setting Up OC4J Standalone OC4J Standalone is distributed as a ZIP file (typically around 30 MB, depending on the specific release) with no formal installation routine. Simply unzip it to the appropriate directory, run one command to set up the administrator password, copy in a compatible tools.jar, and it's ready to run. Do the following: 1.

Download OC4J Standalone from the Oracle Technology Network. As of this writing, you can download it directly from http://otn.oracle.com/software/products/ias/devuse.html or by visiting www.oracle.com and clicking Download. Under Application Server choose OracleAS Containers for J2EE (OC4J), then Production Software. Tip

The link to the OC4J Standalone version is grouped with links to JDBC drivers. Be sure to download the full oc4j_extended.zip (28 MB for 9.0.4, 33 MB for 9.0.4.1), not just the drivers.

2.

Expand the downloaded file (oc4j_extended.zip). There's no formal installation process so unzip it to the directory you intend to use as your OC4J home. Once expanded, there should be a Readme.txt file and around 12 subdirectories, including one called j2ee.

3.

Open a command prompt and navigate to OC4J_HOME/j2ee/home.

4.

Run java -jar oc4j.jar -install to set the administrator password, as follows: C:\java\oc4j\j2ee\home>java -jar oc4j.jar -install Auto-unpacking C:\home\oc4j\j2ee\home\applications\dms0.war... done. Auto-unpacking C:\home\oc4j\j2ee\home\applications\dms.war... done. To enable in-process JSP compilation (which can be faster in some cases), please add the path to your tools.jar in application.xml Example:



Enter an admin password to use: password Confirm admin password: password If you are using J2SE 1.4 or higher, please ensure that all your imported classes are within packages, as required by the Java Language Specification. Installation done

Congratulations! You have installed OC4J. Tip

In-process JSP compilation (mentioned in the install message) is discussed in Chapter 4.

Testing Your Installation The OC4J installation includes a default web application with a welcome page and many JavaServer Pages (JSP) and Servlet examples. To verify that OC4J is installed properly, do the following: 1.

From the same directory (OC4J_HOME/j2ee/home), run java -jar oc4j.jar with no options.

2.

OC4J should start up and display something like this:

3.

C:\java\oc4j\j2ee\home>java -jar oc4j.jar

4.

Oracle Application Server Containers for J2EE 10g (9.0.4.0.0) initialized

5.

Open a browser and go to http://localhost:8888/, which should appear as shown in Figure 3-1.

6.

From this page, browse to the JSP examples as shown in Figure 3-2.

7.

Try out the Numberguess example. If OC4J is configured properly, you should see something similar to Figure 3-3.

Figure 3-1: OC4J welcome page

Figure 3-2: OC4J JSP Samples page

Figure 3-3: OC4J Number Guess page Tip

If this page displays an internal server error and produces an error message that the "major.minor version number" is too recent for this tool to understand, then it's probably compiling the JSPs with an incompatible version of tools.jar. See Chapter 4 for more details about compiler configuration.

Exploring the Server Directory Structure Once installed, the OC4J directory structure should look like Figure 3-4.

Figure 3-4: OC4J directory structure The most important of these is the j2ee/home directory, which contains configuration files, application deployments, and other resources. Most of the other top-level directories support value-added features and aren't heavily used by the Standalone Edition. The j2ee\home directory, often referred to as J2EE_HOME, contains a number of interesting subdirectories, including the following: application-deployments. This directory holds working files for deployed applications and isn't normally used by developers. However, clearing its contents forces OC4J to fully redeploy an application, which can be useful when testing deployment or debugging strange errors. applications. All deployed archives are stored here. For more about application

deployment, see Chapters 9–14. config. The config directory holds every XML configuration file used to manage OC4J. These files are described throughout this book, and can be either manually edited, or updated using the admin.jar tool. For more about editing configuration files, see Chapter 4. connectors. Resource adapters built using the J2EE Connector Architecture are deployed to this directory. These are usually used to connect J2EE applications to enterprise information systems other than standard relational databases (for example, an SAP or PeopleSoft system). For more about configuring and deploying Connectors, see Chapter 12. default-web-app. This directory is configured as the location of the default web application, and initially holds the welcome page and the JavaServer Pages (JSP) and Servlet examples installed with OC4J. For more about configuring and deploying web applications, see Chapter 10. demo. OC4J is packaged with many Enterprise JavaBeans (EJB) examples, all of which are available under this demo directory. Each includes its own Ant build file and configuration instructions. For more about configuring and deploying EJBs, see Chapter 11. jazn . This directory holds security configuration and data files. JAZN is Oracle's JAAS Provider implementation. For more about security, see Chapter 7. lib. This directory contains common libraries (for example, J2EE APIs, JDBC drivers, standard tag libraries, and so on) and is automatically placed on the classpath when the server starts. For more about the OC4J classpath hierarchy, see the section called "Classloading" later in this chapter. log. This directory holds the log files written by various OC4J modules. For more about logging, see Chapter 4.

Basic Operation Once the OC4J Standalone server has been installed, it can be managed entirely from the command line using two executable Java archive (JAR) files. In this section, we'll cover starting, stopping, and restarting the server, both manually and as an automatic service. Generally, it's also useful to capture these commands and any preferred options in reusable batch or shell scripts.

Starting the Server Although later we'll use Oracle Enterprise Manager to start a full Oracle Application Server 10g installation, the standalone version can be started by executing oc4j.jar directly, within the J2EE_HOME directory, as follows: C:\java\oc4j\j2ee\home>java -jar oc4j.jar Once the server has been initialized, it should print a brief message, and start accepting connections. Tip

To start OC4J from any directory, create a system environment variable called J2EE_HOME that points to the j2ee/home directory within your OC4J installation.

Though oc4j.jar is frequently executed without any command-line options, there are a few useful ones available, as described in Table 3-3.

Table 3-3: OC4J Startup Options Option

Description

-install

Completes all necessary installation tasks, including the activation of the admin account and the rewriting of configuration files with the appropriate line endings for the host platform.

-out

Redirects standard output to the specified file.

-err

Redirects standard error to the specified file.

-quiet

Suppresses standard output.

-validateXML

Validates all XML configuration files as they are loaded.

-userThreads

Allows context lookups from user-created threads.

monitorResourceThread s

Additional thread-debugging output.

-version

Prints the OC4J version number.

-help

Prints usage information, including a list of these options.

Several other options are listed in the usage information, but aren't fully functional in this release. Later in this chapter, we'll cover additional Java Virtual Machine (JVM) options that may be used to improve performance. Tip

Use the -validateXML option with care; the OC4J document type declarations (DTDs) often have errors, so validation may reject legitimate configuration files.

Stopping the Server Before we move on to discuss how to shut down and restart the server, please note that the shutdown and restart options described in the these sections should only be used on a standalone server that has been launched by executing oc4j.jar, as described in the previous section. Please see Chapter 15 for details about starting and stopping full Oracle Application Server 10g instances. OC4J should be stopped using admin.jar. This utility takes a host, an RMI port, a username, a password, and a command, as shown here: java -jar admin.jar ormi://host.domain.com<:port> [command-options]

The host should be the machine on which the server is running. The RMI port can be found in the rmi.xml configuration file, and defaults to 23791. The username is normally admin, and the password should be whatever you set it to during installation. Most admin.jar commands deal with configuration and deployment and will be discussed later in this book. To stop the server, use the following shutdown command, which accepts two options: -shutdown [force|ordinary] [reason]

The first option controls whether the server will be allowed to terminate normally, or will be forced to shut down immediately. It defaults to ordinary. The second option indicates a reason for the shutdown. If specified, this reason will be recorded in the server log. For example, to stop the server normally, allowing time for all threads to shut down, you might execute this: C:\java\oc4j\j2ee\home>java -jar admin.jar ormi://localhost:23791 admin mypassword -shutdown "Testing the shutdown process" To force a shutdown, you might execute the following: C:\java\oc4j\j2ee\home>java -jar admin.jar ormi://localhost:23791 admin mypassword -shutdown force If all else fails, you can manually kill the process through the operating system, usually by either hitting Ctrl-C in the terminal, or by finding and terminating the process if it's running in the background.

Restarting the Server Often, it's necessary to restart the server to apply configuration changes. Rather than stopping and starting the server in two steps, you can use the -restart command defined in admin.jar. Like -shutdown, this command accepts an optional reason for the log: -restart [reason] Here's an example: C:\java\oc4j\j2ee\home>java -jar admin.jar ormi://localhost:23791 admin mypassword -restart "Restarting to add data source" Tip

When it receives the restart command, OC4J only prints a single "Restarting" message. By default, it doesn't print a message to indicate that the restart was successful.

Sample Scripts This section includes sample scripts to start and stop OC4J. These should be placed in and run from the j2ee/home directory, though you can modify them to run from other directories. Note that the UNIX scripts must be marked as executable (using a command such as chmod u+rx). UNIX Start Script (start.sh) #! /bin/sh java -Xms128m -Xmx512m -jar oc4j.jar UNIX Stop Script (stop.sh) #! /bin/sh java -jar admin.jar ormi://localhost admin (password) -shutdown force Windows Start Script (start.bat) java -Xms128m -Xmx512m -jar oc4j.jar

Windows Stop Script (stop.bat) java -jar admin.jar ormi://localhost admin (password) -shutdown force

Running as a Windows Service The OC4J Standalone distribution doesn't support installation as a Windows service. However, on many Windows versions, it's possible to manually configure it as a user-defined service using additional tools. Tip

For a free package that installs Java programs such as OC4J as Windows services, see http://wrapper.tanukisoftware.org/doc/engli sh/.

The full Oracle Application Server 10g package includes built-in support for execution as a Windows service. See Chapter 15 for more details.

Running as a UNIX Service OC4J Standalone doesn't include built-in support for execution as a UNIX service, but it can be configured as one in the typical way. For example, on a UNIX system using System V Init scripts, you might do the following: 1.

Create scripts to start, restart, and shut down the server as described earlier in this chapter (making sure that the start script starts the server as a background process and redirects stderr and stdout to appropriate log files).

2.

Create a script in the init.d directory (often /etc/init.d, /etc/rc.d/init.d, or /sbin/init.d), following the usual conventions. These scripts generally accept start, stop, and restart arguments and in this case, should invoke the appropriate scripts from step 1.

3.

Create appropriate links in the rc#.d directories, where # is the runlevel. Some operating systems have a utility to manage this, such as chkconfig on Red Hat Linux and UnitedLinux.

Once you've configured these scripts, the server will be started and stopped according to the runlevel configuration, and you can start and stop it manually by invoking the main script under /etc/init.d with the start, stop, and restart arguments. Tip

For a free package that installs Java programs such as OC4J as UNIX services, see http://wrapper.tanukisoftware.org/doc/english/. Of course, copying and customizing an existing init.d script would work just as well.

Runtime Behavior Before you move on to server configuration, it's important to understand certain key elements of the server architecture and runtime behavior. In this section, we'll discuss the basic server architecture, classloading schemes, ports, protocols, memory usage, and compilers.

Server Architecture OC4J Standalone provides a complete J2EE 1.3-compliant environment for J2EE applications. This means that it supports web applications, EJBs, Java Naming and Directory Interface (JNDI) and all of the other standard J2EE technologies we discussed in Chapter 1. However, it doesn't

include value-added features such as Single Sign-On or Personalization. Figure 3-5 gives a quick visual overview of OC4J's general architecture, which is very similar to that of most other J2EE servers. Don't worry if you haven't used all of these technologies—each will be discussed in a lot more detail in later chapters.

Figure 3-5: Server architecture In particular, make note of the following: Multiple HTTP listeners can be configured to accept requests from web clients on various ports, thereby directing them to individual web applications according to context mappings. Each website can define one default web application to be mapped to the root context. RMI and RMI-IIOP ports can be defined to allow Java and CORBA clients to access JNDI, EJBs, and other resources. JMS servers can be configured with individual ports and JMS destinations. J2EE applications can contain web applications, EJB modules, Connectors, and application clients, and are deployed in a hierarchy, with child applications able to access the resources of their parents. Any application with no defined parent becomes a child of the global application. Web modules also inherit settings from the default web application configuration. DataSources, Connectors, and two-phase commit coordinators can be configured both at the global level and by individual J2EE applications.

A default XML-based JAAS Provider is available to manage user, group, and rolebased security, but can be replaced by a custom implementation.

Classloading Many J2EE developers agree that classloading errors can be among the most difficult to understand and fix, especially when running within an application server. Due to ambiguities in the J2EE specification, some server vendors have designed incompatible classloading architectures that can make it difficult to migrate an application without code changes. The following section looks at OC4J's classloading scheme and how to avoid potential pitfalls.

Review of Java Classloading Every class used in a Java application must be initially loaded using a classloader. This classloader may load the byte code from a file, the network, a parent classloader, or one of many other possible sources. With the exception of the bootstrap classloader (which is responsible for loading the ClassLoader class itself), these classloaders are all Java objects that can be instantiated and arranged in a hierarchy with the following properties: A child classloader can see classes loaded by its parent. When it receives a request to load a class, a child classloader will delegate to its parent first, and only load the class itself if its parent is unable to. Classes loaded by two different classloaders aren't compatible. Once loaded, a class can never be unloaded. However, the classloader can be destroyed and a different classloader can be used to load a new copy of the class. Many Java applications have no need for multiple classloaders, and get by with the most basic configuration—a bootstrap classloader to load the very first classes (before the ClassLoader class exists), an extension classloader to load any Java extensions, and a system classloader to load all of the classes required by the application, as shown in Figure 3-6.

Figure 3-6: Standard J2SE classloader hierarchy In this scenario, when a class needs to change, you just replace its class file and restart the JVM.

J2EE Classloading When moving to an enterprise environment, you'll probably start to see a few problems with this

default classloading scheme. First, you would like your application server to be able to manage several individual applications within a single JVM. However, if all classes are loaded through the system class-loader, then every application will be able to see and use any class loaded by any other application—not a very secure setup! Trying to manage this entirely through security policies would be tedious and prone to errors, particularly when two applications depended on a single library, or worse yet, two different versions of that library. Furthermore, with just one classloader, changes to any application require you to restart all of them. This kind of frequent downtime is rarely acceptable. Thus, instead of depending on the system classloader, it looks like you'll need at least one per application, and possibly one for the server itself so that it can keep its own internal classes hidden from the applications it runs. This will keep each application independent of all the others, and allow you to easily reload it by destroying and re-creating its classloader, as shown in Figure 3-7.

Figure 3-7: Typical J2EE classloading hierarchy In practice, since these applications are component based, J2EE vendors go one step further and create multiple classloaders for each J2EE application, giving you even more flexibility (and complexity).

OC4J Classloading Although the preceding scheme divides components into independent, reloadable pieces, it introduces a new problem. If individual modules have their own classloaders, how do you share classes between them? Declaring dependencies in manifest files works fine for modules within the same J2EE 1.2 application since all shared objects pass through serialization. However, with EJB 2.0, objects can be passed directly from one module to another through local interfaces. Unless the two modules can somehow share a classloader, we'll end up with a ClassCastException on the other side. To solve this problem, as shown in Figure 3-8, OC4J and other servers chain the class-loaders within an application, creating one Connectors classloader, which is parent to an EJB classloader, which in turn is parent to any web application classloaders.

Figure 3-8: Classloading within a J2EE application Of course, this still doesn't help us share code between applications, so OC4J has added a number of additional proprietary extensions, as shown in Figure 3-9.

Figure 3-9: Full OC4J classloader example First, there's a global Connectors classloader that loads any Connectors to which all applications should have access (as configured at the server level). Similarly, a global application serves as the parent to all other applications, loading any libraries that should be available to all. See Chapter 9 for more about configuring global applications. Besides these global classloaders, OC4J also allows any application to specify another application as its parent. In the previous example, both Application C and Application D share a parent Application B. Any EJBs or libraries made available within B will be visible to both C and D. See Chapter 9 for more about configuring parent applications. Tip

The J2EE specification recommends (but doesn't require) that web application classloaders load classes from within the WAR before looking to their parent classloaders. This behavior can be enabled in OC4J (9.0.4) within the orion-web.xml descriptor, as described in Chapter 10. This might be desirable, for example, if the web application and EJBs both need to use a library that loads application classes dynamically. Without this option, the classes would only be loaded at the EJB level, and would get ClassNotFound exceptions when trying to load and use web application

classes on the fly).

Troubleshooting All of this complexity can give rise to a number of classloading headaches during development. The following sections describe some troubleshooting tips for three of the most common. ClassNotFoundException This exception occurs anytime you're trying to explicitly load a class that cannot be found, for example, with a Class.forName("someClass"). Check whether a shared library loaded by a top-level classloader is trying to dynamically load a class only available at a lower level. Whenever you have to specify class names in a configuration file, it's a good clue that the code that requires that configuration file will be dynamically instantiating those classes. So make sure that both that code and the classes you listed are being loaded by the same class-loader. For example, if the Struts web framework has been placed anywhere higher than the web application level, it will be unable to load the web application classes you reference in your Struts configuration file. NoClassDefFoundException This exception occurs when a class depends on another class that cannot be found. Check that no dependencies have been missed, or split across classloading levels. This usually happens when you've compiled a bunch of classes together, but didn't deploy all of the class files, or put some of them in a separate JAR at a lower level. You can prevent this from occurring in the future by packaging all dependent classes in the same JAR. If you must split them up, declare any dependencies on other libraries in each JAR's manifest file, like this: META-INF/MANIFEST.MF File Placed Inside JAR to Declare Dependencies Manifest-Version: 1.0 Class-Path: format.jar dataaccess.jar drivers/oracle.jar For example, if classes in CurrencyUtils.jar depend on and were compiled against classes in NumberUtils.jar, but you don't include NumberUtils.jar in your application or system classpath, then you'll see this error. This will also happen if CurrencyUtils.jar is placed on the system classpath, but NumberUtils.jar is only included down in your application. You can usually solve this problem by adding an entry to the manifest file inside CurrencyUtils.jar to indicate that it depends on NumberUtils.jar (available at some relative path). Other options are to repackage all of those classes into one JAR, or to move CurrencyUtils.jar down to the same level as NumberUtils.jar. Tip

For more information about manifest files, see Sun's Java tutorial online at http://java.sun.com/docs/books/tutorial/jar/basics/manifest.h tml.

ClassCastException This exception occurs when some code has attempted to cast an object of one class to another incompatible class. If no obvious problems are found, it may be that the same class was loaded by two classloaders. In particular, if a web application has been configured to load classes from its lib directory before going up the classloader hierarchy (see Chapter 10), then be sure that it doesn't try to use these classes to interact with EJBs that load their own versions of those classes. Also, be careful about passing objects between two different applications through static variables or Singleton classes. If each application loads its own version of the shared classes,

they will be incompatible. For example, suppose you have two web applications that both depend on a Singleton class called CacheManager, which keeps a static HashMap of request keys and content. You place a JAR with this CacheManager implementation at the top level. At runtime, your first application calls into CacheManager to store a Java bean so that it can be used by future requests of the same type. Later, your second application retrieves that object from the CacheManager and tries to cast it to its bean type. Unless that bean implementation class was loaded by a shared classloader (such as the system classloader), the second application will get a ClassCastException error when trying to cast it, even if both applications include the implementation class. Fortunately, this can usually be fixed by not using static variables (which are unsafe across clusters anyway), thereby ensuring that shared classes are only loaded once by a shared class-loader. If you must share content, make sure it's serialized and deserialized along the way. Tip

Every time an application is reloaded (that is, "hot deployed"), it gets a new classloader. This means that objects stored by an application in a systemlevel Singleton may be unrecognizable to a newly deployed version of the same application. Avoid this by using a more traditional form of persistence (database, file, and so on) or by using classes or interfaces loaded at the same level as the Singleton, so that they won't be affected by the reload.

For more information about classloading in OC4J, see the "Classloading in Oracle9iAS Containers for J2EE" white paper at http://otn.oracle.com/tech/java/oc4j/pdf/ClassLoadingInOC4J_WP.pdf.

Ports and Protocols The OC4J Standalone server uses a number of configurable ports. These might need to be changed, for example, to run multiple OC4J servers on the same machine. You might also want to allow network access to these ports through a firewall. Table 3-4: OC4J Default Network Ports Protocol

Default Port

Configuration File

HTTP

8888

http-web-site.xml (and other *-website.xml files)

HTTPS

None

http-web-site.xml (and other *-website.xml files)

IIOP

5555

internalsettings.xml

IIOP over SSL

5556

internalsettings.xml

JMS

9127

jms.xml

RMI

23791

rmi.xml

Though these ports are also used in a full Oracle Application Server 10g instance, many of the defaults are different. Furthermore, when using the Oracle HTTP Server, most web traffic will come in through a dedicated port for communications between the web server and OC4J, rather

than hitting OC4J's HTTP listeners directly. See Chapter 16 for more information about the ports used in a full Oracle Application Server 10g installation.

Performance and Memory Usage Though most performance tuning is usually saved for the production environment in which you're running a full Oracle Application Server 10g installation, it's usually worthwhile to tweak JVM parameters in a development environment to improve speed and stability. In many cases, the easiest way to get a quick performance boost is to increase the size of the heap. This ends up decreasing the frequency of garbage collection and reducing your applications' susceptibility to OutOfMemory errors. (Of course, if these errors are frequent, it may be a sign of memory leaks within those applications.) You can alter the heap size using the JVM options -Xms and -Xmx. For example, the following command sets the initial heap size to 128 MB and the maximum heap size to 512 MB: java -Xms128m -Xmx512m -jar oc4j.jar Whenever possible, the maximum should be set to at least 256 MB. However, it should never be set higher than the machine's available memory. If the system isn't heavily taxed, you may also want to raise the initial heap size so that the JVM doesn't need to pause to increase its size in the middle of a request. In production, once your applications are stable and predictable, it's common to set the minimum equal to the maximum so that the JVM starts with all the memory it will ever need. On UNIX systems, it may also be helpful to set the -server option. Although this increases startup time and memory requirements, it delivers greater performance in the long run. Usually, this means that it's not a great option for developer servers because they're frequently restarted, but it can often be useful for long-running system tests and QA servers. This is the default when OC4J is run within a full Oracle Application Server 10g instance on UNIX. For more tips about tuning OC4J for performance, see the "Oracle Application Server 10g Performance Guide" available at http://downloaduk.oracle.com/docs/cd/B10464_02/core.904/b10379/toc.htm.

Compilers Whenever an EJB is deployed or a JSP is invoked, the server needs to create and compile one or more Java classes. By default, OC4J uses Sun's Java compiler, but launches a separate process for every compilation task. It may improve performance to run the compiler in process or to specify a higher-performance third-party compiler such as Jikes. See Chapter 4 for more details about these compiler configuration options.

Summary The OC4J Standalone Edition is very easy to install, and you can manage it completely through the command line and a series of configuration files. Despite its small footprint, however, it's still a full-featured J2EE server with a lot of moving parts. Before beginning development, it's best to understand the basic server architecture, classloading scheme, and port assignments. It may also be helpful to experiment with JVM options that can be included in start scripts in order to improve performance.

Chapter 4: General Server Configuration Overview When first installed, OC4J can immediately deploy and run many simple J2EE components without any extra configuration. However, in most cases, you'll need to customize a few server settings to set up data sources, JMS queues, and other common resources. When using the OC4J Standalone Edition, these settings are changed by manually editing a collection of configuration files. In this chapter, you'll do the following: Look at all the server configuration files (many of which will be described more fully in later chapters). Learn which files are most commonly changed, and why. Explore strategies for managing multiple configurations on the same server. Walk through the configuration of log files, ports, transaction timeouts, and other server-level settings.

Working with Configuration Files OC4J Standalone is configured through a collection of files in the OC4J_HOME/j2ee/home/config directory. The root of these files is server.xml, which contains pointers to many of the other files as well as a number of server-level options (logging, transaction, timeout, deployment directories, and so on). Later in this chapter, we'll review each of these settings individually.

Configuring Application-level Resources Some settings and resources can be configured both globally and on a per-application basis. OC4J handles this by arranging all of your applications in a hierarchy in which children inherit configuration details from parents. At the top of this tree is the global application, configured in j2ee/home/config/application.xml. This doesn't represent a real application (unless you go out of your way to configure it like one). It's just a convenient place to configure shared resources and default values. For example, if you would like all of your applications to have access to a shared Java library, you can configure a entry inside application.xml. Tip

Don't confuse this global application.xml file with the application.xml deployment descriptor defined by the J2EE specification. The first is a global configuration file inside j2ee/home/config that contains OC4J-specific settings. The latter is found within the META-INF directory of each deployed application and it contains only standard J2EE elements.

Any settings or resources configured in j2ee/home/config/application.xml will be inherited by all other deployed applications. An individual application can override or add to these settings by including an orion-application.xml file within its META-INF directory. This file uses the same document type declaration (DTD) as j2ee/home/config/application.xml. Chapter 9 will walk you through each of the settings available in these two files and will provide useful tips for organizing your application hierarchy.

Editing Configuration Files All server configuration files can be edited directly in your favorite text or XML editor. However, changes will not take effect until OC4J is restarted. This is a good reason to define commonly changed elements at the application level instead of within the global application.xml file. For example, if you define your database settings in your application's orionapplication.xml file, then you can change them by simply redeploying the application. However, if you define them at the global level (in j2ee/home/config/application.xml), then any changes you make will necessitate a server restart. Tip

Once you've configured OC4J for the first time, check all modified configuration files into a version control system like Concurrent Versions Systems (CVS). This makes it easy to keep track of changes over time and revert to a known working configuration if problems occur. It also helps when following up on bug reports that may have already been fixed by configuration changes (since it helps you reconstruct the original setup).

Managing Multiple Configurations In many cases, it can be useful to maintain several different server configurations, particularly when staging releases or testing against different databases. Unlike the full Oracle Application Server stack, OC4J Standalone doesn't explicitly support multiple instances. However, there are many ways you can manage this on your own. Tip

If you want to be able to run two server instances simultaneously, you'll need to change the default ports so that they don't conflict. See the "Configuring Ports" section later in this chapter.

Multiple OC4J Directory Trees The easiest and most straightforward way is to duplicate the entire OC4J directory structure for each configuration. This makes sense in staging environments where you need to be able to test a configuration on its own and then take it live without changing any file references or startup scripts. However, it requires that you maintain separate copies of every configuration file and library, which is usually overkill if you just want to try out a few new settings or switch back and forth between databases.

Single OC4J Tree with Multiple Configuration Directories Another option is to share one OC4J installation, but keep the configuration files in different directories. In this case, you must start OC4J with a special command-line parameter that tells it where to find the appropriate server.xml file. Since all configuration files are loaded relative to the main server configuration file (usually server.xml), it's not necessary for everything to be kept in the default config directory. Instead, you can create several different configuration directories and just pass the appropriate server.xml file path to oc4j.jar using the -config option. For example, a typical setup might include the following directories shown in Table 4-1.

Table 4-1: Example Setup with Multiple Configuration Directories File/Directory

Description

j2ee/home/devConfig

A directory that contains a complete set of configuration files, with the main application data source pointing to the development database, with transaction timeouts set high, and with other special development-friendly settings

j2ee/home/testConfig

A directory that contains a complete set of configuration files with the main application data source pointing to the test database, with transaction timeouts set normally, with custom log settings, and so on

startDev.sh

A shell script that starts the server using the server.xml file in the development configuration directory with a line like this: java -jar oc4j.jar -config devConfig/server.xml

startTest.sh

A shell script that starts the server using the server.xml file in the test configuration directory, like this: java -jar oc4j.jar -config testConfig/server.xml

This option simplifies maintenance since you don't have to worry about your OC4J versions getting out of sync. Furthermore, you can use all the default filenames, which make it easy to copy files from one configuration to another once you've tested them. This is convenient for staging environments. However, it can be a hassle if you just want to tweak a few settings here and there, while letting changes to the rest affect both configurations.

Multiple Versions of Configuration Files in a Single Directory When you just want to try out a few new settings or allow easy switching between databases and security schemes, the easiest option is to create one or more duplicate server configuration files (in other words, renamed copies of server.xml) within the same config directory. These will start out referring to all the same default configuration files (application.xml, data-sources.xml, and so on) and then you can just customize the parts that should be different. For example, you might have the following directories shown in Table 4-2. Table 4-2: Example Setup with Multiple Configuration Files in One Directory File/Directory

Description

j2ee/home/config/d ev-server.xml

A server configuration file that sets up development-friendly server settings and points to a special devapplication.xml file containing your development database settings

j2ee/home/config/t est-server.xml

A server configuration file that sets up test-friendly server settings and points to a special test-application.xml containing your test database settings

startDev.sh

A shell script that starts the server using the development version of server.xml with a line like this: java -jar oc4j.jar -config config/dev-server.xml

Table 4-2: Example Setup with Multiple Configuration Files in One Directory File/Directory

Description

startTest.sh

A shell script that starts the server using the test version of server.xml with a line like this: java -jar oc4j.jar config config/test-server.xml

Finding the Right Configuration File The most commonly edited server configuration files are undoubtedly server.xml and application.xml. However, in most cases you'll also need to configure database access in data-sources.xml, set up URL mappings to your web applications in http-web-site.xml, and customize one or more security files. Table 4-3 describes each server configuration file and the most common reasons to change it, along with where to find more information about it in this book. Table 4-3: Server Configuration Files File

Description

server.xml

Root configuration file, which contains server settings and references to other files. This is frequently changed to deploy applications, configure logging, configure the transaction timeout, and so on.

application.xm l

Contains default J2EE application settings and is most often changed to configure security and shared libraries.

datasources.xml

Allows configuration of JDBC DataSources to allow managed access to databases.

global-webapplication.xm l

Contains default web application settings that allow you to tweak JSP tuning parameters, file extensions, and so on. Rarely used during development.

http-website.xml

Allows configuration of virtual hosts, default web applications, Secure Sockets Layer (SSL) and other web settings. Most often changed to configure URL mappings for web applications.

internalsettings.xml

Contains RMI-IIOP settings. Most often changed to resolve IIOP port conflicts when running multiple servers on one machine.

java2.policy

Security policy, which restricts the file, property, and runtime permissions granted to code executing in the container.

jazn.xml

Allows configuration of JAAS security providers.

jazn-data.xml

Stores JAAS security data when using the XML provider type.

jms.xml

Allows configuration of the default JMS implementation.

mime.types

Maps MIME types to file extensions so that the HTTP server sets response headers correctly.

oc4jconnectors.xml

Contains settings for global Connectors, which can be used to access external systems other than databases (for example,

Table 4-3: Server Configuration Files File

Description mainframes, accounting systems).

principals.xml

Stores user and group configuration for the default security manager.

rmi.xml

Contains RMI and clustering settings. Most often changed to resolve RMI port conflicts when running multiple servers on one machine.

Warning

For now, since you're working with OC4J Standalone, you can edit these files directly, and any changes to them will be automatically discovered when you restart the server. However, when working with the full Oracle Application Server stack, it's best to update them through the command line or with graphical tools. Otherwise, you'll need to run a synchronization command to tell the server that the configuration has changed. For more information on these tools and the full Oracle Application Server stack, see Chapter 16.

Configuring Logging To new users, OC4J can seem much quieter than other application servers. This is because, by default, it doesn't log routine events to the console (though your application may be generating plenty of noise there with its own debug statements). Instead, OC4J logs different types of events to different files in the j2ee/home/log directory. Table 4-4 gives the (default) name and description of each log file, along with the configuration file that lets you change its name and location. Table 4-4: Log Files Log File

Description

globalapplication.log

Logs all global application events and errors. This is the application log for the global application and is configured in j2ee/home/config/application.xml.

jms.log

Logs all JMS-related events and errors. The name/location of this file can be changed in jms.xml.

rmi.log

Logs all RMI-related events and errors. The name/location of this file can be changed in rmi.xml.

server.log

All events and errors not logged in other log files (for example, server startup, server shutdown, internal errors, other events and errors not related to applications, websites, JMS, or RMI). The name/location of this file can be changed in server.xml.

application.log

Logs all events and errors related to a single deployed application. The name/location of this file can be changed inside the application's orion-application.xml descriptor (see Chapter 9).

http-web-

Logs all web access for a particular website. Each website can

Table 4-4: Log Files Log File

Description

access.log

configure its own separate access log in its j2ee/home/config/*-web-site.xml configuration file.

Configuring Log Filenames and Locations Each log file can be renamed and moved by editing the appropriate configuration file (listed in Table 4-4). For example, the name and location of the web-access log for a website can be configured in its *-web-site.xml like this: ... ... All other log files are configured like this: ... ...

Relative file paths always start from the same directory as the server.xml configuration file (which defaults to j2ee/home/config). However, it can also be useful to specify absolute paths if you want to write logs to a special partition or give log access to developers who don't have access to the server directory. For example, you could place the following snippet in your application's orionapplication.xml file in order to have the log write out to the /var/oc4j/acmestore.log, as follows: Tip

Absolute file paths aren't very portable across servers and can particularly cause trouble when moving configuration files between Windows and UNIX environments. During development it usually makes sense to use relative file paths if possible.

Redirecting Standard Output and Error Streams By default, when an application writes to System.out or System.err, the output goes to the console. This can be inconvenient if OC4J is running as a background process on a server, or if you need to search the output for a debug message. In these cases, you can redirect either or both to log files by passing command-line parameters to oc4j.jar like this:

java -jar oc4j.jar -out log/acmestore-out.log -err log/acmestoreerror.log Tip

If you need a finer level of control over application logging, take a look at the Apache Jakarta Log4J project (http://jakarta.apache.org/log4j/) or the new logging facilities in Java 1.4.

Using OC4J Debug Parameters Many times it's difficult to debug an application problem without figuring out how a particular request was handled by OC4J. Table 4-5 lists debug parameters that can be passed in to OC4J as system properties. When enabled, each logs additional useful debug information. Table 4-5: Debug Parameters Log File

Description

http.session.debug

Logs HTTP session events (for example, session creation, invalidation, and so on); useful when debugging logout sequences and other session-related code

http.cluster.debug

Logs HTTP clustering events

http.error.debug

Logs HTTP errors

datasource.verbose

Logs data source and connection information; useful for troubleshooting connection leaks or sizing connection pools

jdbc.debug

Logs JDBC calls; useful for debugging SQL errors

ejb.cluster.debug

Logs EJB clustering messages

transaction.debug

Logs transaction information; useful for debugging rollback exceptions, deadlocks, and data inconsistencies

rmi.debug

Logs extra RMI information; useful when debugging client applications or communication between J2EE components applications on different servers

rmi.verbose

Logs even more RMI information

jms.debug

Logs extra JMS information

For example, to debug a database connection leak, you might enable data-source logging to see when connections were being opened and released, as shown here: java -Ddatasource.verbose -jar oc4j.jar

Configuring File Locations Most of the time, there's no need to change the default names and locations of the server configuration files. However, if you want to maintain two separate versions of one configuration

file (for example, data-sources.xml) without duplicating the entire config directory, then you can simply edit server.xml or application.xml to point to the correct version. For example, if you want to be able to easily switch the configuration of the JMS topic called CustomerEvents, then you might create two versions of server.xml, each of which contained a element pointing to its own version of jms.xml. You can then switch between the two topics just by telling OC4J which server.xml to use at startup. Table 4-6 shows the configuration files that can be moved or renamed by editing server.xml. Table 4-6: Configuration Files Referenced in server.xml Configuration File

Line in server.xml

jms.xml



rmi.xml



application.xml



global-webapplication.xml



http-web-site.xml



Table 4-7 shows the configuration files that can be moved or renamed by editing application.xml. Table 4-7: Configuration Files Referenced in application.xml Configuration File

Line in application.xml

data-sources.xml



oc4jconnectors.xml



principals.xml



jazn-data.xml



As with log files, all paths are relative to server.xml.

Configuring Ports When OC4J starts up, it begins listening for connections on a number of ports. In general, these port assignments are fine for development, but the following are several common cases in which you may want to change them: When running more than one instance of OC4J on the same machine When running other servers or services that conflict with OC4J's default ports When setting up HTTP traffic to run over port 80 so that you don't need to include the port number in your URLs When enabling HTTPS

Fortunately, each of the ports used by OC4J is configurable.

HTTP By default, the built-in HTTP server accepts connections on port 8888, but you can edit httpweb-site.xml to change this port. For example, to run your web application on port 7001, you might use a file like this: In either of these cases (port 8888 or port 7001), you must include the port number in the URL when accessing your web applications, like this: http://localhost:8888/store/

To allow users to access a web application over HTTP without having to specify a port number in the URL, set the port to 80, which is the standard HTTP port. Then your URL will instead look like this: http://localhost/store/ Of course, if you're using UNIX, you may require root access to be able to bind port 80. Tip

You can configure multiple websites with different ports and settings, each configured through its own *-web-site.xml file. Each of these files will follow this same format but should use a unique port to avoid conflicting with the others. For example, if you want to run an admin web application on a different port, you can add , copy the http-web-site.xml file to admin-web-site.xml and edit the port and web application attributes.

HTTPS OC4J doesn't include a default HTTPS configuration. However, you can easily create one by copying http-web-site.xml and adding a few security settings. Like HTTP, your HTTPS website can use any port. Tip

When running multiple sites on nondefault ports, many developers use consecutive port numbers for HTTP and HTTPS (for example, 8888 and 8889). Others use some variation of the standard HTTP/S port assignments (for example, 8080 and 8443).

For example, to allow secure access to your web application over port 7002, copy your basic http-web-site.xml file, add the secure attribute to the website element, and use the sslconfig element to tell OC4J where to find your keystore and which password to use, as shown here:

Tip

This example uses password indirection for the keystore-password element instead of including it in plain text. The value ->admin tells OC4J to look up the admin user in the security UserManager and use its password to access the keystore.

To allow users to access a web application over HTTPS without having to specify a port number in the URL (for example, https://appserver.acme.com/securestore), set the port to 443, which is the standard HTTPS port. As with port 80, you'll usually need root access to bind port 443 on a UNIX machine.

Java Message Service JMS allows the use of asynchronous messaging between J2EE components, and with external message producers and consumers. Within jms.xml, you can easily configure the port on which JMS listens for incoming requests. In this case, the JMS server will listen on port 9127, as follows: ... See Chapter 6 for greater detail on use of JMS in OC4J. Tip

The default ports in OC4J Standalone are different than the default ports in the full Oracle Application Server stack. Never hard-code these ports in client applications, but instead pull them out into properties files that can easily be changed as you move the code from server to server.

Remote Method Invocation RMI is a technology and protocol used by Java applications to access other Java applications remotely. In particular, it's used by client applications to access EJBs across a network. Within rmi.xml, you can easily configure the port that listens for RMI requests, like this: See Chapter 13 for help more information about how to use RMI to access EJBs.

IIOP Internet Inter-ORB Protocol (IIOP) is a protocol used by CORBA applications to access remote objects. In a J2EE server, you can make your remote EJBs available over IIOP (in addition to normal RMI) to allow easy integration with these CORBA applications. In OC4J, IIOP is disabled by default, so if you won't need it, you don't need to worry about port conflicts. To enable access over IIOP, add the following line to your server.xml configuration file:

Then edit the internal-settings.xml file to customize the IIOP ports that your CORBA

client applications will use to connect. In the following default example, IIOP will be available unsecured on port 5555, with SSL server authentication through port 5556 and with both client and server authentication on port 5557: Once everything is configured, run the server with IIOP enabled by adding the GenerateIIOP system parameter to your OC4J startup command, like this: java -DGenerateIIOP=true -jar oc4j.jar Tip

Any EJBs already deployed before IIOP was enabled will need to be redeployed to trigger the generation of client stubs.

See Chapter 13 for more information about configuring client applications to access EJBs over IIOP.

Configuring Compilers When JSPs and EJBs are deployed, OC4J must generate and compile Java implementation classes to support them. By default, OC4J will use the compiler bundled with the JDK being used to run the server and will launch a separate process every time it needs to compile something. This can be very slow, so you'll probably want to change it to run in process, or choose an alternative, faster compiler, such as jikes. Experiment with both options to see which works best on your platform.

In-Process Compilation Many compilers, including the default javac compiler, can be run directly within the JVM without needing to launch a separate process. This significantly reduces overhead, and in some cases, can shave minutes off your deployment and startup times. To enable in-process compilation with javac, add the following line to server.xml:

Compiling with Jikes Jikes is an open-source and freely available compiler that is often much faster than javac, even though it doesn't support in-process compilation. Your results may vary depending on your platform and application. To configure OC4J to compile using jikes, add the following line to server.xml and fill in the appropriate bindir value: You can download Jikes from the IBM developerWorks website. For more information, visit http://www-124.ibm.com/developerworks/oss/jikes/.

Configuring Transactions The Java Transaction API (JTA) services protect data integrity and are critical to most enterprise applications. Almost all JTA settings are configured through data sources and EJB settings, as described in Chapters 5 and 11, respectively. However, server.xml does contain the following two very important settings.

Transaction Timeout The transaction timeout controls how long a transaction can run before it's rolled back. When set too high, one long-running search or deadlock can bring the server to its knees as database connections are queued up, waiting for tables to be freed. When set too low, some legitimate queries or updates may run out of time and fail. The following example sets the transaction timeout to 60 seconds (the default): This is much too high for most web applications, since few users are willing to wait 60 seconds for a response. Ideally, you should lower this value to the length of your longest running query or update. For many applications, 10 seconds is sufficient. If you find that you need a timeout greater than 30 seconds, you many want to try redesigning the code.

Transaction Recovery Occasionally, the server may encounter a fatal error in the middle of a global transaction, which as a result is never committed or rolled back. These transactions are written to a file, thereby allowing OC4J to attempt to complete them the next time it starts. This behavior can be configured inside server.xml, using the recovery-procedure attribute of the root element. For example, the following (default) configuration tells the server to always attempt to recover transactions: The allowed values are as follows: automatic. OC4J will automatically attempt to recover interrupted transactions. prompt. OC4J will prompt the user at the console before recovering transactions.

ignore. OC4J will never recover interrupted transactions (faster).

Configuring Other J2EE Services In addition to the services described so far, you can use server configuration files to configure security, database access, JMS, JavaMail, and global J2EE Connectors (also known as resource adapters). These services are complex enough that each is covered in its own chapter, as shown in Table 4-8. Table 4-8: Other J2EE Services J2EE Service

Refer To

Database Connectivity (JDBC)

Chapter 5

Java Message Service (JMS)

Chapter 6

Security

Chapter 7

JavaMail

Chapter 8

Global Connectors

Chapter 12

Configuring HTTP Connection Throttling When a web application experiences overwhelming traffic, it's better if you start queuing or dropping some connections than to exhaust server resources trying to serve them all at once. Within server.xml, you can set limits on the number of simultaneous connections allowed and choose how many connections should be queued before incoming requests result in server errors or redirects to a specified URL. The following example shows the default configuration:

In this case, if the server needs to start refusing some requests, it will return "Server Busy" errors instead of the requested pages. If you would prefer to have it redirect to a user-friendly error page, just include that URL inside the element, as follows: http://www.acme.com/unavailable.html The element allows the following attributes: Value. The maximum number of HTTP connections that will be serviced concurrently. The default is 100,000, which is probably unmanageable on most hardware configurations. socket-backlog. The maximum number of HTTP connections that will be queued before socket connections are rejected. The default is 30. max-connections-queue-timeout. The maximum number of seconds that a connection may remain in the queue before the server sends a busy notification or

redirect to the client and drops the connection. The default is 10. The optimal value for each of these parameters is highly dependent on the underlying hardware and operating system. To tune, run load tests and observe how many concurrent connections the application server can handle before performance becomes unacceptable. Set your max-httpconnections value a bit lower than this breaking point and run tests to ensure that the server no longer fails under excess load. This gives you a good baseline, from which you can systematically adjust all three parameters to find the best-performing combination. Tip There are a number of open-source and commercial load generators Tip that will let you create a test plan through your browser and then execute it hundreds or thousands of times in parallel, to simulate heavy traffic. If you have the budget, take a look at Mercury's LoadRunner (www.mercury.com/us/products/performancecenter/loadrunner/). Otherwise check out the open-source JMeter project (http://jakarta.apache.org/jmeter).

Configuring Deployment Behavior Applications can be deployed to OC4J Standalone in three different ways (each of which is described in detail in Chapter 9): By editing server.xml to add an element Through the command line, using the admin.jar utility By placing the application in an auto-deploy directory (in other words through "hot deployment") Within server.xml, you can configure the directories used for autodeploying, staging, and running applications, and Connectors. You can also control which applications are started automatically when the server starts, which can be useful for balancing server startup time vs. responsiveness to the first user request. The following example from server.xml file shows the default OC4J configuration: ... The following sections describe the attributes. As with other configuration files, all file paths are relative to the location of server.xml.

Application-Auto-Deploy-Directory This attribute specifies the "hot deployment" directory. Any updates to EAR files (or in the case of exploded deployments, any updates to META-INF/application.xml) in this directory will be noticed and will prompt OC4J to redeploy the application. This is very useful during development to avoid the hassle of manually redeploying or restarting the server every time the application is rebuilt. Instead, you can just have the last step of the build process copy the EAR file into an autodeployment directory. Alternatively, if your project build directory is laid out in the same way

as an EAR, you can just make that the autodeployment directory and you don't have to create an EAR at all. No autodeployment directories are configured by default.

Application-Directory This specifies the directory in which application archives that are deployed through admin.jar will be stored. This is basically just a staging area for EARs before they're exploded into the deployment-directory. The default value is ../applications.

Deployment-Directory This attribute specifies the directory in which applications will actually be deployed (in other words, exploded, compiled, validated, and run). This directory is generally only touched by the server itself and the default value is ../application-deployments.

Connector-Directory This attribute specifies the directory in which global Connectors will be deployed. The default value is ../connectors. Connectors (also known as resource adapters) are J2EE components that allow access to external systems other than databases (for example, mainframes, billing systems, and so on). Global Connectors are made available to all applications within the server. Other Connectors can be deployed as part of a J2EE application (see Chapter 12).

Auto-Start-Applications This attribute controls whether deployed applications are automatically started when the server is started. If you set it to true (the default setting), all applications will be fully initialized when the server starts. If set to false, then applications will not be initialized until the first user request. However, individual applications can override this false value, thus allowing a limited subset of deployed applications to be started automatically. When working with one application, it generally makes sense to leave this parameter set to true. However, when multiple applications are deployed, you may want to decrease server startup time by only automatically initializing the applications that are used the most. For example, if you've deployed a J2EE testing application that you occasionally use to test your EJBs, you may not want to wait for it to be deployed every time you bounce the server. Instead, you just have to wait a few extra seconds for it to load (automatically) if and when you do decide to use it.

Configuring Applications Of course, the driving purpose of a J2EE server is the configuration and deployment of J2EE applications. Fortunately, most of your server-side code can be portable and doesn't need to change to run within OC4J. However, like most other J2EE servers, OC4J extends basic J2EE with additional features that can be configured through server-specific configuration files, which in turn get packaged and deployed alongside the standard J2EE deployment descriptors. For example, in addition to the standard ejb-jar.xml that defines EJBs, transaction attributes, and security settings, you can include an orion-ejb-jar.xml that maps fields to underlying tables and columns and configures the database isolation level.

Table 4-9 maps each J2EE descriptor to the corresponding OC4J descriptor and indicates where this is covered in the book. Table 4-9: Mapping OC4J Deployment Descriptors to J2EE Deployment Descriptors J2EE Descriptor

OC4J Descriptor

Refer To

application.xml

orion-application.xml

Chapter 9

web.xml

orion-web.xml

Chapter 10

ejb-jar.xml

orion-ejb-jar.xml

Chapter 11

ra.xml

oc4j-ra.xml

Chapter 12

application-client.xml

orion-application-client.xml

Chapter 13

Once you've customized all of your descriptors and packaged the application, you can deploy and run it without any further configuration. See Chapter 9 for more information about J2EE packaging and deployment.

Summary You can manage OC4J Standalone entirely through configuration files. The most important of these are server.xml and application.xml, both of which configure server-level settings and provide references to other useful configuration files. The next ten chapters will walk you through many of these other files and explain the services that you can configure with them.

Chapter 5: Configuring JNDI and JDBC Services Overview Most J2EE applications need to access at least one database through JDBC. The recommended way to access databases from JDBC is to do it with JNDI and a data source object. Therefore, in this chapter, you'll cover the following: How to configure JNDI How J2EE applications typically access databases The types of JDBC drivers and data sources available How to configure these to work with Oracle and other databases

Java Naming and Directory Interface JNDI is a generic interface that provides a common set of functions for accessing naming and directory services. Used together with other J2EE technologies, JNDI can provide a centralized storage mechanism for components in a distributed computing environment. A naming service in computer terms allows for objects (maybe printers, computers, contacts, or Enterprise JavaBeans) to be associated with a unique name. Using the naming service, applications can then gain access to these resources using their unique name. A directory service is an extension of a naming service that allows for attributes to be associated with the stored objects. There are many different types of naming and directory type services, such as Lightweight Directory Access Protocol (LDAP) (a directory service), DNS (a naming service) and even the file system of your computer. When you use JNDI you can access all these directory services with a standard API that abstracts the underlying implementation of the directory away from your application. For more information on the use of JNDI in general, check out the documentation at http://java.sun.com/products/jndi/. Although the directory access capabilities of JNDI are an important part of J2SE, its naming capabilities are a cornerstone of the J2EE environment. All J2EE application servers are required to provide an internal naming service, accessible via JNDI, in which you can store resources for your application. In many cases these resources can be configured externally from your application, allowing for changes to be made to application components without the need to modify the Java code. The implementation of this service is left to the choice of the application server vendor, and for the most part is unimportant to your application. The collection of resourceto-name bindings within the application server is called a context. The most common resources stored in the application server context are Java Database Connectivity (JDBC) DataSources, Enterprise JavaBeans (EJB) references, Java Message Service (JMS) destinations, and JavaMail sessions. In this chapter you'll see how to set the JNDI location of a DataSource object. You'll find JNDI examples for the other resource types in the relevant chapter, as follows: For more information about setting the JNDI location of a JMS connection factory or destination, see Chapter 6. For more information about setting the JNDI location of a JavaMail session and about configuring arbitrary environment settings, see Chapter 8. For more information about setting the JNDI location of an EJB, see Chapter 11. In the case of all these resources, Oracle 10g AS allows for external configuration.

Within the JNDI context you can also manually store additional resources for your application. For instance you may have a set of error messages that you want to be available throughout your application. If this is the case you can place them in the JNDI context. However, from a practical point of view, using JNDI resources for what are essentially lightweight resources isn't a good idea. You could just as easily create a simple external Java properties file to store the error messages and load this when your application starts. In practice, JNDI is more suited to storing objects that represent some kind of resource, not just configuration values.

Understanding JNDI Locations There are three types of JNDI locations, each of which has its own visibility. Global locations can use any namespace (as long as it doesn't begin with java:/) and are accessible to any component or client that's allowed to access JNDI. Local locations begin with java:/comp/ and are only accessible to components within the container. Finally, a separate local java:/comp/env/ namespace is configured for each individual component and prepopulated based on its deployment descriptor. Most resources, such as DataSources, JMS destinations, and JavaMail sessions are bound to global locations such as jdbc/OracleProductDataSource and jms/MQSeriesOrderQueue. Often, these are then mapped to local component references like java:/comp/env/jdbc/ProductDB and java:/comp/env/jms/OrderQueue, which you can look up within your EJB or Servlet code. You can also specify environment entries in your deployment descriptors. These will be made available to your components in the java:/comp/env/ namespace. Note

You'll see an example of the global and component-local namespaces in Chapter 8.

The containerwide java:/comp/ namespace is most often used when obtaining a user transaction from java:/comp/UserTransaction. In most cases, however, your applications will deal with the global namespace (for configuration) and the local namespace.

Getting a JNDI Context To access JNDI, you must first create a javax.naming.InitialContext. This is easy within the container, where all JNDI properties are already configured and you can simply use the default constructor, like this: Context ctx = new InitialContext(); Client applications, on the other hand, need to first configure the following JNDI properties. These can either be passed as a map to a special InitialContext constructor, or included in a jndi.properties file in the root of the classpath, as shown here: java.naming.factory.initial=com.evermind.server.rmi.RMIInitialContextFa ctory java.naming.provider.url=ormi://localhost/yourApplicationName java.naming.security.principal=admin java.naming.security.credentials=yourAdminPassword Customize the URL, principal, and credentials as appropriate for your application. Using the configuration file is the preferable solution since you can avoid hard-coding the attributes into your application.

Accessing Databases from J2EE Applications J2EE applications interact with databases in a variety of different ways. For example, a typical ecommerce application may need to create and update product records, search for products that match certain criteria, and update a separate inventory database when an order is placed. In each of these cases, the application does the following: Obtains a JDBC connection object (an instance of java.sql.Connection). Executes one or more SQL queries or commands. Closes the connection. This is easy to accomplish directly through the JDBC APIs. Unfortunately, the simplest approach isn't very scalable or maintainable. The following two examples show the differences between traditional JDBC access and the more complex but powerful J2EE approach.

Simple Database Access in Non-J2EE Environment In a basic Java application, you might write the following code to remove products that have passed their expiration date: // Load your JDBC driver class so that it can register itself with DriverManager Class.forName("oracle.jdbc.driver.OracleDriver"); // Declare your connection var outside the try block so that we can clean it up later Connection c = null; try { // Get connection from DriverManager with a JDBC URL, username, password c = DriverManager.getConnection("jdbc:oracle:thin:@myserver:1521:mydb", "scott", "tiger"); // Execute some SQL command Statement s = c.createStatement(); s.execute("UPDATE product SET active=0 WHERE expiration_date < sysdate"); s.close(); } finally { // close your connection c.close(); }

This code is very clean and straightforward. You load a driver, get a connection, execute the update, and then close the connection. Note

In this example and others throughout this chapter, exception catching and null checks have been omitted to improve readability.

Of course, life gets a lot more complex once you start thinking about where to store data-base usernames and passwords, how to throttle the number of simultaneous connections, how to ensure that two updates don't clash, and how to roll back changes to a product database if updates to an inventory database are unsuccessful. In a J2SE application, you could try to solve each of these problems yourself with special driver implementations, configuration files, and direct manipulation of JDBC transactions. However, in the world of J2EE, these problems have already been solved for you with data sources, the Java Transaction API (JTA), and JNDI.

Database Access in a J2EE Environment With a J2EE application, you'll spend some extra time up front configuring a data source for your server, but then you'll be able to use it over and over again, from many different classes and applications, without worrying about drivers, usernames, passwords, or server locations. By default, OC4J data sources are configured in a file called data-sources.xml, which is located in the main server configuration directory (OC4J_HOME/j2ee/home). A typical data source declaration might look like this: You'll revisit all of these properties later in this chapter, but for now, notice that you've specified the name of a driver class (connection-driver), a JDBC URL, a username, and a password. You've also chosen a data-source implementation class and set up a few JNDI locations that control where your new data source will live in the global JNDI directory. When OC4J starts, it will initialize this data source and make it available in JNDI at those locations. Then your applications can access it with code like this:

// First, create a JNDI InitialContext so that we can look things up in JNDI InitialContext context = new InitialContext(); // Next, look the data source at the JNDI location we configured in data-sources.xml DataSource ds = (DataSource) context.lookUp("jdbc/ProductCatalogDS"); // Declare our connection var outside the try block so that we can clean it up later Connection c = null; try { // Get connection from the data source c = ds.getConnection(); // Execute some SQL command Statement s = c.createStatement(); s.execute("UPDATE product SET active=0 WHERE expiration_date < sysdate"); s.close(); } finally { // Close connection so the database can use those resources for another request c.close(); } Though the code doesn't look much different, this second approach makes it much easier to take advantage of enterprise features available in OC4J and other J2EE servers. In particular, you can use the following: Connection pooling. Lets you set upper and lower limits on the number of open connections. This cuts down on expensive initialization costs by reusing connections, and helps throttle access to the database so that it cannot be overwhelmed by a surge in requests. Container-managed persistence (CMP). This built-in J2EE persistence framework can automatically save and retrieve entity-bean contents using a specified data source. This means that instead of hand-coding SQL to insert, update, or delete products, you can work with product EJBs and count on OC4J to save any changes to the database. Java Transaction API (JTA). Lets you coordinate the success or failure across many different connections without needing to explicitly track, commit, or roll back each. You can mark the start and end of your transactions either programmatically (with UserTransaction) or declaratively (in your EJB deployment descriptors). Distributed transactions. OC4J provides support for Open Group's XA standard, which allows for the coordination of transactions across multiple databases or applications. In practice, this means that you can use more than one (XA-capable) data source in a single transaction. For example, you can configure your application so that any

associated updates to the product database will also roll back if updates to the inventory database fail. This is accomplished by a protocol called two-phase commit, which first asks each database whether it's capable of committing, and then commits or rolls back all of them together based on the results. Note that OC4J only supports two-phase commit for Oracle data sources. Improved monitoring and tuning. In addition to connection pool sizes, you can also configure transaction timeouts and many other properties that can improve your applications' performance and stability. You can also easily monitor transactions and connection usage through the server console. Portability. Since your code never references a specific driver or JDBC URL, you can easily change database or application servers without rebuilding the application. Instead, you just need to change a few server configuration files.

JDBC Drivers Though you'll use JDBC extensively to access your database, it doesn't provide built-in support for any particular database vendor. Instead, it assumes that an appropriate JDBC driver implementation has been loaded. In the first example, you loaded this driver class with Class.forName(). In the J2EE example, you just specified the driver class name in your data source configuration and the server loaded it for you. Out of the box, OC4J includes drivers for the following databases listed in Table 5-1. Table 5-1: JDBC Drivers Provided with OC4J Database

Driver Class Name

Oracle

oracle.jdbc.driver.OracleDriver Description: Includes a pure-Java driver implementation that connects directly to the database, as well as an Oracle Call Interface (OCI) driver that uses JNI to connect to a native Oracle client installation. When using the OCI driver, ensure that the ORACLE_HOME, LD_LIBRARY_PATH, and TNS_ADMIN environment variables are set properly so that the driver can find your Oracle client installation.

MS SQL Server

com.merant.datadirect.jdbc.sqlserver.SQLServerDriver

IBM DB/2

com.merant.datadirect.jdbc.db2.DB2Driver

Description: Pure-Java driver

Description: Pure-Java driver Sybase

com.merant.datadirect.jdbc.sybase.SybaseDriver Description: Pure-Java driver

If you need to connect to another type of database, you'll need to get a JDBC driver implementation for that database from the vendor and put it on your OC4J classpath. Usually, this means downloading a JAR and dropping it in OC4J_HOME/j2ee/home/lib. At the time of this writing, JDBC drivers for PostgreSQL and MySQL were available at the following URLs listed in Table 5-2:

Table 5-2: Additional JDBC Drivers Database

Driver Class Name

URL

PostgreSQL

org.postgresql.Driver

http://jdbc.postgresql.org/downloa d.html

MySQL

com.mysql.jdbc.Driver

www.mysql.com/downloads/apijdbc.html

Choosing the Right Driver As noted in the previous section, Oracle provides two types of drivers, OCI and thin, for clientside development. It also provides drivers intended for use when working inside the Oracle database, but we won't cover those here). The Oracle thin driver is a pure Java implementation, which makes it a Type 4 JDBC driver. The JDBC thin driver uses Java TCP sockets to connect directly to the database by emulating the Oracle SQL*Net Protocol. Thus, the thin driver requires a TCP/IP listener up and running at the database server, which is usually the case anyway. No software is required on the client-side (the machine on which the driver is operated), other than a suitable JRE. As a result, the thin driver is platform-independent and can thus be used both in a traditional 3-tier setup, and even in a 2-tier setup without an Oracle client, such as a Java applet accessed through a browser. If your environment has web-based clients, then the thin driver is the correct choice. The Oracle OCI driver (often called the thick driver) provides a part-Java, part-native JDBC implementation, which makes it a Type 2 JDBC driver. It interacts with the Oracle data-base through the OCI by invoking C language routines in the Oracle OCI libraries. As a result, Oracle client software has to be installed for each client connecting with Oracle through the OCI driver. This makes the OCI driver platform-specific, and it's supported only on those platforms for which the Oracle client software is supported. The OCI driver supports all installed Oracle Net Services adapters, including IPC, named pipes, TCP/IP, and IPX/SPX. Note

With Oracle 10g, there's now an option called "Instant Client," which significantly reduces the number of files it requires on the client machine.

If your JDBC client application is going to run on a machine where the Oracle client is installed, then you should consider the JDBC OCI driver because it will often provide better performance compared to the JDBC thin driver. If you need to use a networking protocol other than TCP/IP (a rare situation), then you must use the OCI driver. If you do have a choice of driver, then it's a good idea to run simple benchmarks tests to verify that the driver will give you the best performance for your application. This is usually quite a straightforward process. You can create a simple database table (called measurements, in the following example) to store your timing data. Then, having established your connection and so on (not shown here), your JDBC code may contain something like the following: //execute a series of SQL statements against the standard EMP, DEPT tables pstmt1 = conn.prepareStatement("insert into dept (deptno, dname, loc) " + "values (?, ?, ?)"); pstmt2 = conn.prepareStatement("update emp set deptno = ? " + "where ename in ('SMITH','SCOTT')");

pstmt3 = conn.prepareStatement("select count(*) from dept"); // Insert your timing data into the measurements table pstmt4 = conn.prepareStatement("insert into measurements (name, x, y) " + "values (?, ?, ?)"); // execute the tests, for varying numbers of executions try { for (int i = 0; i < Integer.parseInt(args[0]); i++) { execute(1); execute(10); execute(20); execute(30); execute(40); execute(50); } } finally { pstmt1.close(); pstmt2.close(); pstmt3.close(); pstmt4.close(); conn.close(); } } Note

Of course, in your own benchmarks you'll want to incorporate tests that match what your application is doing. For example, handling LOBs is one of those things that can change performance between the drivers.

The following execute() method takes the number of executions to make for an argument. It goes into a for loop and executes the specified number of statements. To measure the time it takes to execute, it uses the current system time, obtained with a call to System.getCurrentTimeMillis(), as follows: public static void execute(int count) throws SQLException { ResultSet rs; int cnt; // start the measurements long timestamp = System.currentTimeMillis();

long time; // execute a series of statements for (int i = 0; i < count; i++) { // create a new department pstmt1.setInt(1, 50 + i); pstmt1.setString(2, "DEPT #" + i); pstmt1.setString(3, "CITY #" + i); pstmt1.executeUpdate(); // move Smith and Scott to the new department pstmt2.setInt(1, 50 + i); pstmt2.executeUpdate(); // select the number of departments rs = pstmt3.executeQuery(); cnt = rs.next() ? rs.getInt(1) : 0; rs.close(); } Finally, the results of the measurements are logged in to the database, as shown here: time = System.currentTimeMillis() -timestamp; pstmt4.setString(1, "JDBC with OCI"); pstmt4.setInt(2, count); pstmt4.setLong(3, time); pstmt4.executeUpdate(); conn.commit(); } } You would repeat the tests a number of times for a specific driver in order to gain an average value, and then repeat the tests for your second choice of driver. You can then gather the results as follows: SQL> select x, oci, thin, thin-oci, trunc((thin-oci)/oci*100, 1) pct 2 3

from ( select x,

4

trunc(avg (decode(name, 'JDBC with OCI', y, null)),1) oci,

5

trunc(avg (decode(name, 'JDBC with thin', y, null)),1) thin

6

from measurements

7

group by x

8 );

Choosing a Data Source Type Now that you have a JDBC driver, you need to choose a java.sql.DataSource implementation. Data sources wrap around JDBC drivers and provide support for many of the advanced pooling, distribution and monitoring, and portability features mentioned earlier. OC4J allows you to plug in any data source implementation, but only supports JTA through the following two built-in implementations: com.evermind.sql.DriverManagerDataSource. This implementation supports the JTA specification and OC4J pooling and caching. However, even though it emulates XA support, it does not actually implement two-phase commit and other distributed transaction features. This makes it faster for single-database access but very dangerous in multidatabase situations (since it only pretends to go along with distributed commit and rollback decisions). com.evermind.sql.OrionCMTDataSource. This implementation is heavier, but provides true support for two-phase commit and other XA features. It also provides greater support for Oracle JDBC extensions. Using these reduces your database portability, but can be very useful when you've already made a long-term commitment to Oracle. For more information, visit the Oracle Technology Network (OTN) website at http://otn.oracle.com/. Thus, for applications that access only one database and don't need any vendor-specific features, you're usually best off with the built-in DriverManagerDataSource. If you need twophase commit (to access more than one database in the same transaction) or Oracle-specific extensions, OrionCMTDataSource is the natural choice. Finally, if you need other vendorspecific functionality (for example, DB/2 extensions) and can live without JTA, then you may want to look for a third-party data source implementation specific to that database.

Configuring Data Sources By default, OC4J data sources are configured within data-sources.xml inside in the OC4J_HOME/j2ee/home/config directory. However, the name and location of this file can be changed within the data-sources element of the application.xml configuration file. Initially, data-sources.xml contains one sample data source definition that uses DriverManagerDataSource to connect to an Oracle database. If your application only accesses a single Oracle database, then you can just customize the JNDI locations, username, password, and URL in this sample definition. If you need to access a non-Oracle database, you'll also need to change the connection-driver property. If you need support for transactions across multiple databases or non-Oracle extensions, then you'll need to specify a different data-source implementation in the class property. The following example shows possible configurations for a variety of drivers and data sources:









Customizing Data-Source Attributes As seen in the preceding example, a number of different attributes may be used to configure data sources. Some are required, while others have default values if not specified. Table 5-3 lists some of the common data-source properties that you will need to set, and then we move on to discuss some of the properties that determine how the data source behaves in operation.

Table 5-3: Data-Source Properties Attribute

Description

class

Fully qualified name of the java.sql.DataSource implementation class. As described earlier in this chapter, this should be com.evermind.sql.OrionCMTDataSource when using multiple Oracle databases with two-phase commit or com.evermind.sql.DriverManagerDataSource in most other cases (third-party data sources can also be used if non-Oracle extensions are needed, but don't work with OC4J's container-managed transactions).

location

JNDI name used to look up data sources that don't use the DriverManagerDataSource implementation (Note: DriverManagerDataSource data sources still have to specify a value here, but it isn't used. See ejb-location instead.)

xa-location

DriverManagerDataSource data sources must specify some value for this property, but it's never used to access them. See ejblocation instead.

ejb-location

JNDI name used to look up data sources that use the DriverManagerDataSource implementation.

name

Unique name for this data source. Defaults to the value given for ejblocation.

connectiondriver

Fully qualified name of the JDBC driver class. This will usually be oracle.jdbc.driver.OracleDriver for Oracle databases.

username

Name of the schema to which this data source should connect (for example, "scott").

password

Password that should be used to connect (for example, "tiger"). Alternately, this can be "->"followed by the name of the user whose password should be used, as long as that user is available through the configured UserManager. For example, if you have configured a user in OC4J called "scott" with password "tiger," then instead of putting "tiger" here as the password, you can put "->scott" and OC4J will look up and use the password of the user "scott."

URL

JDBC URL for database connections. If using the pure-Java Oracle driver, this will resemble jdbc:oracle:thin:@myserver:1521:mysid. If using the OCI driver, this will resemble jdbc:oracle:oci8:@:mytnsname. For non-Oracle drivers, consult the documentation or the examples earlier in this chapter.

The following sections discuss those properties that determine exactly how the data source behaves, such as how long it will cache an idle connection before closing it.

Inactivity-Timeout This is the number of seconds to cache a connection that's no longer in use before closing it. Defaults to 60 seconds. This is a bit low for most applications and is typically raised to at least

120 seconds or whatever length of idle time you normally expect between traffic surges. At low values, OC4J will spend a lot of time giving up and reacquiring connections between requests. At high values, your connection pool will tend to stay full unless there is a long period of inactivity. To tune this parameter, observe your connection pool size during periods of normal and high traffic. If it's constantly oscillating between min-connections and some higher value, then you may want to raise this value. Of course, if you don't need to conserve connections during low traffic, then you're probably better off just raising min-connections.

Min-Connections This is the minimum number of connections kept open for this data source (though not opened until the data source is first accessed). This defaults to 0, but that's usually much too low for a production application. It's important to stay within a range that your database can handle, but try to set it to at least as many connections as are used during normal load. If resources aren't scarce, consider setting it to the number of connections in use during peak load, since you probably don't want the expense of opening and closing connections during your heaviest periods (raising the inactivity-timeout can also help with this problem by preventing excess connections from being closed too rapidly). Once your application is stable, be sure to load-test your application with several different values to see how it responds. Though most applications perform better with larger connection pools, you may find that the reverse is true if your application relies on very complex queries that overwhelm the database when executed in parallel.

Max-Connections This is the maximum number of pooled connections allowed for this data source. By default, there's no maximum, but you should almost always set one. Under heavy load, a shared database often becomes the bottleneck and can quickly become overwhelmed or run out of connections, thereby causing unexpected errors and potentially starving other applications. It's usually a good idea to coordinate max-connections values among all applications using the database. You should ensure that the database is properly configured to handle the total. Typically, you can use load tests to determine the value at which your database becomes overwhelmed and performance begins to suffer. As noted under min-connections, some applications actually perform better when connections are limited.

Wait-Timeout This is the number of seconds that the data source will wait for a free connection before timing out. The default value is 60 seconds. In general, if you're seeing timeouts on connection requests, you should try raising max-connections first However, if your database can't handle more connections, then you can raise this wait-timeout value to get a bit of extra breathing room until you can tune the application or add more hardware. If you expect these kinds of delays during normal usage, it may be worthwhile to move to an asynchronous architecture and throttle the number of simultaneous requests at the application or JMS level.

Max-Connect-Attempts This defines the maximum number of unsuccessful attempts to open a connection before returning an error. The default value is 3. This is useful if you expect connection attempts to occasionally fail (for example, due to spotty network connectivity or overloaded database traffic). Of course, where possible it's usually better to address the source of the instability rather than increasing the time the application server spends making unsuccessful requests.

Customizing Data Source Properties A data source definition can also include elements, whose values are passed into the data source when it's initialized. In particular, the OrionCMTDataSource accepts two properties: cacheScheme and dblink. This cacheScheme property controls what happens when the maximum number of connections is exceeded. For example, to cause requests to block until a connection becomes available, you would add a child element to like this: Possible values for this property are FIXED_WAIT_SCHEME. Requests beyond the maximum will block until a connection becomes available. FIXED_RETURN_NULL_SCHEME. Requests beyond the maximum will return null (usually causing an error). DYNAMIC_SCHEME. Requests beyond the maximum will cause extra connections to be opened, but each will be closed and freed immediately when it's no longer in use. Caution

The cacheScheme property defaults to the DYNAMIC_SCHEME value, which means that the max-connections you set isn't a hard limit. If you need to cap the number of possible connections, be sure to change this to FIXED_WAIT_SCHEME or FIXED_RETURN_NULL_SCHEME.

The dblink property specifies the name of the database link to be used for this database by the commit coordinator during two phase commits. Examples are given later in this chapter in the "Configuring Two-Phase Commit" section.

Deploying Data Sources Once the data source has been configured in data-sources.xml, OC4J must be restarted before the changes will take effect. At this point, the new data source will be available through JNDI to all deployed applications. See Chapter 9 for more information about restricting data sources and other resources to particular applications.

Using Data Sources Once a data source is configured and deployed, you can use it within a J2EE application by locating it in JNDI, obtaining a connection, performing some work, and then closing the connection. In this example from earlier in the chapter, you use a data source to deactivate products whose expiration date has passed: // First, create a JNDI InitialContext so that you can look things up in JNDI InitialContext context = new InitialContext(); // Next, look the data source at the JNDI location you configured in data-

sources.xml DataSource ds = (DataSource) context.lookUp("jdbc/ProductCatalogDS"); // Declare your connection var outside the try block so that you can clean it up later Connection c = null; try { // Get connection from the data source c = ds.getConnection(); // Execute some SQL command Statement s = c.createStatement(); s.execute("UPDATE product SET active=0 WHERE expiration_date < sysdate"); s.close(); } finally { // Close connection so the database can use those resources for another request c.close(); }

Determining the Correct JNDI Location In the example, you looked up the data source at the JNDI location, jdbc/ProductCatalogDS. If you're using a normal DriverManagerDataSource, then this value should correspond to the ejb-location value that you specified for that data source in data-sources.xml. If this isn't a DriverManagerDataSource, then you should use the value of location instead. Note

In practice, you'll often use elements in your deployment descriptors to remap these global JNDI locations to local names. This general J2EE technique improves portability and is described fully in Chapter 8.

Overriding the Default Username and Password Though you'll usually configure a default username and password in data-sources.xml, you can override this by specifying a different username and password when obtaining a connection from your data source, like this: con = ds.getConnection("scott2", "tiger2"); This can be useful for applications with a limited number of users, particularly if you need to implement row-level security. Instead of embedding that logic in your application, you can use the database to enforce access controls and always connect to it using the login credentials of the current application user. It's important to note that multiple connections obtained from the same data source within a single transaction will share a single underlying "physical" connection, for which the first username and password specified will always be used. Attempting to use a

different username with that DataSource object within the same transaction will cause an exception. If this behavior isn't desirable, you can use a second data source or adjust your EJB transaction settings to force the use of a separate transaction for the alternate login.

Using Oracle JDBC Extensions Many Oracle-specific features are not available through the standard JDBC APIs. To access these features, you can cast your Connection object to oracle.jdbc.OracleConnection. This object can then be used to obtain Oracle-specific statements, result sets, and so on. Of course, tying your code to Oracle in this way reduces your application's database portability. If it may ever need to run against a different database, then you should try to isolate Oracle-specific chunks inside instanceof tests or in easily overridden methods.

Configuring Two-Phase Commit To access more than one Oracle database in the same transaction, you need to enable twophase commit by configuring a commit coordinator database and linking it to each of the other databases involved, as described here: 1.

Choose a database to act as the commit coordinator. This can be any of the databases involved in the transaction, or a separate database.

2.

Using your favorite Oracle client, create database links from the commit coordinator database to the other databases. For example, the following commands create links to the "product" and "inventory" databases: create database link productlink using "product"; create database link inventorylink using "inventory";

3.

Configure the two-phase commit coordinator by adding the following to OC4J_HOME/j2ee/home/config/application.xml (substituting the appropriate username and password):

5.

Define at least two regular data sources that should be able to participate in distributed transactions. Each of these data sources needs to use the OrionCMTDataSource implementation, and needs to specify a dblink property with the name of the corresponding database link that you created in step 2, as follows:

6.

Use the data sources normally.

Summary J2EE components deployed in OC4J can access any database that has a JDBC driver as long as an appropriate data source is configured in data-sources.xml. Of course, since most OC4J applications are built on Oracle databases, some functionality (for example, two-phase commit and simultaneous use of JTA and JDBC extensions) has only been implemented for Oracle data sources. Once configured, any data source can be located programmatically through JNDI and used to connect to a database. Data sources are also commonly used to configure persistence frameworks such as EJB CMP and the open-source Hibernate framework.

Chapter 6: Configuring Java Message Service Overview In the fast-moving world of technology, in which technologies come in and out of fashion, enterprise messaging has enjoyed a long and successful life. Enterprise messaging simplifies the process of inter-application communication, especially across platform boundaries, and it provides an excellent mechanism for systems integration, legacy or otherwise. Another common use of enterprise messaging is to provide asynchronous execution of code, something that's especially useful for executing long-running processes without the need to keep the user waiting around. Finally JMS is also quite useful for replicating data in a distributed environment, however, in most cases your relational database management system (RDBMS) will have much better support for this than JMS and will require less effort to set up. JMS provides a standard API to access enterprise messaging resources, allowing your application to leverage the power of messaging without having to worry about vendor-specific implementations. In this chapter we take a detailed look at JMS support in Oracle 10g AS. We'll show you how to configure the server, build a sample application to test your configuration, and use the JMS management tools for practical purposes. We won't cover every single parameter and property that can be set, because this is provided in excellent detail in the documentation. However, we'll point out those properties that sometimes cause confusion, or those places where you may want to consider changing the default setting. This chapter is split into two main parts. The first part covers Oracle Application Server JMS, the default JMS implementation used by Oracle 10g AS. The second part of the chapter looks at the use of additional JMS providers via the Resource Provider extension mechanism. Specifically, this section will cover Oracle JMS and SonicMQ. You should note that this chapter assumes an understanding of the JMS API and basic concepts of messaging. Wherever possible we'll explain JMS-specific topics as best as we can, but if there's something you don't understand then we recommend Richard Monson-Haefel and Dave Chappell's superb Java Message Service (O'Reilly & Associates, 2000).

JMS in Oracle 10g Application Server Out of the box, Oracle 10g AS comes with a single, built-in provider for JMS, Oracle 10g AS JMS. Oracle 10g AS JMS complies with version 1.0.2b of the JMS specification, the latest version of JMS being 1.1. On top of the standard provider, you can configure additional providers for Oracle JMS (OJMS) and other, third-party, messaging solutions. OJMS is the JMS-based interface to the Oracle Streams Advanced Queuing (AQ) feature of the Oracle database. It's important not to confuse Oracle 10g AS JMS with Oracle JMS. Oracle 10g AS JMS is an entirely in-container solution, whereas OJMS is based on the AQ technology and relies on the Oracle database. From a high-level the basic structure of a JMS-based application running on Oracle 10g looks like Figure 6-1.

Figure 6-1: High-level overview of JMS in Oracle 10g AS As you can see from the diagram, whether they're Enterprise JavaBeans (EJB), JSP, Servlet, or Standalone, clients interact with the messaging providers through Oracle 10g AS via the JMS API. The default provider, Oracle 10g AS JMS, is mapped to the java:comp/env/jms namespace within the Java Naming and Directory Interface (JNDI), while any external providers, linked in through the Resource Provider subsystem are mapped to the java:comp/resource namespace.

The Resource Provider Model Oracle 10g AS provides a flexible way to plug additional resources into the container. In this context, resources aren't just limited to JMS connection factories, but also JDBC data sources, JavaMail sessions, and URL connection factories. The basis of the Resource Provider is the ResourceProvider interface. There's no need for every single JMS provider to create its own implementation of the ResourceProvider interface. Instead, you can use the ContextScanningResourceProvider class shipped with 10g to integrate any JMS provider that maintains its own JNDI tree. The ContextScanningResourceProvider class provides a useful mechanism for binding resources that exist in an external naming context into the local context. Using this mechanism, you can bind the JNDI resources stored in any message provider's context into your application's context. Which is to say that if you're running a thirdparty JMS provider such as SwiftMQ, you can bind the JMS resources from the SwiftMQ JNDI tree directly into the Oracle 10g AS tree using ContextScanningResourceProvider. In this way you simply configure the ResourceProvider and then configure SwiftMQ as normal—the ContextScanningResourceProvider takes care of the JNDI bindings in Oracle 10g AS for you. The usage of ContextScanningResourceProvider is covered in more detail later in the "Configuring Third-Party JMS" section.

Configuring and Using Oracle 10g AS JMS As discussed earlier, the default JMS provider, Oracle 10g AS JMS, is enabled out of the box. To disable JMS in your environment simply comment out the following line in the server.xml file: From the preceding code you can probably tell that the path to the Oracle 10g AS JMS configuration file is jms.xml and that the file is stored in the same directory as server.xml. You can change the location of the configuration file by changing the path attribute to the path you want. However, you should think twice about doing this since you'll be moving the file out of its standard location, which may confuse others who have to manage your server. Also remember

that the default configuration keeps the JMS configuration in the same place as all the other configuration files— so why change this?

Standard Configuration The standard jms.xml file looks like this: A dummy queue A dummy topic Oracle Syndication Services Queue

--> Queue for replication scheduler --> Queue for Web Clipping -->
Due to the good use of XML, the configuration file is fairly self-explanatory. The elements are used to configure queues for point-to-point messaging, and the elements are used to configure topics for publish/subscribe messaging. Queues and topics are collectively known as destinations. Connection factories are configured using the and tags. For those of you who aren't totally familiar with the nuances of JMS, connection factories are used to obtain a connection to particular resource, be it a queue or a topic. The Queue and Topic interfaces defined in the JMS specification serve as an abstraction of the provider-specific destination name, not of the resource itself. The QueueConnection and TopicConnection interfaces encapsulate access to the resources identified by Queue and Topic objects. The QueueConnectionFactory and TopicConnectionFactory interfaces are designed to encapsulate provider-specific logic for obtaining a connection to the destination and to present a unified API to Java applications. Without these interfaces your application would need to

understand all the different, provider-specific, mechanisms for obtaining a connection to a destination. Unless you want to download and try out the examples from the Oracle website then you can safely remove the and tags for demoQueue and demoTopic. However, you should leave the other and tags (for the Web Clipping, Syndication Service and the UDDI replication service queues) in place, or at the most, comment them out so you can easily put them back in, because these features use them internally. To define transactional connection factories you can use the , , and elements. Use these factories if you want your queues to participate in Java Transaction Service (JTS) managed transactions. This can be useful in applications in which messaging is part of the critical application logic and must be performed as part of larger, atomic blocks, perhaps in conjunction with some kind of database management system (DBMS). Configuring the XA factories is no more complicated than configuring their nontransactional counterparts, but you should only use the XA versions if your messaging application definitely requires transaction support. Don't be tempted to use the XA versions "just in case" you might need transaction support in future. Transactions add a performance overhead, which is completely unnecessary if your application doesn't need them. As you'll see, by coding to interfaces (Connection and ConnectionFactory) and using appropriate configuration, you can completely change the destination configuration without affecting the code. In addition to whatever you configure in jms.xml, you'll find six built-in connection factories that your applications can use. These are available at the following JNDI locations: jms/ConnectionFactory jms/QueueConnectionFactory jms/TopicConnectionFactory jms/XAConnectionFactory jms/XAQueueConnectionFactory jms/XATopicConnectionFactory Each one of these is bound to an implementation of the corresponding interface. For the most part these predefined connection factories will serve the needs of your application. However, if you need settings other than the defaults, then just configure your own connection factories in jms.xml. In addition to these connection factories, there's also a default queue where all undelivered messages get placed. If you find that some of your messages just aren't getting through and you can't see why, check the jms/Oc4jJmsExceptionQueue queue. If your messages are in there, then it's likely that your code is correct but that you have a configuration error that's causing the messages to be undeliverable. If the message isn't in this queue, then the likelihood is that the message never reached Oracle 10g AS, which points to a coding error.

Building and Configuring an Application In the previous section you looked at the basics of configuration. In this section you'll put that knowledge to use and build and configure a full point-to-point JMS-based application. This application will implement two command-line tools: one that sends a message containing "Hello World" to a queue and another that receives and displays a message from the same queue.

Along the way, we'll show you how you can use the JMS command-line management tools to check that your application is functioning correctly.

Creating a Queue First, you need to configure the queue for the "Hello World" messages. Do this by adding a tag to the jms.xml configuration file, as shown here: A queue for the hello world "application" You can check that the queue is configured correctly be firing up OC4J and running the following command from the command line: java -cp "$J2EE_HOME/oc4j.jar" com.evermind.server.jms.JMSUtils / -username admin -password welcome destinations You should see the helloWorldQueue entry appear in the list. As far as server configuration goes, that's all that's required. The bulk of the configuration is done in the application configuration files. Note

The JMSutils tool, used here to check the existence of the queue, performs lots of useful operations on the Oracle 10g AS JMS server. We've described a few of the more useful ones in this chapter, but you'll find a full list in the documentation.

Creating a Base Class Both of the command-line tools you'll be implementing (the sender and the receiver) will need to look up the queue and get QueueConnection objects, so it's easiest to put this functionality into a base class, as follows: package com.apress.oracle10g.jms; import javax.jms.JMSException; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; public abstract class AbstractJMSClient { private static final String FACTORY_NAME = "java:comp/env/jms/QueueConnectionFactory"; private static final String QUEUE_NAME = "java:comp/env/jms/helloWorldQueue";

private QueueConnectionFactory factory = null; protected Queue getQueue() throws NamingException { Context ctx = new InitialContext(); //get the connection factory QueueConnectionFactory factory = getQueueConnectionFactory(); // get the queue Queue q = (Queue) ctx.lookup(QUEUE_NAME); return q; } protected QueueConnection getQueueConnection() throws NamingException, JMSException { return getQueueConnectionFactory().createQueueConnection(); } private QueueConnectionFactory getQueueConnectionFactory() throws NamingException { Context ctx = new InitialContext(); factory = (QueueConnectionFactory) ctx.lookup(FACTORY_NAME); return factory; } } This code simply wraps the JNDI lookups for the connection factory and for the queue. Notice that it uses local JNDI names (which start with java:comp/env) rather than referring to the actual JNDI locations specified in the configuration file. Later, you'll map these local names to real locations in your deployment descriptors, using and elements. This indirection gives you the flexibility to change what these names map to without changing any code. It also makes your code more portable between application servers. Of course, if you're just whipping up a quick test client and know that you won't need to change the JNDI locations, then you can just hard-code the actual JNDI locations instead. Check out Chapter 5 for more tips on using JNDI.

Implementing the Sender Now you can create a simple sender client, as shown here:

package com.apress.oracle10g.jms; import javax.jms.JMSException; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueSender; import javax.jms.QueueSession; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.NamingException; public class SendHelloWorld extends AbstractJMSClient { public static void main(String[] args) throws Exception { SendHelloWorld sender = new SendHelloWorld(); sender.send(); } public void send() throws JMSException, NamingException { // get queue and connection Queue q = getQueue(); QueueConnection connection = getQueueConnection(); // start... connection.start(); QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); // send QueueSender sender = session.createSender(q); TextMessage msg = session.createTextMessage(); msg.setText("Hello World!"); sender.send(msg); // close sender.close(); session.close(); connection.close(); System.out.println("Message Sent"); } }

The preceding code simply uses the queue and queue connection provided by the base class to create and send a textual message containing the words "Hello World."

Configuring an Application Client At this point you're almost ready to try out the code; all that's left to do is to create the application configuration files. The first one to create is jndi.properties, which contains the JNDI connection details, as follows: java.naming.factory.initial= com.evermind.server.ApplicationClientInitialContextFactory java.naming.provider.url=ormi://localhost/ java.naming.security.principal=admin java.naming.security.credentials=welcome The jndi.properties specifies the name of the JNDI context factory class, along with the URL, username, and password required to connect to the JNDI server. If you have OC4J running on a different machine or if you need to use a different username or password, then you should make the appropriate changes in your file. Next up, as shown in the following code sample, is the standard J2EE applicationclient.xml file, which is required by all standalone J2EE client applications: Hello World jms/QueueConnectionFactory javax.jms.QueueConnectionFactory Container Shareable jms/helloWorldQueue javax.jms.Queue In this file you're telling OC4J that this application client will need to be able to look up a connection factory at jms/QueueConnectionFactory and a queue at jms/helloWorldQueue. Note that the names used here are the local JNDI names (minus the java:comp/env prefix) that your application uses, not the real locations specified in

jms.xml. Next, create an orion-application.xml file. Inside it, map these local JNDI names to real locations, as follows:

Running the Client Once the code is compiled you can run it with the following: java -cp "classes:src/META-INF:$J2EE_HOME/oc4j.jar" \ com.apress.oracle10g.jms.SendHelloWorld This command assumes that the class files for your application are under the classes directory and that your application-client.xml and orion-application.xml configuration files are in the src/META-INF directory. If you've used a different directory structure, edit the cp (classpath) parameter accordingly. If the application runs successfully you'll receive a "Message Sent" message. If you don't get this message, check that the classpath is specified correctly, that OC4J is running, and that the queue is configured correctly. To check that the message actually made it to your queue, you can use the browse command of JMSutils, as shown here: java -cp "$J2EE_HOME/oc4j.jar" com.evermind.server.jms.JMSUtils username admin / -password welcome browse "Hello World Queue" The important thing to notice about the use of the browse command is that instead of the using the JNDI name for the queue, you have to use the "friendly" name that you specified in the name attribute of the tag. This means that if your name contains spaces, you need to enclose it in quotes. For this reason it's generally easier to use names that don't contain spaces. Running the browse command should yield output like this:


value="PERSISTENT" />


value="Queue[Hello World Queue]" />


value="0" />


value="4" />


value="false" />


value="null" />


value="1082451689466" />


value="" />


key="JMSXConsumerTXID" value="" />


key="JMSXDeliveryCount" value="1" />


key="JMSXProducerTXID" value="" />


key="JMSXRcvTimestamp" value="1082451693818" />


key="JMSXUserID" value="" />


key="JMS_OC4J_Type" value="textmessage" />


value="Hello World!" />

1 messages processed Near the bottom of the message you should see the element, which contains the value of the message in a tag. This output contains a lot of information about the message that can be used for diagnostic purposes if you're experiencing problems with your JMS application.

Implementing the Receiver Now that you have a message in the queue you can build a receiver to consume the message and display it in the console. The code for the ReceiveHelloWorld class is very similar to that of the SendHelloWorld class, as shown here:

package com.apress.oracle10g.jms; import javax.jms.JMSException; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueReceiver; import javax.jms.QueueSession; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.NamingException; public class ReceiveHelloWorld extends AbstractJMSClient{ public static void main(String[] args) throws Exception { ReceiveHelloWorld recevier = new ReceiveHelloWorld(); recevier.receive(); } public void receive() throws NamingException, JMSException { // get queue and connection Queue q = getQueue(); QueueConnection connection = getQueueConnection(); // start... connection.start(); QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); // receive QueueReceiver receiver = session.createReceiver(q); TextMessage msg = (TextMessage)receiver.receiveNoWait(); if(msg != null) System.out.println("Received: " + msg.getText()); else System.out.println("No message received"); // close receiver.close(); session.close(); connection.close(); } }

The main difference, of course, is that this class receives a message from the queue instead of sending one to it. Run the receiver using the following command in order to receive the message you just sent: java -cp "bin:src/META-INF:$J2EE_HOME/oc4j.jar" \ com.apress.oracle10g.jms.ReceiveHelloWorld You should receive a message informing you whether or not a message was received from the queue. Running the JMSutils browse command again should now show that no messages are left in the queue. As you can see, getting a basic JMS-based application up and running is easy. In the rest of this section you'll look at additional configuration options.

Configuring File Persistence The queue you created in the previous example was an in-memory queue. This means that if you send a message to the queue and then shut the server down, the message will be gone when you restart the server. In some cases this may be the desired effect, but in others you may wish to have some level of protection for failures in the server. Using file persistence, you can instruct Oracle 10g AS to persist messages in a particular queue or topic to the file system. To see this in action, you should first try sending a message to helloWorldQueue using the sender, and then shut down and restart OC4J. When you restart, use the JMSutils browse command to check the contents of the queue. You should find nothing there. To turn on file persistence for the helloWorldQueue, make the following modification to the jms.xml file: A queue for the hello world "application" Notice that the element now contains a persistence-file attribute that contains the path to the file where messages should be stored. If the file doesn't exist, then Oracle 10g AS will create it for you. The path specified can be either an absolute path or a path relative to the default persistence location specified in application.xml. You can change the default location by modifying the following entry in application.xml: Once you've updated jms.xml to specify a persistence file, restart the application server and send another message to the helloWorldQueue. Use the JMSutils browse command to verify that the message made it to the queue. Then restart the server and use the browse command to verify that unlike before, the message is still in the queue.

Persistence File Management The file format used by Oracle 10g AS is a vaguely decipherable binary format. Open the file up in a text editor and you'll be able to make out the gist of each message in between a mass of undisplayable characters. Although you could probably edit these files there would be no guarantee that it would work all the time and we certainly wouldn't recommend it. You're free to copy or delete persistence files when they aren't in use, but doing so while Oracle

10g AS is using them will result in an unrecoverable error. Provided you haven't disabled locking, a lock file that's used to synchronize access across multiple instances of Oracle 10g AS will accompany each queue. Lock files have the same name as the queue persistence file; they just have .lock bolted on at the end. In general, you should avoid playing with these files while the server is running. A normal shutdown of Oracle 10g AS will clean up the lock files used by the queues. However if Oracle 10g AS terminates without a proper shutdown, either because of an error or because you've killed the process, then some lock files may be left lying around. You should delete these before you restart the Oracle 10g AS server, since the state they contain will be inconsistent with the runtime environment. Be aware that there's a limit on the number of active file handles that Oracle 10g AS will maintain for persistent destinations. By default this is set to 64, meaning that Oracle will only maintain 64 active file handles for persistence. If you have more than this number of persistent queues then Oracle will open and close files as appropriate, which can slow down message delivery. You can change the maximum number of allowable file handles by setting the oc4j.jms.maxOpenFiles system property when starting Oracle 10g AS. This is useful if your operating system won't allow 64 open file handles for the process or if you wish to increase the number (within the bounds of the operating system) to increase performance. If you have a large number of persistent queues, then you should consider using OJMS (covered later in this chapter) instead of the default Oracle 10g AS JMS provider. OJMS is built on top of the Oracle database and is more reliable than simple file-based persistence.

Configuring Hosts and Ports By default Oracle 10g AS JMS will listen on port 9127 for all network interfaces in the machine. You can change the port number by editing the port attribute of the root tag in jms.xml as follows: If you want Oracle 10g AS JMS to listen on a single network interface, then you can also set the host attribute of the tag, as shown here: By default, connections obtained through connection factories will use the local JMS services configured in the jms-server element. To force all connections to go to a different server, adjust the host and port attributes on the connection factory element. For example, to force all connections obtained through myQueueConnectionFactory to go to the server listening on 192.168.1.57:9127, you might specify the following: This can be useful if you wish to redirect JMS operations to a different server, and is a valid reason for specifying a custom connection factory rather than using the default factories provided by Oracle 10g AS JMS.

Configuring Logging You can configure email and file-based logging using the element within jms.xml. By default, OC4J JMS logs to /j2ee/home/log/jms.log. This file is specified relative to jms.xml, like this:

If a mail session has been configured, events can also be logged to an email address, like this: By default the logging output includes WARNING, ERROR, and CRITICAL events, meaning that it only contains information when something goes wrong. You can increase the verbosity ofm the log by setting the oc4j.jms.debug system property to true. This will include all NORMAL level events—basically a trace of the actions taken by Oracle 10g AS JMS. When you set oc4j.jms.debug to true the log messages are written to stderr as well as to the log file. None of the log levels will write the message contents to the log. If you want to check the contents of a queue, then you need to use the JMSutils command-line tool that you saw earlier.

Configuring Oracle JMS In the previous section you saw how to create and configure an Oracle 10g AS JMS-based application. In this section you'll take that application and make it run against the Oracle JMS provider. As we mentioned earlier, Oracle 10g AS provides a standard mechanism with which you can plug in additional JMS providers: the ResourceProvider interface. Oracle 10g AS comes complete with an implementation of this interface, oracle.jms.OjmsContext, which enables Oracle JMS to be used as a JMS provider. Oracle JMS is based on the Oracle Streams Advanced Queuing (AQ) feature of the Oracle database. AQ is a full messaging system built on top of the Oracle database system supporting both point-to-point and publish/subscribe messaging. AQ has a vast array of features that improve upon plain JMS, but one of the biggest benefits of AQ is the fact that it has many different client libraries that allow it to be accessed from Java, C, PL/SQL and many more. This makes AQ a great way to integrate applications that were written using different languages. A full discussion of AQ is outside the scope of this chapter and this book, but we'll demonstrate how to configure a queue on a database that's running AQ in the following section.

Setting Up the Queue Configuring an OJMS queue is mostly a database process. The first step is to create a user with the appropriate permissions, and then, using the DBMS_AQADM package, create the tables and queues in that user's schema. The following SQL script will create the user jmsuser and give him the appropriate permissions. It will then create the queue and queue table within the jmsuser schema. DROP USER jmsuser CASCADE ; GRANT connect, resource,AQ_ADMINISTRATOR_ROLE TO jmsuser IDENTIFIED BY pwd ; GRANT execute ON sys.dbms_aqadm

TO

jmsuser;

GRANT execute ON sys.dbms_aq

TO

jmsuser;

GRANT execute ON sys.dbms_aqin

TO

jmsuser;

GRANT execute ON sys.dbms_aqjms

TO

jmsuser;

connect jmsuser/jmsuser; BEGIN DBMS_AQADM.CREATE_QUEUE_TABLE( Queue_table

=> 'helloWorldQueueTbl',

Queue_payload_type

=> 'SYS.AQ$_JMS_MESSAGE',

sort_list => 'PRIORITY,ENQ_TIME', multiple_consumers

=> false,

compatible

=> '8.1.5');

DBMS_AQADM.CREATE_QUEUE( Queue_name

=> 'helloWorldQueue',

Queue_table

=> 'helloWorldQueueTbl');

DBMS_AQADM.START_QUEUE( queue_name

=> 'helloWorldQueue');

END; / quit; If you want to create a topic destination rather than a queue, just set the multiple_consumers parameter of the CREATE_QUEUE_TABLE procedure to true.

Configuring Oracle 10g AS Configuring Oracle 10g AS for the Oracle JMS provider requires modifications to two configuration files: the global application.xml and data-sources.xml. The first step is to configure the resource provider in the application.xml file, as shown here: OJMS/AQ Though the description isn't important, the name you specify in the tag is, because it will be used later as part of the JNDI name for resources managed by the Oracle JMS provider. The OjmsContext resource provider also requires you to specify a element with the name of the data source it should use. This should point to the database holding the Oracle AQ queue. Therefore, it's necessary to configure a data source in the data-sources.xml file that points at that Oracle database server, as follows:

If you used the SQL script described earlier to create the queues in Oracle AQ, then the username and password will be the same—otherwise you should change them to match your environment. The URL for your Oracle database will undoubtedly be different than the one configured here, so make sure that you change that to match your environment as well. At this point, the resource provider you've configured should be available globally to all applications. If you wish to set up a resource provider specific to an individual application, move the declaration from the global application.xml file to that application's orion-application.xml file.

Configuring the Hello World Application All that's left is to reconfigure the application so that it uses the Oracle JMS queues instead of the Oracle 10g AS JMS queues. Because we used local JNDI names in the Java code and in the application-client.xml file, all that's required is a change to the orion-applicationclient.xml file, as shown here: You'll notice that we've changed the location attributes to the values required by Oracle JMS. To build these location strings, start with the prefix, java:comp/resource, which is used by all resource providers. Follow that with the resource provider's name: in this case, oraclejms. After that the remainder of the location is specific to the resource provider. For Oracle JMS, queue connection factories are accessed under the QueueConnectionFactories name and queues are accessed under the Queues name. Likewise you can access topic connection factories and topics using TopicConnectionFactories and Topics. The name used for the queue connection factory in the final part of the location attribute is unimportant, unless you require access to a specifically configured connection factory. The configuration of connection factories in AQ is outside the scope of this chapter, but you'll find more details in the online AQ reference at http://download-

west.oracle.com/docs/cd/B13789_01/server.101/b10728/toc.htm. Tip

If you're having problems getting this example to work, start OC4J with the datasource.verbose system property set to true. This will output some fairly detailed information about the data sources and will help you to trace the behavior of the data source that's configured for the AQ server.

Before you run the sender to test the Oracle queue, run a SELECT COUNT(*) FROM helloWorldQueueTbl query on the helloWorldQueueTbl table in Oracle to make sure the current message count is zero. After running the sender, run the SELECT query again to check that the message is in the queue.

Configuring Third-Party JMS If you want to access queues and topics that aren't in Oracle 10g AS JMS or Oracle JMS, you can configure the application server to use additional JMS providers. Oracle 10g AS provides a ResourceProvider interface as a standardized mechanism for linking in these third-party providers. However, rather than relying on individual manufacturers to build adapters for their products, Oracle provides an out-of-the-box ResourceProvider implementation the ContextScanningResourceProvider class, which binds objects from an external JNDI tree into the local tree. This mechanism works well because most JMS providers tend to bind their objects into a JNDI tree. Using ContextScanningResourceProvider, you can use a third-party provider for the Hello World application. We've chosen to use SwiftMQ because it's available as a small evaluation download for both Windows and UNIX platforms—it even runs on Mac OS X. Plus the installation is a breeze! Visit the SwiftMQ website at www.swiftmq.com and download the evaluation version of the SwiftMQ Router. The download is available in a TAR format for UNIX and a ZIP format for Windows. The scripts in each release are specific to the operating environment. To install the SwiftMQ Router, simply extract the archive to a suitable location and you're done. SwiftMQ already comes with some preconfigured queues for testing, so rather than create a new one, just fire up the first router by running ${SWIFTMQ_HOME}/scripts/unix/smqr1.sh script. For Windows users, the location for the start script is ${SWIFTMQ_HOME}/scripts/win32/smqr1.sh. The next step is to add an additional entry to the global application.xml file, as shown here: SwiftMQ resource provider.

From the preceding code you can see that the ContextScanningResourceProvider is configured with three properties. First, it requires the java.naming.factory.initial and java.naming.provider.url properties—without them it won't know which JNDI tree to search for resources. The resource.names property specifies which resources in SwiftMQ's JNDI tree should be bound into the local JNDI context. Here, we've included the testqueue queue and the plainsocket connection factory from router 1. The next step is to point the local names used by the Hello World application to the SwiftMQ resources instead of the Oracle 10g AS JMS or Oracle JMS resources that they're currently bound to. As mentioned before, this is simply a matter of making the appropriate change in orion-application.xml:

Again, you'll notice that the JNDI names for the external resources have the prefix java:comp/resource followed by the resource provider name that's specified in application.xml and then the provider-specific name. Now for the interesting part—the documentation states that you should be able to simply drop the swiftmq.jar file into the $J2EE_HOME/lib directory, start up the server, and everything will be OK. Unfortunately, that's not the case. After placing the .jar file in every lib directory in the OC4J directory, after attempting to configure it as an additional within application.xml, and after starting up, OC4J still informed me that it was unable to find the com.swiftmq.jndi.InitialContextFactoryImpl class. We tried this on OC4J on Mac OS X, Linux and Windows as well as on Oracle 10g AS Standard for Windows, but it didn't work on any of those installations. In the end we decided to take a different approach and instructed Java to load the swiftmq.jar into the classloader hierarchy above OC4J—that way it would be available to OC4J at startup. To do this, specify the bootclasspath option when starting OC4J, as follows: java Xbootclasspath/a:$SWIFT_MQ/jars/swiftmq.jar:$SWIFT_MQ/jars/jms.jar \ -jar oc4j.jar You'll notice that we also load the jms.jar file supplied with SwiftMQ. This is because SwiftMQ requires classes that aren't available in the OC4J JMS distribution. You should now be able to run your Hello World sender and receiver applications in order to send and receive messages using the SwiftMQ message queue.

Picking Your Provider Choosing which kind of provider to use can be a difficult decision, but in most cases following a few simple steps can make the decision easier.

First, it's perfectly acceptable to use a different provider for development and production—just be sure to test on the production provider during development. In most cases Oracle 10g AS JMS will prove the best choice for development. Oracle 10g AS JMS is fast and simple to configure, making it an ideal proposition for developers who would rather focus on coding than on wrestling with their development environment. Another reason for using Oracle 10g AS JMS for development is that it can be configured and monitored in isolation. Using Oracle JMS for development means that somebody has to install and administer the Oracle instance used for AQ. Choosing which provider to use for production is more difficult, however, in some cases your environment may have already made the decision for you. For example, if you're using Oracle 10g AS on top of a database other than Oracle then you can automatically rule out the use of Oracle JMS. Furthermore, many systems are built on top of existing infrastructure that may include a substantial investment in messaging techniques. If this is the case then it's often wise, from a business point of view, to use the messaging infrastructure already in place, especially if you'll be integrating with existing applications. When choosing between Oracle 10g AS JMS and Oracle JMS, look at your performance, reliability, management, and integration needs. If your application only uses messaging internally and persistence isn't important, then Oracle 10g AS JMS is your fastest option. However, if you're using persistence, this performance difference disappears and Oracle JMS provides far more in terms of reliability, ease of backup, and management. Like other external providers, Oracle JMS is also very useful when you want to use messaging as a mechanism for interacting with other applications, especially those written in languages other than Java. Because Oracle JMS sits on top of AQ, you can use any AQ client library to access the messages sent to Oracle JMS from your application. This has many benefits. Let's say you have an application that you want to save data to the database and queue off a message to another source. You can either queue the message in your JDBC call or use a trigger or stored procedure. The big advantage to this over an external message provider is that you know for sure that you don't queue a message if it doesn't get in your database and vice versa. You also have the ability to make take a point-in-time backup and be guaranteed through Oracle's facilities to have perfect synchronization.

Summary Support for JMS in the Oracle Application Server is excellent. This chapter has covered the practical aspects of configuring JMS using Oracle 10g AS JMS, Oracle JMS, and third-party providers. The decision of which provider to use can be a difficult one, but if you use the knowledge you gained from this chapter, you should be able to make it easily.

Chapter 7: Security Overview Security is an important aspect of many enterprise applications. Building a secure application from the ground up, without any support, is an arduous task and certainly not one you would consider doing in a hurry. Thankfully, Java provides an excellent security model that reduces the burden on developers, and puts the creation of secure applications within the grasp of mere mortals. In this chapter, we'll show you how the J2EE security model is implemented in Oracle 10g AS. Specifically, we'll cover the following: J2EE security model. Here you'll learn some of the core concepts of the J2EE security model, including authorization, authentication, principals, and roles. Java Authentication and Authorization Service (JAAS). This section introduces JAAS and looks at what features the JAAS security model offers. J2EE and JAAS. This section looks at how the JAAS security model works with J2EE as well as where JAAS-based security moves outside the bounds of the basic J2EE security model. JAAS support with JAZNUserManager. The JAZNUserManager is an implementation of the OC4J security model and uses JAAS as the underlying model. It comes complete with two storage mechanisms: XML and Lightweight Directory Access Protocol (LDAP). Much of this chapter is focused on using the JAZNUserManager along with some associated tools. DataSourceUserManager. This offers an alternative to the JAAS-based JAZNUserManager and uses a data source to access user credentials. This chapter provides information about how to use the DataSourceUserManager in your application. Customizing security. At the end of the chapter we'll discuss the options that are available if you want to provide your own security implementation. Don't worry if some of the things in that list don't make sense yet; all will become apparent as you read the chapter. Although we'll give you a cursory introduction to JAAS, full coverage is outside the scope of this book. If you require more information on JAAS check out the documentation for Java 1.4 provided by Sun (see http://java.sun.com/products/jaas/overview.html). The security documentation for Oracle 10g AS is composed of over ten different manuals and is full to bursting with reference detail on all things related to security. Rather than reproduce that information here, we'll focus on the practical aspects of building and configuring a secure application and refer you to the manual when necessary. If you have trouble finding the security manual online (and you will), the following link will take you straight there: http://downloaduk.oracle.com/docs/cd/B10464_02/web.htm. Use the tabs at the top of the screen to navigate to the J2EE, Web Services, & Internet Apps and Management & Security sections, where you'll find individual manuals covering specific topics.

Introduction to J2EE Security In the J2EE security model, a principal is essentially any entity that could possibly be allowed access to the J2EE server, whether it's an end user, an application, or a device. Whenever you use the term, user, you're typically referring to the principal, which represents that user. Although, in security, a user is always represented as a principal, principals do not always represent users,

and may be used to represent groups of users or devices. In the J2EE model, and indeed many other security models, the means of regulating access to the server is based around the following two core concepts: Authentication. This is the process by which a principal asserts its identity to the J2EE container. An end user might enter his username and password; an application might present an SSL certificate; a device might use its IP address. Authorization. This is the process of determining whether or not a principal is allowed to do something within the context of the container. Within the Servlet container, authorization is URL based. In other words, it's possible to restrict access to certain resources, based on their URL, to a specific set of principals. In the EJB container it's possible to restrict access to bean methods to one or more principals. Both of these authorization mechanisms are configured declaratively within your application's deployment descriptor. The final piece in the J2EE security puzzle is security roles (or simply, roles). A role, in J2EE terms, is simply a logical grouping of principals. When configuring J2EE security declaratively you do not mandate a resource or method on a principal-by-principal basis: instead you use roles. For example, within the Servlet container you would restrict access to the www.foo.com/secure URL to principals Bob and Fred only, instead you would restrict access to that URL to the manager's role, of which Bob and Fred are members.

Introduction to the Java Authentication and Authorization Service JAAS is a standard API used for building secure applications, and it's fully integrated with OC4J. When you're working with security in an Oracle 10g AS context, most of your interaction with JAAS will be transparent, with the majority of JAAS code working under the hood of the application server. The JAAS specification allows you to define the authentication and authorization procedures for your application. Using the identity provided during the authentication phase, JAAS will check that the principal (or any of the roles to which the principal is a member) has permission to execute the attempted action. Authorization in JAAS is much more fine-grained than in J2EE. Using JAAS, you can grant specific permissions to principals using a permission policy. Permissions are implemented as subclasses of the java.security.Permission class, and associated with each Permission class are list of permissible actions. For example, the java.io.FilePermission class defines four permissions: read, write, execute, and delete. Permissions-based security has been around in Java for a long time, but JAAS adds the ability to grant permissions based on the principal, not just on what code is running. When associating a permission with a principal, you specify a target, the meaning of which is permission specific, followed by the actions you wish to allow for that permission. For instance if you want to grant read access to the file /tmp/foo.txt (the target) to the principal Bob, then you would use a Policy similar to this: grant { permission java.io.FilePermission "/tmp/foo.txt", "read"; }; This is the standard Sun policy file format. As you'll see later in the chapter, it's also possible to define permissions using an Oracle-specific XML format. Although permissions aren't part of the J2EE specification, they do allow security to be managed at a particularly fine-grained level,

which may be useful in some scenarios. However, the main problem with relying on permissions to enforce security in your application is that you're relying on a nonstandard feature—not all application servers use JAAS for security. Since permissions aren't part of the core J2EE security model, we won't be spending much time discussing them, other than to demonstrate how to configure them when using Oracle's JAAS Provider.

JAAS Providers The JAAS specification provides support for the concept of Pluggable Authentication Modules (PAM). The idea behind PAM is that the authentication logic of the security system is pluggable and can be transparently replaced by different implementations. In JAAS, you create an authentication module by implementing the javax.security.auth.spi. LoginModule interface. The LoginModule interface is used by JAAS to control authentication of principals. It's the LoginModule implementation that's actually invoked when a user attempts to authenticate with a system. Implementers can choose any mechanism for storing and retrieving principal data. As you'll see, the Oracle JAAS Provider supports both XML and LDAP as a storage mechanism. Oracle's JAAS Provider also provides custom implementations of the javax.security.auth.login.Configuration and java.security.Policy classes. JAAS uses an instance of the Configuration class to decide which LoginModule implementation to use. By using the Oracle implementation of Configuration, you're telling JAAS to use the Oracle implementation of the LoginModule interface. The Policy class is used across the whole Java 2 security framework to represent the system's security policy. A security policy in the traditional J2SE sense is the definition of which pieces of code are granted which permissions. JAAS extends this by allowing permissions to be granted not only to code but also to principals as part of the system security policy. The default implementation of Policy, reads the security policy from a file in the Sun policy format. Oracle's implementation of Policy allows you to specify which permissions to grant to which prinicipals as part of your application configuration files.

JAAS and J2EE JAAS is an important specification, and it's useful to be aware of it and to know when to use it. However, although JAAS is now a standard part of the J2SE specification, there's no requirement in the J2EE 1.3 specification for application servers to use JAAS to support the J2EE security mechanism. Although many application server providers, including Oracle, have chosen to do so, their implementations may not be as compatible as you would like due to the exclusion of certain key areas from the JAAS specification. Key omissions from the specification include a definition of how user and role data should be stored, and a standard interface to define management operations such as the creation and deletion of roles and users. As you'll see, the Oracle JAAS Provider provides two storage mechanisms, XML and LDAP, as well as a custom mechanism for managing the data contained in these stores.

Oracle Application Server Security Overview Figure 7-1 shows the basic setup of security in Oracle 10g AS.

Figure 7-1: Security in Oracle 10g AS As you can see in Figure 7-1, clients, whether they're Servlets, standalone applications, or EJBs, are authenticated using the com.evermind.security.UserManager interface. UserManager is an interface of the underlying OC4J container, which provides a uniform mechanism for user and role management. Oracle 10g AS comes with a selection of UserManager implementations, the most widely used being JAZNUserManager and DataSourceUserManager. OC4J also comes with the XMLUserManager, but this is now depreciated in favor of using the JAZNUserManager. In a similar way to the interfaces defined in the JAAS specification, UserManager, and its associated set of interfaces, define a standard mechanism for user authentication and authorization in OC4J.

The JAZNUserManager Java Authorization (JAZN) is the old, but still widely used, name of the Oracle JAAS Provider. The JAZNUserManager is built on top of JAAS, and as such supports not only the role-based security mechanism of J2EE, but also performs further authorization based on a permission policy (as we mentioned earlier, we won't focus too much on permission policies, other than to cover the syntax required to grant permissions to a user). The JAZNUserManager is the default UserManager in Oracle 10g AS and, in general, it will suffice for most applications. Since JAAS doesn't specify a mechanism for user storage or management, Oracle has adopted the notion of a realm, which is suggested in the JAAS reference implementation. A realm can be thought of as a logical grouping of users and roles. The JAZNUserManager provides two storage mechanisms for realm data: an XML provider and an LDAP provider. We'll discuss the relative benefits of each of these providers once you have had a chance to see them in action, and see them in the context of the other UserManager implementations available. Note

The LDAP provider should really be called the pseudo-LDAP provider. You can only use the LDAP provider if you have Oracle Internet Directory (OID) installed, and it depends on the OID client libraries for communication.

The realm data for JAZNUserManager can be managed using the JAZN Admintool commandline utility. An example of this is shown later.

The XMLUserManager XMLUserManager is a UserManager implementation that stores user and role data in an XML file. XMLUserManager is built entirely independently of JAAS. When using the XMLUserManager you store your user and role details in a file called

principals.xml, which can be found in the $J2EE_HOME/config directory. XMLUserManager is now considered obsolete and is included for backward compatibility only. If you wish to use XML to store user and role data, then use the XML provider for JAZNUserManager instead. JAZNUserManager allows you to use XML for user and role data storage, and in addition, also provides a simple mechanism for scaling up to OID in the future. This, taken with the fact that you can use any JAAS-compliant LoginModule with the JAZNUserManager, makes it hard to think of any reason why you would want to use XMLUserManager. JAZNUserManager provides all features of XMLUserManager and many, many more. If you have an application that is using XMLUserManager already, then you should consider migrating this application to JAZNUserManager. To do this you need to move the data contained in principals.xml and add it to the JAZNUserManager configuration. The XML formats used by XMLUserManager and JAZNUserManager aren't identical but converting from one to the other is straightforward.

The DataSourceUserManager DataSourceManager allows for user and role data to be stored in a database. This is a popular method of storage and can be useful when you want to keep user and role data near your application data. As with XMLUserManager, DataSourceUserManager is built entirely separately from the JAAS framework.

Creating and Configuring a Secure Application Rather than simply giving you a copy of the data in the manual for each of the UserManagers, you're going to build a simple web application and secure it using the JAZNUserManager, with both XML and LDAP providers. The application will have two J2EE Security roles: sr_admins and sr_users. These roles will be mapped to the admins and users JAAS roles. Then you'll give the admin user membership to the admins role and the user user membership to the users role. Also, you'll see how to make one role a member of another, effectively making all members of the first role members of the second one. In the final part of this section you'll look at an alternative to the JAZNUserManager, DataSourceUserManager, which allows you to store your user and role data in a relational database.

Java Virtual Machine Configuration Parameters Before you begin looking at the example it's important to ensure that you've configured the JVM you use to run Oracle 10g AS correctly. Specifically, the JAAS configuration for the JVM needs to have the JAAS Configuration and Policy classes set to use the Oracle implementations. As we discussed earlier, the use of the Oracle-specific implementations of these classes is a must if you want to use the JAZNUserManager, otherwise JAAS won't be configured to use the correct LoginModule implementations, nor will it be able to read policy information contained in your configuration files. For OC4J you need to set the following lines in the ${JAVA_HOME}/jre/lib/security/java.security file: auth.policy.provider=oracle.security.jazn.spi.PolicyProvider login.configuration.provider=oracle.security.jazn.spi.LoginConfigProvid er

Note

If you're using Java, Standard, or Enterprise Edition and you're using the JVM that came with your edition then you don't need to perform this configuration step. It's already done for you.

If either of these properties is already defined in your java.security file with a different value, then be sure to comment them out or remove them all together.

The HelloServlet Application The example application is a simple Servlet that displays Hello World, along with some information about the current security context. In order to demonstrate the authentication and authorization processes, you'll set access rights to this Servlet based on the URL of the requesting client. The code for the HelloServlet class, which is shown here, is very simple: package com.apress.oracle10g.security; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HelloServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); ServletOutputStream output = response.getOutputStream(); output.println(""); output.println("HelloServlet"); output.println(""); output.println("

Hello World!

"); output.println(request.getRemoteUser() + "
"); output.println("In sr_users role? " + request.isUserInRole("sr_users") + "
");

output.println("In sr_admins role? " + request.isUserInRole("sr_admins") + "
"); output.println(""); output.println(""); } } As you can see the code processes a GET request and will output "Hello World", followed by the name of the current user and then a summary of the user's membership in the sr_users and sr_admins roles. You will not create these roles yet, so you can see what happens when you run the application without them. The web.xml file simply configures the Servlet and then maps it to the /*URL pattern, as follows: Hello Servlet Application helloServlet Hello Servlet com.apress.oracle10g.security.HelloServlet helloServlet /* helloServlet j_security_check You should compile and try the application now. You should see that instead of the name of the user, the output is null. The reason for this is that the application isn't subject to any security and that you haven't presented your identity to the Servlet at all. Note

If you have trouble building and deploying the application, you can download all the code along with an Ant build script from the Apress website.

Configuring J2EE Security Configuring the security for the application is simply a matter of selecting the roles that the application will use, specifying the access rights for each role, and then identifying the authentication method. To specify the roles used, you define the security roles, sr_users and sr_admins, in the web.xml file, as follows: sr_users sr_admins

Within a web application, access to resources is restricted to certain roles that are using a URL pattern, as shown here: Users /users/* sr_users Administrators Only /admin/* sr_admins In the previous code sample, we have restricted access to any resources with a URI that matches the pattern /users/* to the sr_users role. Likewise access to resources matching /admin/* is restricted to the sr_admins role. If this were an EJB-based application then we could restrict access to certain methods on the EJB to certain roles in the EJB deployment descriptor.

Note

If you're unfamiliar with how EJB security works then you should read Enterprise JavaBeans 2.1 by Stefan Denniger, Ingo Peters, and Rob Castaneda. (Apress, 2003).

The last step in configuring the J2EE portion of the web application security is to set the authentication method. For web applications the Servlet container takes care of requesting authentication details and validating them using the configured UserManager, in this case JAZNUserManager. Once the Servlet container authenticates your identity, it will use the identity to determine whether or not you're authorized to access certain resources. For this application you'll use BASIC authentication, as follows: BASIC

When using BASIC authentication, the users' browsers will prompt them for a username and password that will be transmitted in clear text to the Servlet container. Table 7-1 lists the four types of authentication mechanisms available. Table 7-1: J2EE Web Application Authentication Methods Method

Description

BASIC

Basic authentication is performed between the browser and Servlet. The browser will pop up a small window prompting you for a username and password, which are sent to the Servlet in UU-encoded format. This method is insecure unless all communication with the Servlet takes place over SSL. In most cases you won't use BASIC authentication, because FORM-based authentication allows for a much friendlier interface to be presented to users. However, for the sake of this example, BASIC is the simplest authentication method to set up.

CLIENT-CERT

Client certificate authentication is very secure, but is also difficult to configure and not for use in B2C applications. Using CLIENT-CERT, the client browser presents the server with an SSL certificate that asserts the users identity without the need for them to enter any details at all.

DIGEST

From a user perspective, DIGEST authentication functions very much like BASIC authentication. However, the password is passed to the server in a format that isn't easily decrypted.

FORM

Form authentication allows for you to present a friendly, usually HTML-based, form to your users for them to enter their credentials into. As with BASIC authentication, this method of authentication is insecure unless SSL communication is used.

SSO

Single Sign-On isn't a standard J2EE authentication method and relies on Oracle SSO being available in your environment. SSO is great when you have bunch of applications that can be accessed by the same set of users. Using SSO, they sign into a single application and they're automatically signed in to all the applications using SSO.

You cannot specify the use of SSO in the web.xml file; instead, you must specify SSO usage in the orion-web.xml file, like so:

The use of the Oracle SSO is covered in more detail in Chapter 20.

Configuring the XML Provider By default JAZNUserManager is configured to use the XML provider as the data store for realm data. You can choose to store your realm data either in the master jazn-data.xml file in the $J2EE_HOME/config directory or in a file local to your application. You can even change the file-name if you wish, although it's probably a good idea to stick with jazn-data.xml to make it easier for other developers working with your application. If you choose to use the master file, you can change its location by modifying the following entry in $J2EE_HOME/config/jazn.xml:

Storing realm data locally for your application means that you don't have to play around with the global configuration files and you can keep all your application data together in one place. However, using a local file does make manipulating the data using the JAZN Admintool slightly more difficult, although not impossible. At the end of the day you're free to use whichever implementation is best suited to your environment. It may be that you have a lot of applications using different security realms, in which case using application-specific files makes sense. However, if you have a few applications all sharing the same realm data, then using the global file is probably the best option. To configure JAZN to use the XML provider and a local realm data store, add the following entry to your orion-application.xml file: This line specifies that the application will be using the XML provider and that the realm data will be stored in a file called jazn-data.xml in the same directory as orion-application.xml. Configuring Users and Roles in jazn-data.xml Now you need to actually define the realms, users (principals), and JAAS roles that will make up the application. For the purpose of this application the security configuration will be as follows: You will create a single realm called helloServlet, which contains two roles: administrators and users; and two users: admin and user. The user called user will be a member of the users role. The user called admin will be a member of the administrators role. The administrators role will be a member of the users role, so that all members of the administrators role are implicitly members of the users role. Later you'll define a mapping between these JAAS roles, configured in jazn-data.xml, and the sr_admins and sr_users J2EE roles configured earlier in the web.xml file. Note

If you're using Java, Standard, or Enterprise Edition then you can configure the JAZN realm data using the Application Server Control (ASC) utility. As with Admintool you're unable to configure users if you're using the LDAP provider; instead, you must use the Delegated Administrative Service (DAS) to create users in OID.

The format of the jazn-data.xml file is quite complicated, so we'll include the code in full punctuated by explanations of the individual pieces, as follows: helloServlet The file starts by declaring the realm and giving it a name, in this case, helloServlet. Next come the user definitions, as shown here: admin Administrator !pwd user User !pwd anonymous The default guest/anonymous user The XML for creating users is pretty simple to understand: Each user is given a name, which is the username used when authenticating with the system, and a display name that's displayed in the ASC. The tag specifies the user password, prefixed by a ! character, which indicates that the password is in plain text. When you deploy the application, Oracle 10g AS will encrypt the password in the deployed instance of the system. If you use JAZN Admintool (shown later) to add a user to a realm then the password is already encrypted for you. The same is true when you're using ASC in Java, Standard, or Enterprise Edition. Now that you've created the users, all that's left for this configuration file is to create the roles, as shown here:

administrators Administrator Role user admin users User Role user user role administrators
Again the XML is fairly self-explanatory. The main point of interest here is that for the administrators role, we've specified one member: the admin user. However, for the users role, we've specified two members: the user with username user, and the administrators role. This means that instead of having to add a new administration user to both the administrators and users roles, we just need to add them to the administrators role. The remaining elements are unimportant at this point, but here's how it looks:

'


The element is used to assign specific permissions to a principal. So if you wanted to allow all users in the helloServlet realm to access EJBs using their remote interfaces they would need to be granted the login action of com.evermind.server.rmi.RMIPermission, as follows: helloServlet role oracle.security.jazn.spi.xml.XMLRealmRole helloServlet/users com.evermind.server.rmi.RMIPermission login The and of the are specific to the resource that you're granting permission to, and they correspond to the name of the permission implementation class and the action you wish to grant. The tag specifies which user or role the permission is being granted to. In this case it's the users role in the helloServlet realm. An example of how to use can be found in the global jazn-data.xml file. The and appear to be entirely

undocumented. Outside of code examples containing them as empty elements, there's no mention of either element on the Oracle site and a Google search displays very little. The tag is used to map LoginModules to different applications. Later on in the chapter you'll see how this tag is used when configuring a custom LoginModule.

Mapping J2EE Roles to JAAS Roles In the last section you created the users and administrators roles, and assigned users to each role. In this section you'll see how to map these JAAS roles to the J2EE roles specified in the web.xml file. Doing so is remarkably easy, requiring just a few extra entries in the orionapplication.xml file, as shown here:

Each element in the preceding example links one J2EE Security role to one JAAS role. In actual fact you're mapping to an OC4J group, part of the UserManager infrastructure, but the JAZNUserManager maps these one to one with JAAS roles specified in the jazn-data.xml file. So you can see that the users JAAS role is mapped to the sr_users J2EE security role and the administrators JAAS role is mapped to the sr_admins J2EE security role.

Try Out the Application You're now ready to deploy the application and try it out. Once deployed point your browser at http://localhost:8888/helloServlet (or the URL appropriate to your environment) as shown in Figure 7.2.

Figure 7-2: No authentication

Notice that the username is null and that your membership in both roles is false. Now visit a resource under the /users/* URI. You'll be prompted by your browser to provide the username and password. Use the username, user, and the password, pwd, to log in as user in the users role as shown below in Figure 7.3.

Figure 7-3: Authenticated as a member of the users role Now you can see that the username is set to helloServlet/user (the realm-qualified username), and that your membership in the sr_users role shows up as true. Remember that the sr_users J2EE role is mapped to the users JAAS role. Now visit a resource under the /admin/* URI. You're prompted again for a username and password, even though you already specified one. The reason for this is that even though your identity has been authenticated by the application server, the application has determined that you're not authorized to view resources under the /admin/* URI. Enter the user name, admin, and the password, pwd, as shown in Figure 7-4.

Figure 7-4: Authenticated as a member of the administrators role Now you can see that username is set to helloServlet/admin and that you're a member of

both roles.

Administering the HelloServlet Application with JAZN Admintool JAZN Admintool is a command-line utility that allows you to configure JAZN realm data without the need to modify the XML configuration file directly. Admintool can be used to manage realm data for both the XML and LDAP providers. However, when using the LDAP provider you're unable to add or remove any users using Admintool. Instead you must use the DAS, as discussed later in the chapter in the "Configuring Oracle Internet Directory" section. Unfortunately, the documentation doesn't explain how to use the JAZN Admintool to configure applications that store realm data in local XML files. However, it's possible to use the JAZN Admintool to manage your application, and we're going to show you how. The JAZN Admintool has a wide array of commands. We'll demonstrate the most useful here, and details on the rest can be found in the documentation. You should note that OC4J doesn't need to be running to use the JAZN Admintool. First of all, open up a terminal or command window and change to the $J2EE_HOME directory. The basic command syntax for JAZN Admintool is as follows: java –jar jazn.jar –user –password By default Admintool looks in the global jazn.xml file to determine the location of the global jazn-data.xml file. This is the file it will write its changes to. To change the config file that's used to locate the jazn-data.xml file you can set the oracle.security.jazn.config system property when running the tool. The username and password are required when using Admintool to manage XML realm data. When managing application-specific files, you can use any username and password combination from the file. So to list all the realms defined for the Hello Servlet application you would use the following: java -Doracle.security.jazn.config=application-deployments/helloServlet /orion-application.xml / -jar jazn.jar -user admin -password pwd listrealms Notice that we've pointed Admintool to the orion-application.xml file instead of the global jazn.xml file. The oracle.security.jazn.config property should point to the file that contains the element; from there Admintool will locate the correct jazn-data.xml file. The last part of the command, –listrealms, is the important part. This is the Admintool command. Whenever you run Admintool the first part of the command text will always be the same up to specifying the password regardless of which Admintool command you wish to run. All that changes is what comes after your password. The -listrealms command isn't very useful. You already know what realms are specified by the HelloServlet application (it's the helloServlet realm). It's useful, however, to be able to retrieve a list of users and roles in a particular realm. This is achieved by using the –listusers and –listroles commands, each of which takes the realm name as a parameter. Consider the following command: .. –listuser helloServlet

We've excluded the first part of the command since it never changes. For the HelloServlet application this would yield the following: user

admin To find out which roles a particular user is a member of, use the –listroles command, which specifies both the realm and the user, as shown here: > ..-listroles helloServlet admin users administrators The command you're likely to use most often is the –adduser command. To add a user with username foo and password bar to the helloServlet realm, use the following command: > ..-adduser helloServlet foo bar A nice part of Admintool is that it will automatically encrypt the user's password for you. To make the foo user and member of the user role use the –grantrole command, as follows: >..-grantrole users helloServlet foo Changes made to the XML realm data store aren't picked up until you restart OC4J, so do that now and then try to log in to the HelloServlet application using the foo user.

Using the JAZNUserManager LDAP Provider In the previous section you created a basic secure application using the Oracle JAAS Provider (JAZN) and the JAZN XML provider. In this section you'll reconfigure the application to make use of the LDAP provider instead.

Configuring Oracle Internet Directory The first step is to configure the OID, adding the appropriate users and roles to the directory. If you're unfamiliar with how to install OID then see Chapters 20 and 21 to obtain installation and startup instructions. Configuring the OID for the HelloServlet application is a trivial job. You need to add two users: user and admin, and then add two groups: users and administrators. To add the groups, log in to the OID DAS and click the Directory tab on the home page. After logging in through SSO page, click the User tab, and then click Create as shown in Figure 7-5.

Figure 7-5: Create User page On the Create User page, enter all the resource information for the user user under the Basic Information section. Be aware that the minimum size for passwords is five characters. Once you're finished, click the Submit button in the top right of the screen. Repeat this process to create the directory entry for the admin user. The next task is to create the users group. Click the Group tab at the top of the screen and then click the Create button, as shown in Figure 7-6.

Figure 7-6: Create Group page Under the Basic Information section enter the information for the users group, and then scroll down to the Members section, as shown in Figure 7-7.

Figure 7-7: Create Group Members section Click the Add User button to display the Select User page. On the Select User page click the Go button to display a list of all users. Select the user user and then click the Select button. Back on the Create Group page, click either of the Submit buttons to complete the process. Repeat the process for the administrators group.

Configuring the HelloServlet Application With the user and group data created for the LDAP provider, all that remains is to configure the HelloServlet application to use the LDAP provider instead of the XML provider. To do this you simply replace the existing tag in orion-application.xml with the following: This is all that's required. Redeploy the application and try to log in using the usernames and passwords for the users you created in OID. Once you're logged in you should get something like what's shown in Figure 7-8.

Figure 7-8: Authenticated using LDAP provider

Notice that realm of the username has changed from helloServlet to the name of the OID instance, in the case of the following image, tiger.

Using DataSourceUserManager Until now you've been working solely under the Oracle JAAS Provider, JAZNUserManager. However, as we mentioned earlier, the main security mechanism in OC4J is the UserManager. Oracle is pushing the JAZNUserManager extensively, which in the long term may prove to be useful, but currently, there's still place for the other UserManagers as well for custom UserManagers in your J2EE applications. In this section you'll see how you can use the DataSourceUserManager to store user details in a database. The main reason you would want to use the DataSourceUserManager is if you're already storing user credentials in a database. This is a pretty common occurrence in web-based applications and it may be that you aren't ready to move to OID just yet. In this case DataSourceUserManager should be able to help you out. However, if you're starting from scratch and wondering where best to store your user credentials, then we would definitely recommend that you investigate using OID. OID provides a highly scalable solution, and the directory-based data structures are optimized for data that is read mostly, which most user data typically is, especially login credentials.

DataSourceUserManager Overview The setup of DataSourceUserManager is quite strange. Rather than storing everything in the database, the DataSourceUserManager stores the roles (called groups in UserManager terms) in the same XML file used by the XMLUserManager, principals.xml, and stores the users along with their membership of the various roles, in the database. At first this sounds like a limiting factor, but only to a small degree. We find that in most applications the actual roles change very rarely; often they're defined during the creation of the application and never change. However, if a new role is required and you want to limit access to some resources based on membership in that role, then you're going to have to update the deployment descriptors of your application anyway, so what is the harm in adding the role declaration to an XML file? When configured correctly you can also manage the DataSourceUserManager using ASC.

Creating the Tables The database needs two different tables, one to hold the user data and the other to hold data to link the users to their roles. The users table requires at least two fields, one to store the user name and the other to store the passwords. A typical SQL command to create this table will look like this: CREATE TABLE user ( username varchar(64) PRIMARY KEY, password varchar(64) NOT NULL ); The names are arbitrary—you can call them what you like. The table for mapping users to their roles also requires two fields, one to store the username and the other to store the role name, as follows: CREATE TABLE usergroups ( username varchar(64) NOT NULL, groupname varchar(64) NOT NULL, PRIMARY KEY(username, groupname)

); Again the names you use are completely arbitrary.

Creating the Data Source Since this is the DataSourceUserManager, you're going to need a data source. Create an entry in data-sources.xml for the data source containing the tables you just created: You're not limited to using just the Oracle database; you can point your data source at any database that has a JDBC driver.

Configuring the HelloServlet Application Configuring the HelloServlet application is relatively easy. The first job is to create the principals.xml file, and specify the basic roles available: administrators users

Notice that we've defined two roles: users and administrators. Also notice that we've assigned the RMI login permission to members of the user's role, thereby allowing them to access EJBs running over remote interfaces. This is synonymous with the RMI permission given to this group in jazn-data.xml. Again, the permission isn't part of the J2EE security, but instead it's part of the underlying security model of OC4J. To tell OC4J where the principals.xml file is, you need to add a element to the orion-application.xml file, as shown here: The next job is configure the UserManager itself, again in the orion-application.xml file, as follows:

All UserManagers require that the class attribute of the tag is specified. The tags are specific to the individual UserManager. Here you can see that we have parameters for the data source, the tables in the database, and the names of the fields in the tables. We've also set the debug parameter to true, which is helpful when you're trying to set up the DataSourceUserManager. That's the final piece of configuration; all you need to do is add some sample data to the database, defining some users and their membership in the users and administrators roles, and you're ready to deploy the application and try it out.

Customizing Security As you've seen Oracle 10g AS provides full support for J2EE security through the use of UserManagers. Oracle is pushing JAZNUserManager in a big way, and it has the fullest support for creating a secure application. The other main UserManager is DataSourceUserManager, but this suffers from the problem that the passwords are stored in plain text in the database. However, it's possible to extend the support for user authentication and authorization in two ways: by using a custom UserManager or a custom JAAS LoginModule .

Custom UserManagers If you require custom authentication for your application and you want to take advantage of the ASC management tool, then you need to create a custom UserManager. Creation of a custom UserManager is outside the scope of this chapter, but you can find an excellent article on the

topic at http://kb.atlassian.com/content/orionsupport/articles/usermanager.html? printable=true. Custom UserManagers are configured in the same way as DataSourceUserManager, using the tag in the orion-application.xml file.

Custom LoginModules If you don't require the ASC support, then you may want to consider creating a custom JAAS LoginModule that can be used in conjunction with the JAZNUserManager. The LoginModule interface only considers the authentication of users and matching them to roles. There's no consideration for managing the user store and no integration with ASC. However, custom LoginModules are portable between application servers that have JAAS-based security methods. We aren't going to show you how to create a custom LoginModule. That is certainly outside the scope of this chapter, although you'll find plenty of information about the subject on the Web. To use a custom LoginModule, such as the com.sun.security.auth.module.UnixLoginModule, which is included in the JDK, within your application you must be using the JAZNUserManager with the XML provider. In the jazndata.xml file, you need to configure the LoginModule using the tag, as follows: helloServlet com.sun.security.auth.module.UnixLoginModule required

UserManager or LoginModule Choosing whether or not to use UserManager or LoginModule for your custom security provider can be a difficult decision, however, it's a decision you may not need to make. Both UserManager and LoginModule are interfaces, so there's nothing stopping from you creating a class that uses the same internal logic to implement both interfaces. Indeed, if you're intending to implement UserManager in order to integrate with the ASC, then it will require little effort to implement the LoginModule interface as well. If you're primarily developing a LoginModule for use on multiple application servers, then creating a fully functional UserManager will require that you create much more logic in order to support the user and role creation functions of the UserManager. However, it's likely that you will need to create a login in order to support user management, so you should consider encapsulating this as part of the UserManager interface.

Choosing Your Security Method Oracle 10g AS gives you a wide range of security choices for your applications. Making the

decision can be quite difficult, but in general there are only a few different scenarios. For development purposes, the XML provider of JAZNUserManager is generally the best choice. It makes it simple for developers to work and test in isolation. My preference for deployment is almost always the OID and JAZNUserManager combination, especially in enterprise settings. Directory-based storage is generally faster than database for applications that are predominately read only. In an enterprise setting, aside from the initial data population, the number of users won't change that often. Certainly you shouldn't expect to see more than a handful of modifications each day (unless your enterprise has particularly bad staff retention!). In a Business-to-Customer (B2C) setting, especially in Internet applications, where you allow users to register their own details (think Amazon.com), it may be wise to consider the use of a relational database, in which case the DataSourceUserManager will suffice. Still, you may want to consider a custom implementation that will encrypt passwords for storage in the database. However, even in this scenario the OID choice might still be valid, but you'll want to do some performance testing before you commit to this. Of course if you have specific storage requirements then you're going to have to build a custom implementation. The choice then is which kind of custom implementation, Login-Module or UserManager, but as we mentioned earlier you don't necessarily need to make this choice.

Summary In this chapter you have created a secure web application and secured it using the JAZNUserManager, with both XML and LDAP providers, and the DataSourceUserManager. As you can no doubt tell after reading this chapter, configuring J2EE application security in Oracle 10g AS is very simple. The hardest part is choosing which of the UserManagers to use, and when using JAZNUserManager, which provider to use. At the end of the chapter we discussed the factors to consider when making that decision and how to be comfortable with the decision you're making.

Chapter 8: Using JavaMail and Java APIs for XML Overview Many of the J2EE services provided by OC4J don't require extensive configuration, and can be used in the same way across all J2EE servers. Still, there are a few OC4J-specific details to remember, and you'll learn about them in this chapter. We'll discuss the JavaMail and the XML APIs, and answer questions such as these: How do I create and use a JavaMail session? Which JAX implementation will be loaded in my environment? As part of the discussions you'll build a Servlet-based application that leverages the Java Naming and Directory Interface (JNDI) for storing and managing JavaMail session implementations (see Chapter 5 for details on how to configure JNDI).

JavaMail OC4J supports JavaMail 1.2, an API that allows you to send and receive mail through SMTP, IMAP, and POP servers. Since the JavaMail implementation is included on the server class-path, you can use it directly in any of your Java classes. However, to avoid hard-coding return addresses, hostnames, and other information, it's usually best to set up one or more JavaMail sessions, which can then be referenced logically and shared by your J2EE components. This section walks you through setting up and using a simple SMTP mail session. For more details on individual classes and protocols, check out Sun's JavaMail documentation at http://java.sun.com/products/javamail.

Building an Application with JavaMail and JNDI For both JavaMail and JNDI there's only so much that can be explained in writing. To get a fuller grasp of both topics let's build a sample application that leverages both technologies. The sample application you're going to build allows for an email to be sent to an arbitrary recipient from a web page.

Configuring a Mail Session The first step when using JavaMail is configuring a mail session. A session is an instance of javax.mail.Session that has been initialized with certain default properties, such as the protocol, mail server, and from address. Each session is described in either orionapplication.xml, or the global application.xml configuration file. When OC4J reads that file, it creates the session and makes it available in JNDI under the specified location. To configure an SMTP mail session for the sample application, you need to add a tag to the orion-application.xml file, or to $J2EE_HOME/j2ee/home/config/application.xml:

The important part here is of course the tag. The location attribute specifies the JNDI location to which the mail session will be bound and to which is a required parameter. Here you can see that the Session is bound to mail/SampleMail in the global JNDI namespace. Tip

OC4J doesn't include a mail server, so you'll need to specify an external SMTP, POP, or IMAP server in your mail-session attributes. The Apache James project (http://james.apache.org) is a 100 percent Java implementation of a mail server. Currently, James provides SMTP and POP implementations. James is a cinch to get up and running and provides an ideal solution for testing.

The subelement is used to specify JavaMail properties, as described in the JavaMail specification. These properties aren't OC4J specific, but descriptions are included in Table 8-1 for your convenience. Table 8-1: Common JavaMail Properties Property Name

Allowed Values

Description

mail.debug

true | false

Whether to print debug information. Default is false.

mail.from

String

The default sender email address to use if no "from address" is specified in a message.

mail.mime.address.s trict

true | false

Whether to use strict parsing on headers. Default is true.

mail.host

String

The default hostname if not specified for a

Table 8-1: Common JavaMail Properties Property Name

Allowed Values

Description particular protocol. Default is localhost.

mail.protocol.host

String

The default host name for the specified protocol. (Replace protocol with the name of a protocol, for example, SMTP, POP3, IMAP,)

mail.store.protocol

String

The default store protocol (for example, IMAP, POP3).

mail.transport.prot ocol

String

The default transport protocol (for example, SMTP).

mail.user

String

The default user to connect to the mail server as, if not specified for a particular protocol.

mail.protocol.user

String

The default user to connect to the mail server as, for the specified protocol. (Replace protocol with the name of a protocol, for example, SMTP, POP3, IMAP.)

mail.protocol.class

String

The fully qualified class name for the provider to be used for the specified protocol. (Replace protocol with the name of a protocol, for example, SMTP, POP3, IMAP.)

mail.protocol.port

String

The port number to be used for the specified protocol. Default depends on protocol. (Replace protocol with the name of a protocol, for example, SMTP, POP3, IMAP.)

In the previous example you can see that we've set the default transport protocol for this session to SMTP, the host to smtp.localdomain.com and the default from address to [email protected].

Creating a Local Resource Reference In the previous section you created a global JNDI binding for the resource. Now you're going to bind this resource into the local namespace for the sample Servlet. JNDI resources are bound into the local component namespace using the web.xml file for Servlets and the ejb-jar.xml file for EJBs. Here's the complete web.xml file for the sample Servlet: JavaMail Sample Application javamail JavaMail Servlet com.apress.oracle10g.javamail.JavaMailServlet javamail /send defaultSubject This is the default subject java.lang.String mail/SampleMail javax.mail.Session Container The important parts here are the and tags, along with their child tags. The tag binds a resource from the global namespace, identified by the tag, into the local namespace. The property specifies the type of object that's being bound and the tag specifies who is responsible for managing the security of this resource. In this case, the security will be managed by the container. The name given to this resource in the local tree is simply the global name, identified by the location attribute of the tag in the orion-application.xml file, prefixed with java:comp/env/, in this case java:comp/env/mail/SampleMail.

The tag allows you to bind a simple value into the local JNDI namespace. The types of values available are any of the number wrapper classes (Integer, Long, and so on), Boolean, Character, and String. In the preceding example you can see that we've created an entry for a default subject, something that isn't covered by the JavaMail configuration properties. Since this parameter is bound into the local JNDI namespace it can be accessed using java:comp/env/defaultSubject.

The Mail Form In order to pass the appropriate parameters to the Servlet you need a simple JSP file that presents an HTML form, as follows: JavaMail Sample Form form name="mailForm" action="send" method="post">
From:
To:
Subject:
Body
JNDI Scope:
You'll notice that we've added a drop-down box to allow the user to choose a JNDI scope. The mail session used by the Servlet will be obtained using the binding to the appropriate scope. This allows you to illustrate the use of the two different scopes.

Building the JavaMailServlet The key class in this example is JavaMailServlet, which is responsible for processing the parameters submitted from the HTML form you've just seen, and creating and sending an e-mail using them. The class is quite large so we'll split it into sections and explain each one independently. The first part of the class simply imports statements and a few constant declarations, as follows: package com.apress.oracle10g.javamail; import java.io.IOException; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;

public class JavaMailServlet extends HttpServlet { private static final String LOCAL_NAME = "java:comp/env/mail/SampleMail"; private static final String SUBJECT_NAME = "java:comp/env/defaultSubject"; private static final String GLOBAL_NAME = "mail/SampleMail"; Notice that we've created constants for the name of the mail session in both the local and global namespaces, along with the name of the default subject binding in the local namespace. Next up is the doPost() method, which handles the request from the mail form, as shown here: protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // get the parameters String jndiScope = request.getParameter("jndiScope"); String subject = request.getParameter("subject"); String to = request.getParameter("to"); String from = request.getParameter("from"); String body = request.getParameter("body"); You start by retrieving the parameters from the request. Next you grab the Session from the appropriate JNDI scope, as follows: // get the mail session Session session = null; if("local".equals(jndiScope)) { session = getLocalMailSession(); } else { session = getGlobalMailSession(); } Don't worry about the getLocalMailSession() and getGlobalMailSession() for now. It's enough to know that they return a mail session returned from the appropriate JNDI namespace. Next you create and send the mail message, as follows: // create the mail try { Message mail = new MimeMessage(session); if((subject != null) && (subject.length() > 0)) { mail.setSubject(subject); } else {

mail.setSubject(getDefaultSubject()); } mail.setText(body); if((from != null) && (from.length() > 0)) { mail.setFrom(new InternetAddress(from)); } mail.addRecipient(Message.RecipientType.TO, new InternetAddress(to)); // send Transport.send(mail); } catch(MessagingException e) { throw new ServletException( "An error occured creating or sending the message", e); } If the from parameter isn't provided in the form, then you don't attempt to set it. This will cause the default value that was configured in the tag in orionapplication.xml to be used. Also notice that if the subject parameter isn't supplied, you retrieve the default from JNDI with a call to getDefaultSubject() and use that. Finally, for this method you redirect the user to the success.jsp file, which will display a nice message telling him that his mail has been sent, as shown here: // success! RequestDispatcher rd = request.getRequestDispatcher("success.jsp"); rd.forward(request, response); }

The next method is getGlobalMailSession(), which retrieves the mail Session bound to the global JNDI namespace (with the mail/SampleMail name), as follows: private Session getGlobalMailSession() throws ServletException { try { Context ctx = new InitialContext(); Session session = (Session)ctx.lookup(GLOBAL_NAME); log("Obtained mail session from global context"); return session; } catch(NamingException ex) {

throw new ServletException("Unable to locate mail session", ex); } } As you can see, retrieving an object from JNDI is very simple. Once the InitialContext is created you simply call Context.lookup(), and pass in the resource name in order to retrieve the resource from the naming service. Since lookup() returns Object you need to cast the result of a call to lookup() to the appropriate type. The remaining two methods are very similar to getGlobalMailSession(), as shown here: private Session getLocalMailSession() throws ServletException { try { Context ctx = new InitialContext(); Session session = (Session)ctx.lookup(LOCAL_NAME); log("Obtained mail session from local context"); return session; } catch(NamingException ex) { throw new ServletException("Unable to locate mail session", ex); } } private String getDefaultSubject() throws ServletException { try { Context ctx = new InitialContext(); String subject = (String)ctx.lookup(SUBJECT_NAME); log("Obtained default subject " + subject + " from local context"); return subject; } catch(NamingException ex) { throw new ServletException("Unable to locate mail session", ex); } } }

Notice that both of these methods use resource names that point to the local JNDI namespace. That is all there is to the process of creating and configuring the basic application. Before we continue the discussion of additional configuration options for this application, you should try out

the application using both the locally and globally bound mail Sessions. Also see what happens when you don't specify a from address or a subject.

Choosing Between Global and Local Namespaces As you've seen from the sample application, there's very little difference between using a resource bound into the global scope and one that's bound into the local scope. So then, what is the benefit of using the local scope over the global scope? Simply put, there's no immediate benefit of doing so. However, consider a situation in which you have three applications running, each using a mail session bound into the global scope. What happens, then, when you wish to change the mail session in one application? You have to revisit the Java and code and recompile the application. Binding resources into the local tree provides a level of indirection for your application. However, when you create the new global Session and change the binding in the web.xml file, the name of the resource in the local namespace changes accordingly. What you need is the ability to retain the same name in the local namespace, but also to change the resource from the global tree that's bound to that reference. Enter logical references.

Using Logical References Using logical references is very simple, but it's best demonstrated rather than explained. You can modify the sample application to use logical references to fully decouple the application from the global namespace. The first step is a slight change to the orion-application.xml file, as shown here: Notice that we've changed the name of the original mail session to mail/SampleMail1 and added a second session, mail/SampleMail2, with a different "default from" address. If you tried to the run the application now, an error would occur during sending. The application is still looking to bind a resource with the name mail/SampleMail from the global namespace into the local scope. You could of course change the web.xml file for the application to look for one of these resources and then change the name used to look up the resource in the code. However, a better solution is to use logical references to link one of the resources in the global scope to the name that the application is looking to bind to its local namespace. To do this, you need to create an orion-web.xml file and add it to the web application's WEBINF directory, as follows:

The important tag here is the tag. The name attribute specifies the logical name you wish to associate with the resource, that is, the name used by the application. The location attribute specifies the location of the resource in the global namespace. Here you can see that we've associated the name mail/SampleMail with the resource bound to mail/SampleMail2. No changes are required to the application code or to the web.xml file. You can redeploy the application and try it out again. You should note that the option to send using the global session won't work because there's no resource named mail/SampleMail bound to the global namespace. Try changing the location that the logical reference points to. You can tell the difference between the two by the "default from" address that's used when you don't specify one.

Java APIs for XML JAX provides standard interfaces for parsing, transforming, and otherwise manipulating XML content. The latest versions of these APIs are complete enough so that many applications need not worry about the underlying implementation. However, for some XML-intensive applications, JAX isn't enough. The applications must instead rely on additional features or behavior provided by specific JAX implementations like Crimson or Xerces. Unfortunately, the bundling of JAX within J2EE containers, and more recently, within the Java Runtime Environment itself has made life difficult for developers who rely on a particular version. Since a much higher classloader loads the standard Java APIs and the container, it can be difficult or impossible to override their JAX implementation for a single application.

Determining Your JAX Version Often, the first step to solving a JAX conflict is simply to understand which libraries are being loaded. If you are using Java 1.4, this will default to the Crimson implementation included in $JAVA_HOME/jre/lib/rt.jar. If you are using a previous version of Java that did not include a JAX implementation, then it will default to the Crimson implementation included in OC4J in $J2EE_HOME/lib/crimson.jar. Tip

To get the exact version number of the bundled Crimson implementation, look at META-INF/Manifest.mf within the crimson.jar library.

The Crimson libraries are not as actively maintained as the popular Xerces implementation, so it's possible that either the Java Runtime Environment (JRE) or OC4J or both may use Xerces in the future. To determine which implementation is bundled with your JRE, look for org.apache.crimson or org.apache.xerces classes within rt.jar. To determine which implementation is bundled with OC4J, look for crimson.jar or xerces.jar within

$J2EE_HOME/lib.

Overriding the JAX Implementation Ideally, your application will be able to use the Crimson libraries bundled with OC4J or the JRE. However, if you rely on specific features of Xerces or another JAX implementation, then use the following steps to override the default implementation. These steps assume that you're using the JAXP method for obtaining a parser implementation. If you're directly instantiating the parser of your choice then you can ignore the following: In JDK 1.3.x, remove crimson.jar from $J2EE_HOME/lib and replace it with your preferred JAX implementation. In JDK 1.4.x, place your preferred JAX implementation library in a directory on the local file system. When starting OC4J, set the java.endorsed.dirs system property to point to that location, like this: java -Djava.endorsed.dirs=/my/xml/dir ... If you wish to configure the implementation programmatically by setting the following system properties, then you can ignore the following: javax.xml.parsers.SAXParserFactory. Use this property to specify the full name of the SAXParserFactory class implementation. javax.xml.parsers.DocumentBuilderFactory. Use this property to specify the full name of DocumentBuilderFactory implementation class.

Testing the JAX Override It's quite simple to check which XML implementation is being used. This Servlet application will display the name of the XML document implementation loaded using JAXP, as follows: package com.apress.oracle10g.xml; import java.io.IOException; import java.io.InputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document;

public class JaxServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { InputStream webXml = this.getServletContext().getResourceAsStream( "/WEB-INF/web.xml"); DocumentBuilder builder = DocumentBuilderFactory.newInstance() .newDocumentBuilder(); Document doc = builder.parse(webXml); response.setContentType("text/html");

response.getOutputStream().println(doc.getClass().getName()); } catch (Exception ex) { throw new ServletException(ex); } } } This code is fairly simple. It loads the application's web.xml file using the JAXP-supplied parser. Then it simply outputs the name of the class, implementing the Document interface, which was supplied by JAXP. You'll be able to tell the implementations that are being used from the package name displayed.

Summary JNDI, JavaMail, and JAX are used in essentially the same way across all J2EE servers. However, each application server uses a different InitialContextFactory for remote JNDI access, a different syntax for declaring mail sessions, and different default JAX implementations. Little details like these are important to keep in mind when using these familiar APIs.

Chapter 9: J2EE Application Deployment Overview Deploying J2EE applications requires an understanding of J2EE components and configuration. It's important to understand what components exist within a J2EE application and how they're packaged into a deployment file. Using this information you can package the application by modifying the corresponding configuration file (deployment descriptor). Once the application has been packaged into the correct EAR file, it's deployed to the server. In this chapter, we'll cover the following: J2EE architecture. Identify the architecture and components within a J2EE application. Configuration. Identify what files are configured for an application deployment using deployment descriptors. Organization and packaging. Identify the structure and purpose of the JAR, WAR, and EAR files. Deployment. How to deploy J2EE applications and what actually happens during an application deployment.

J2EE Architecture J2EE applications are structured according to a multiple tier distributed component model. This means that application code can exist on multiple tiers and will have specific functions based on its location. Each tier of the model is used to support a specific component type. Within each tier different types of Java code are written, such as Java Server Pages (JSPs), Servlets, or Enterprise JavaBeans (EJBs). By following the guidelines of placing the right code using the right technology at the most appropriate location, you're able to improve code development, deployment, and performance. In Figure 9-1 you can see the four tiers of J2EE.

Figure 9-1: J2EE component architecture In the previous figure, you can see that J2EE applications can have Java code that exists in three physical locations: client machine, J2EE server, and the database server. However, the J2EE model defines this as four tiers, with the J2EE server representing two tiers. They are Client tier. The client machine, typically a PC running a web browser. However, it can be a Java EJB application making remote calls to EJB components on the business tier. This is covered in greater detail in Chapter 14. Web tier. The web tier executes on the J2EE server, but provides presentation logic for the client tier. This is where and how data is processed and massaged before being displayed to the client. The Java code that provides this presentation functionality contains JSPs, Servlets, and applets. This is covered in greater detail in Chapter 10. Business tier. Intensive processing of business logic occurs on the business tier. This processing is often called by other components, sometimes remotely. It's not concerned with the presentation of data; rather it's the processing of business logic.

The Java code specifically designated for this type of work contains EJBs and Business Components for Java (BC4J). It should be noted that business logic is sometimes implemented in Servlets. The business tier is covered in Chapter 11. Enterprise Information System (EIS) tier. The EIS is most commonly a database, often an Oracle database, when dealing with OC4J and 10g AS. However, it can be a filebased data source or an enterprise messaging system. Connecting to the database tier is covered in Chapter 5. Not every application will actively use components for each tier. For example, an application may contain JSPs, Servlets, and access to a database via JDBC, but not use EJBs. However, the J2EE framework specifies writing Java application code with the function identified based on the previous model. Just as with any guideline, you can bend the rules and you can move business logic into the presentation tier, but that's not how the presentation was intended to work.

Note

When administering the full size 10g AS application server, the web and business tiers are the primary focus. 10g AS is a web application server because it supports both the web listener component (via Oracle HTTP Server or OHS) and the J2EE application server component (via OC4J). It's common to refer to tiers within the 10g AS context as being client, middle or mid tier, meaning web application server, and database server. This three-tier definition is slightly different than the pure J2EE four-tier definition. Details about 10g AS architecture are in Chapter 15.

Configuration Within OC4J there are two sets of configuration files: those for the OC4J container and server itself and those for the application.

OC4J Server Configuration Files Configuration files for the OC4J container are located in $ORACLE_HOME/j2ee/home/config, as you can see here: $ ls $ORACLE_HOME/j2ee/home/config application.xml

java2.policy

oc4j-connectors.xml

database-schemas

javacache.xml

oc4j.properties

data-sources.xml

jazn-data.xml

principals.xml

global-web-application.xml

jazn.xml

rmi.xml

http-web-site.xml

jms.xml

server.xml

internal-settings.xml

mime.types

$ These files are updated with application information during deployment, but they aren't dedicated to a specific application. An OC4J server can have multiple, distinct applications deployed to it. The listing of each application at the server level takes place in these files as well as in the configuration settings for the OC4J server itself. While each of these files is important, two files that are key to the deployed applications are server.xml and http-web-site.xml. The server.xml file lists the locations of key application, application-deployment,

and connector directories. It also identifies other key configuration files such as rmi.xml, jms.xml, application.xml, global-web-application.xml, and http-website.xml. Additionally, it lists the location of the server.log. The following is an example of the server.xml file:

Of key importance for the discussion of application deployments is the reference to the Petstore application. This is a demo application that you'll learn how to deploy later in this chapter. Notice that the Petstore application has been already deployed and is now listed in the application tag with a path to the ../applications/petstore.ear file. The auto-start flag is also set to true. This indicates the application has been deployed to this OC4J server. The next key file for deployed applications is the http-web-site.xml file, as shown in the following sample.

This file identifies the URI where the deployed application can be reached. Specifically, it lists the root location for the application on the URL. In this case it's http://hostname.doman/petstore, as shown here: The file also lists the application name and the load-on-startup parameters. Greater details on the files in the $ORACLE_HOME/j2ee/home/config directory are covered in previous chapters, which focus on server configuration.

Application Configuration Files The primary focus of this chapter is the application files. Later in the chapter we'll explain how applications are stored in application archive files (JAR, EAR, and WAR), however, within those packaged files are individual configuration files. These configuration files are deployment descriptors for the application. They specify the deployment and runtime behavior of the application code. There are two subclassifications of these deployment descriptors: those that are standard in any J2EE application server and those that are specific to OC4J. Configuration files with specific OC4J parameters are prefaced with "orion" to denote the Orion web server, which is the source of OC4J (for example, orion-web.xml). These are written to the $ORACLE_HOME/j2ee/home/application-deployments subdirectories after the application has been deployed to the server. Note

Just as Oracle Corporation licensed the Apache web server as the basis for its OHS, so they also did a similar move for the J2EE server. OC4J is based on a licensed copy of the Orion application server by IronFlare. Documentation specific to Orion can be found at www.ironflare.com.

The application deployment descriptors that are most commonly configured are web.xml, application.xml, orion-web.xml, and orion-application.xml. We provide examples of these files later in the chapter specific to their location within EAR and

WAR files. However, to find detailed information about the options available within any deployment descriptor, there's a URL at the top of each file. For example, at the top of the web.xml file the URL http://java.sun.com/j2ee/dtds/web-app_2.2.dtd is provided. Or for orion-application.xml there's http://xmlns.oracle.com/ias/dtds/orionapplication.dtd. Another excellent source of documentation is the documentation section for the Orion server, which you can find at www.ironflare.com/docs/.

Organization and Packaging Prior to deployment to the J2EE server for execution, a J2EE application needs to be packaged. This is a means of combining the developed J2EE modules into a single file to be deployed. Depending on the type of application module, you can create different types of deployment files. Although each of these files is a JAR file (perhaps containing other JAR files), each one will belong to one of the following categories: Client applications that use Java archive (JAR) files. JAR files are used to package a Java application together. They can contain Java classes or images. These types of files aren't directly deployed to a server. They're typically included in larger files. Business components use EJB modules and are stored within JAR files. These are packaged with a larger archive called an EAR file. Web modules use web archive (WAR) file. WAR files contain web components such as JSPs and Servlets. They can also include HTML and images. These are normally packaged within an EAR file. Enterprise archive (EAR) files contain an entire J2EE application for deployment. They may contain client applications, web modules (packaged in a WAR file), or EJB components (packaged in a JAR file). When deploying applications, the EAR file is used for the deployment. In the following sections, we go into greater detail explaining the structure of JAR, WAR, and EAR files.

Java Archive File A JAR is a file that packages application files together (such as Java classes or images). It may be included within EAR and WAR files and within library paths. In addition to the application contents of a JAR file, it also contains a manifest file that keeps an inventory of the contents of the file. The contents of JAR files are compressed, which allows for faster downloads from web servers to clients. Additionally, JAR files can be cached on clients so they're only downloaded again if a newer version is found on the server. Like all application archives (which are types of JARs), the JAR file's format is shown in Figure 92. myJAR.jar | | ------- META-INF |

|

|

| ------- MANIFEST.MF

| | ------- img |

|

|

| ------- welcome.gif

|

| ------- product.gif

|

| ------- map.gif

Figure 9-2: JAR file structure

Java Application Archive (JAR) Structure The MANIFEST.MF in the META-INF acts as an inventory for what is stored in the JAR. In the preceding example, you're simply storing GIF files in an img subdirectory. JAR files are managed via the jar command, with some similar syntax to the tar command. Syntax can be looked up with man jar. To create a simple JAR file containing image files, place them in a directory called img. Then do the following: $ jar -cvf icons.jar img/* added manifest adding: img/welcome.gif(in = 870) (out= 534)(deflated 38%) adding: img/product.gif(in = 871) (out= 542)(deflated 37%) ... $ ls -l total 1366 -rw-r--r--

1 oracle

dba

drwxr-xr-x

2 oracle

dba

686829 May 10 13:11 icons.jar 2560 May 10 11:35 img

To view the contents of the JAR file, use jar –t filename, as follows: $ jar -tf icons.jar META-INF/ META-INF/MANIFEST.MF img/welcome.gif img/product.gif ...

Notice the use of a manifest file within the JAR file. Also notice that during the creation of the JAR file, the contents were compressed.

Web Archive (WAR) File Web application modules include JSPs and Servlets that generate dynamic presentation for the application. These components are packaged within a WAR file, which may contain JSPs, Servlets, HTML, and images. WAR files use the structure shown in Figure 9-3.

myWebModule.war | | ------- WEB-INF |

|

|

| ------- web.xml

|

| ------- orion-web.xml

|

|

|

| ------- classes

|

|

|

|

|

| ------ servlet1.class

|

|

| ------ servlet2.class

|

|

| ------ servletN.class

|

|

|

| ------- lib

|

| ------- library jar files

| | | ------- index.html | ------- page1.jsp | ------- page2.jsp | ------- images |

|

|

| ------- welcome.gif

|

| ------- product.gif

|

| ------- map.gif

Figure 9-3: WAR file structure

Web Application Archive (WAR) Structure In the previous example, the WAR contains Servlets (Servlet classes), JSPs (pageN.jsp), HTML (index.html), and image files (GIFs). These are located in the root directory. Under the WEB-INF directory is the web.xml file. This file is the deployment descriptor for WAR files. It tells what parameters are to be used for the deployment and application. A web.xml for the Petstore sample application is shown here:

WebTier Web Tier DD for the PetStore application webTierEntryPoint centralServlet no description com.sun.j2ee.blueprints.petstore.control.web.MainServlet webTierEntryPoint /control/* populateServlet Populate Servlet no description com.sun.j2ee.blueprints.tools.populate.web.PopulateServlet populateServlet /populate 54

index.html jdbc/EstoreDataSource javax.sql.DataSource Container ejb/catalog/CatalogDAOClass java.lang.String com.sun.j2ee.blueprints.shoppingcart.catalog.dao.CatalogDAOImpl ejb/profilemgr/ProfileMgrDAOClass java.lang.String com.sun.j2ee.blueprints.personalization.profilemgr.dao.ProfileMgr DAOImpl server/ServerType Oracle9iAS (1.0.2.2) Containers for J2EE java.lang.String ejb/catalog/Catalog Session com.sun.j2ee.blueprints.shoppingcart.catalog.ejb.CatalogHome com.sun.j2ee.blueprints.shoppingcart.catalog.ejb.Catalog

ejb/cart/Cart Session com.sun.j2ee.blueprints.shoppingcart.cart.ejb.ShoppingCartHome com.sun.j2ee.blueprints.shoppingcart.cart.ejb.ShoppingCart ejb/customer/Customer Session com.sun.j2ee.blueprints.customer.customer.ejb.CustomerHome com.sun.j2ee.blueprints.customer.customer.ejb.Customer ejb/profilemgr/ProfileMgr Entity com.sun.j2ee.blueprints.personalization.profilemgr.ejb.ProfileMgr Home com.sun.j2ee.blueprints.personalization.profilemgr.ejb.ProfileM gr ejb/scc/Scc Session com.sun.j2ee.blueprints.petstore.control.ejb.ShoppingClientContro llerHome com.sun.j2ee.blueprints.petstore.control.ejb.ShoppingClientCont roller

ejb/inventory/Inventory Entity com.sun.j2ee.blueprints.inventory.ejb.InventoryHome com.sun.j2ee.blueprints.inventory.ejb.Inventory
Here you can see Servlet and EJB mappings within the web.xml file. Within the WEB-INF directory are also subdirectories for classes and library JAR files, as shown here: $ ls lib classes classes: com

javax

META-INF

org

lib: customerEjb_client.jar

jaxp.jar

parser.jar

shoppingcartEjb_client.jar

inventoryEjb_client.jar

mailerEjb_client.jar

personalizationEjb_client.jar

signonEjb_client.jar

$ The web module files (JSPs and HTML) can be found in $ORACLE_HOME/j2ee/home/applications/petstore/petstore, as follows: $ ls -altr *jsp -rw-r--r--

1 oracle

dba

1429 May 27 21:01 topindex.jsp

-rw-r--r--

1 oracle

dba

1101 May 27 21:01 template.jsp

-rw-r--r--

1 oracle

dba

863 May 27 21:01 splash.jsp

-rw-r--r--

1 oracle

dba

347 May 27 21:01 signoff.jsp

-rw-r--r-1 oracle signinsuccess.jsp

dba

360 May 27 21:01

-rw-r--r--

1 oracle

dba

1391 May 27 21:01 signin.jsp

-rw-r--r--

1 oracle

dba

1557 May 27 21:01 sideindex.jsp

-rw-r--r-1 oracle preferencesform.html

dba

1480 May 27 21:01

-rw-r--r--

1 oracle

dba

2444 May 27 21:01 index.html

-rw-r--r-index.html

1 oracle

dba

262 May 27 21:01 annotated-

-rw-r--r-1 oracle addressform.html

dba

… $ ls -altr *html

$ ls -l META-INF total 4

1973 May 27 21:01

-rw-r--r--

1 oracle

dba

23 May 27 21:01 MANIFEST.MF

$ ls -l WEB-INF total 24 drwxr-xr-x

6 oracle

dba

4096 May 27 21:01 classes

drwxr-xr-x

2 oracle

dba

4096 May 27 21:01 lib

drwxr-xr-x

2 oracle

dba

4096 May 27 21:01 sql

drwxr-xr-x

2 oracle

dba

4096 May 27 21:01 tlds

-rw-r--r--

1 oracle

dba

3854 May 27 21:01 web.xml

drwxr-xr-x

3 oracle

dba

4096 May 27 21:01 xml

$ There's also an orion-web.xml file located in $ORACLE_HOME/j2ee/home/applicationdeployments/petstore/petstore. This file specifies OC4J options such as autoreloading and timeouts. The following is a sample orion-web.xml file: Because the Petstore application contains EJB components, there will also be orion-ejbjar.xml files located within each *.jar directory in $ORACLE_HOME/j2ee/home/application-deployments/petstore. These files are extracted from the WAR file during deployment. The WAR file is itself a web

module contained within a larger deployment file called the enterprise archive (EAR) file.

Enterprise Archive (EAR) File EAR files are a type of archive file designed to contain an entire J2EE application. The EAR file is what contains the modules that are composing a single application. It also represents what is actually deployed to the server. Packaging all the necessary modules together allows for easier deployment. The modules follow a standard structure that allows them to be deployed to any J2EE server. An EAR file is composed of the following: XML configuration files (for examples, application.xml and orionapplication.xml). Library components such as manifest files. Web modules such as JSPs and Servlets with HTML and image files. These are stored in a web archive (WAR) file. These files optionally may be included depending on if the application uses web components. Business modules such as EJBs stored in a Java archive (JAR) file. This optionally may be included depending on if the application uses EJBs. Client modules that access remote applications. Inclusion is optional depending on if the application uses it. Resource adapter that provides connection information to the EIS (database) tier. EAR files use the structure shown in Figure 9-4. myApp.ear | | ------- META-INF |

|

|

| ------- application.xml

|

| ------- orion-application.xml

| | ------- myApp.jar | | ------- myWebModule.war | | ------- myEJB.jar | Figure 9-4: EAR file structure

Enterprise Application Archive (EAR) Structure In the preceding example you have an EAR (myApp.ear) file containing a JAR (myApp.jar); a web module (myWebModule.war) containing Servlets, JSPs, HTML, and images; and an EJB component (myEJB.jar). It's not required to include all these components, but they are included here. Under the META-INF directory you have the application.xml. This deployment descriptor file identifies the components in the EAR file and their relative locations. The orion-

application.xml deployment descriptor file specifies OC4J specific parameters. A sample application.xml from the Petstore application is provided here: petstore Application description petstoreEjb.jar signonEjb.jar petstore.war customerEjb.jar personalizationEjb.jar inventoryEjb.jar shoppingcartEjb.jar mailerEjb.jar Here you can see that there are multiple modules within this application. It has seven EJB JAR

files and one web module (petstore.war). By packaging developed applications into EAR files (which may contain web applications, WAR and JAR files, and EJBs), a file that can be deployed to a J2EE server is created.

Deployment Once the J2EE application has been created and packaged within an EAR file, it's time to deploy it. In this chapter we'll show you how to deploy to the OC4J 9.0.4 standalone container. This isn't the full-size 10g AS product, but rather the smaller OC4J container. We cover the full size 10g AS product in Chapters 15–21 with a deployment covered in Chapter 18. Deploying to a standalone OC4J container allows you to either package and deploy an EAR file or to have OC4J reference an expanded directory structure without the EAR file. Since the expanded directory structure is only applicable to the standalone OC4J instance (not the 10g AS server), we'll focus on deploying EAR files.

Deployment Steps To deploy an EAR file manually to an OC4J standalone container, you'll need to use the java – jar admin.jar command. We'll use the Petstore example application for the sample. The steps are as follows: 1.

Log in to the server as the software owner. Since you're deploying to a Linux server where you have a standalone OC4J installation, log in as oracle, as follows: $ id uid=500(oracle) gid=501(dba) groups=501(dba),100(users)

2.

Verify the environment and OC4J version, as shown here: $ echo $ORACLE_HOME /u01/app/oracle/product/9.0.4oc4j $ cd $ORACLE_HOME/j2ee/home $ java -jar oc4j.jar -version Oracle Application Server Containers for J2EE 10g (9.0.4.0.0) (build 040317.1838) $

3.

Copy or use FTP to move the EAR file from the developer to the $ORACLE_HOME/j2ee/home directory. In this case, you're deploying petstore.ear, as follows: $ cp /home/oracle/deployments/ftp_dir/petstore.ear . $ ls -l petstore.ear -rw-r--r-petstore.ear

1 oracle

dba

1234968 May 27 20:36

$ Deploy the new application using the –deploy option to java –jar admin.jar. This will create a new directory structure for the application, as shown here: $ java -jar admin.jar ormi://192.168.1.11:11888 admin tigerpassword -deploy -file petstore.ear -deploymentName petstore

04/05/27 20:36:08 Notification ==> Application Deployer for petstore STARTS [ 2004-05-27T20:36:08.718EST ] 04/05/27 20:36:08 Notification ==> Undeploy previous deployment 04/05/27 20:36:08 Notification ==> Copy the archive to /u01/app/oracle/product/9.0.4oc4j/j2ee/home/applications/petstor e.ear ... Notification ==> Initialize petstore begins... Notification ==> Initialize petstore ends... Notification ==> Application Deployer for petstore COMPLETES [ 2004-05-27T20:36:18.010EST ] $ In the previous sample, you used the java –jar admin.jar command to deploy the application for the first time. You've configured the OC4J instance to use a nonstandard RMI port of 11888, and the IP is 192.168.1.11 so you should use ormi://192.168.1.11:11888. The username is admin and the password is tigerpassword. You can use the –deploy flag followed by –file, and the EAR file we you're deploying, called petstore.ear. Finally, you give the new application a deployment name with -deploymentName petstore. CHANGING OC4J PORTS For security it's often advisable to change the default ports of your application server. Additionally, if software is already installed on a server that already uses those ports, you must change the ports of newer software to avoid port conflicts. To change the default ports of OC4J standalone, edit the following files located in $ORACLE_HOME/j2ee/home/config. $ vi rmi.xml $ vi jms.xml $ vi http-web-site.xml

Change in 2 locations

Here you changed RMI to use 11888, JMS to use 11777, and HTTP to use 11999. The deployment will create a petstore directory containing a petstore.war file (extracted from petstore.ear) in the $ORACLE_HOME/j2ee/home/applications and application-deployments directories, as follows: $ ls applications application-deployments application-deployments:

default

petstore

applications: admin_ejb.jar dms0.war

admin_web.war

dms.war

petstore

dms

dms0

petstore.ear

$ 4.

Bind the newly deployed Petstore application to the /petstore URI using the – bindWebApp flag, as shown here: $ java -jar admin.jar ormi://192.168.1.11:11888 admin tigerpassword -bindWebApp petstore petstore http-web-site /petstore 04/05/27 20:38:58 Web-App default:defaultWebApp (0.0.0.0/0.0.0.0:11999/) started... 04/05/27 20:38:58 Building Application TagLibrary Persistent Cache for defaultWebApp 04/05/27 20:38:58 Done getting application current resources ... 04/05/27 20:38:58 Done persisting cache 04/05/27 20:38:58 Found 0 listeners $

5.

Access the application, using the /petstore binding, at the following URL: http://mike.wessler.name:11999/petstore/.

6.

If you need to undeploy (remove) an application, use the following –undeploy flag: $ java -jar admin.jar ormi://192.168.1.11:11888 admin tigerpassword -undeploy petstore 04/05/27 20:54:56 Notification ==> Application UnDeployer for petstore STARTS [ Thu May 27 20:54:56 EST 2004 ] 04/05/27 20:54:56 Web-App default:defaultWebApp (0.0.0.0/0.0.0.0:11999/) started... ... 04/05/27 20:54:57 Notification ==> Application UnDeployer for petstore COMPLETES [ Thu May 27 20:54:57 EST 2004 ] $

The application has now been undeployed. Checking the

$ORACLE_HOME/j2ee/home/applications and application-deployments directories shows that the Petstore application has been removed, as follows: $ ls applications application-deployments application-deployments: default applications: admin_ejb.jar

admin_web.war

dms

dms0

dms0.war

dms.war

$ The application can be deployed again by following steps 4 and 5.

Explanation of Deployment As you saw earlier, deployment is a two-step process. First, the application is deployed using the –deploy option to java –jar admin.jar. This will create a new directory structure for the application under the $ORACLE_HOME/j2ee/home/applications and applicationdeployments subdirectories. Next, you bound the application to a URI using the -bindWebApp flag of java–jar admin.jar. Although the deployment requires two commands by the deployer, the following are several actions that occur behind the scenes: First, the EAR file is opened and the application.xml file is read. Next, each deployment descriptor for each included module (such as web.xml for web modules) is read. Any parameter not listed in the deployment descriptors will have the default values applied. The application modules are created within the $ORACLE_HOME/j2ee/home/application-deployments directory. The $ORACLE_HOME/j2ee/home/application is also written. We cover the details of these directories in the "Directory Descriptions" section. The global configuration file $ORACLE_HOME/j2ee/home/config/server.xml has the application added to it. The global configuration file $ORACLE_HOME/j2ee/home/config/http-website.xml has the URI for the application bound to it. Memory is initialized with the application and it's ready to be executed. At this point the application can be executed because it has been deployed and bound.

Directory Descriptions Although the applications and application-deployments directories are specific to the application (not the global server), there are differences in content and purpose for each directory. The applications directory is used to hold the exploded EAR file. This is where you will find the JARs, HTML, and JSPs of an application. It will also contain the EAR file that was deployed, as shown here:

$ ls -l $ORACLE_HOME/j2ee/home/applications total 1768 -rw-rw-r--

1 oracle

dba

12399 Mar 17 13:33 admin_ejb.jar

-rw-rw-r--

1 oracle

dba

49665 Mar 17 13:33 admin_web.war

drwxr-xr-x

4 oracle

dba

4096 Mar 17 13:36 dms

drwxr-xr-x

4 oracle

dba

4096 Mar 17 13:36 dms0

-rw-rw-r--

1 oracle

dba

787 Mar 17 13:36 dms0.war

-rw-rw-r--

1 oracle

dba

811 Mar 17 13:36 dms.war

drwxr-xr-x

4 oracle

dba

4096 May 27 21:01 petstore

-rw-r--r--

1 oracle

dba

1234968 May 27 21:01 petstore.ear

$ In the previous sample, you can see the petstore.ear file and a petstore directory. Within the petstore directory, you can see the files that were contained in the petstore.ear file, as shown here: $ ls -l $ORACLE_HOME/j2ee/home/applications/petstore total 1364 -rw-r--r--

1 oracle

dba

67397 May 27 21:01 customerEjb.jar

-rw-r--r-1 oracle inventoryEjb.jar

dba

14997 May 27 21:01

-rw-r--r--

1 oracle

dba

7879 May 27 21:01 mailerEjb.jar

drwxr-xr-x

2 oracle

dba

4096 May 27 21:01 META-INF

-rw-r--r-1 oracle personalizationEjb.jar

dba

drwxr-xr-x

7 oracle

dba

-rw-r--r--

1 oracle

dba

266619 May 27 21:01 petstoreEjb.jar

-rw-r--r--

1 oracle

dba

941693 May 27 21:01 petstore.war

-rw-r--r-1 oracle shoppingcartEjb.jar

dba

23796 May 27 21:01

-rw-r--r--

dba

18314 May 27 21:01 signonEjb.jar

1 oracle

22273 May 27 21:01 4096 May 27 21:01 petstore

$ The files include EJB JAR files, the petstore.war file contains web modules, and the METAINF directory contains the application.xml file, as shown here: $ ls -l $ORACLE_HOME/j2ee/home/applications/petstore/META-INF total 8 -rw-r--r--

1 oracle

dba

-rw-r--r--

1 oracle

dba

880 May 27 21:01 application.xml 23 May 27 21:01 MANIFEST.MF

$ You can also see an additional petstore subdirectory located in $ORACLE_HOME/j2ee/home/applications/petstore. The web component contents of the petstore.war file is located in this directory, as follows: $ ls -l petstore

total 200 -rw-r--r-1 oracle dba accountcreationsuccess.jsp

613 Jun

4 17:29

-rw-r--r-1 oracle dba accountupdatesuccess.jsp

576 Jun

4 17:29 4 17:29

-rw-r--r-1 oracle addressform.html

dba

1973 Jun

-rw-r--r-index.html

1 oracle

dba

262 Jun

drwxr-xr-x

2 oracle

dba

4096 Jun

4 17:29 images

-rw-r--r--

1 oracle

dba

2444 Jun

4 17:29 index.html

-rw-r--r--

1 oracle

dba

475 Jun

4 17:29 index.jsp

drwxr-xr-x

2 oracle

dba

4096 Jun

4 17:29 ja

drwxr-xr-x

2 oracle

dba

4096 Jun

4 17:29 META-INF

-rw-r--r-1 oracle missingformdata.jsp

dba

1117 Jun

4 17:29

4 17:29 annotated-

...

… -rw-r--r--

1 oracle

dba

1429 Jun

4 17:29 topindex.jsp

drwxr-xr-x

7 oracle

dba

4096 Jun

4 17:29 WEB-INF

$ The $ORACLE_HOME/j2ee/home/application-deployments directory contains the application configuration files and compiled code for execution. It's also the directory structure where OC4J-specific orion-X.xml files will be found, as follows: $ ls -l $ORACLE_HOME/j2ee/home/application-deployments/petstore total 48 -rw-r--r--

1 oracle

dba

200 May 28 21:26 application.log

drwxr-xr-x

2 oracle

dba

4096 May 27 21:01 customerEjb.jar

drwxr-xr-x 2 oracle inventoryEjb.jar

dba

4096 May 27 21:01

-rw-r--r--

1 oracle

dba

615 May 27 21:01 jazn-data.xml

drwxr-xr-x

2 oracle

dba

4096 May 27 21:01 mailerEjb.jar

-rw-r--r-1 oracle application.xml

dba

1351 May 27 21:01 orion-

drwxr-xr-x 2 oracle personalizationEjb.jar

dba

4096 May 27 21:01

drwxr-xr-x

3 oracle

dba

4096 May 27 21:06 petstore

drwxr-xr-x

2 oracle

dba

4096 May 27 21:01 petstoreEjb.jar

-rw-r--r--

1 oracle

dba

215 May 27 21:01 principals.xml

drwxr-xr-x 2 oracle shoppingcartEjb.jar

dba

4096 May 27 21:01

drwxr-xr-x

dba

4096 May 27 21:01 signonEjb.jar

$

2 oracle

The configuration files are jazn-data.xml, orion-application.xml, and principals.xml. Notice that the *.jar are actually directories and not physical files, as shown here: $ ls -l customerEjb.jar total 52 -rw-r--r--

1 oracle

dba

-rw-r--r--

1 oracle

dba

45921 May 27 21:01 deployment.cache 1577 May 27 21:01 orion-ejb-jar.xml

$ In this case, they contain deployment.cache and orion-ejb-jar.xml files.

Forcing a Automatic Redeployment To force an automatic redeployment of the application, you can remove the application-specific subdirectories under applications and application-deployments. This is shown in the following procedure. 1.

Shut down the OC4J instance, as follows: $ java -jar admin.jar ormi://mike.wessler.name:11888 admin tigerpassword –shutdown

2.

Remove the $ORACLE_HOME/j2ee/home/applicationdeployments/application_name that's specific to the application you want to redeploy, as shown here: $ rm -rf $ORACLE_HOME/j2ee/home/application-deployments/petstore

3.

Remove the $ORACLE_HOME/j2ee/home/application/application_name that's specific to the application you want to redeploy, as follows: $ rm -rf $ORACLE_HOME/j2ee/home/applications/petstore Notice that you leave the EAR for the application. It's this file that's used for the redeployment, as shown here: $ ls -l $ORACLE_HOME/j2ee/home/applications/petstore.ear -rw-r--r--

1 oracle

dba

1234968 May 27 21:01

/u01/app/oracle/product/9.0.4oc4j/j2ee/home/applications/petstore. ear 4.

Restart the OC4J instance. The application will automatically redeploy, as follows: $ java -jar oc4j.jar -config config/server.xml -verbosity 10 err log/out.log

5.

During startup you can see that OC4J automatically deploys the application using the petstore.ear file, as shown here: 04/06/04 17:29:47 Auto-unpacking /u01/app/oracle/product/9.0.4oc4j/j2ee/home/applications/petstor e.ear... done. 04/06/04 17:29:47 Auto-unpacking /u01/app/oracle/product/9.0.4oc4j/j2ee/home/applications/petstor e/petstore.war...

done. 04/06/04 17:29:48 Auto-deploying petstore (New server version detected)... ... The applications and application-deployment directories that you deleted have been created, as follows: $ ls $ORACLE_HOME/j2ee/home/application*/petstore* /u01/app/oracle/product/9.0.4oc4j/j2ee/home/applications/petstore. ear /u01/app/oracle/product/9.0.4oc4j/j2ee/home/applicationdeployments/petstore: application.log

jazn-data.xml

personalizationEjb.jar

mailerEjb.jar

petstore

principals.xml customerEjb.jar

shoppingcartEjb.jar inventoryEjb.jar signonEjb.jar

orion-application.xml

petstoreEjb.jar

/u01/app/oracle/product/9.0.4oc4j/j2ee/home/applications/petstore: customerEjb.jar petstoreEjb.jar

mailerEjb.jar

personalizationEjb.jar

shoppingcartEjb.jar inventoryEjb.jar petstore.war

META-INF

petstore

signonEjb.jar $ The application is again accessible via the following URL: http://mike.wessler.name:11999/petstore/.

Summary In this chapter we identified the architecture of J2EE applications including client tier, web tier, business tier, and Enterprise Information Systems (EIS), which usually exists as a database. You learned about the components available within J2EE applications and the purpose of each. Specifically, we discussed client applications, web applications, and EJBs. Then you saw how they exist within JAR, WAR, and EAR files. Next, you learned about the configuration options available for each of these file types. Finally, we covered how to deploy an application to a standalone OC4J container, what actually occurs during deployment, and how to force a redeployment.

Chapter 10: Web Applications Overview Oracle AS 10g (9.0.4) is J2EE 1.3 compatible and supports web applications based on the Servlet 2.3 and Java Server Pages (JSP) 1.2 specifications, which are both backward compatible to previous versions. Web applications can access all the other resources deployed within OC4J, including Enterprise JavaBeans (EJBs), Java Message Service (JMS) connection factories and destinations, JDBC data sources, and JavaMail sessions. The web application itself may include Servlet classes, JSPs, tag libraries for JSPs, Servlet filters, deployment descriptors and other XML configuration files, and any resources or static content (HTML pages, images, and so on) required by the application. In addition to the functionality required by the J2EE 1.3 specifications, OC4J supports many additional features that can be configured in an orion-web.xml descriptor. Some of the most useful settings include the ability to override settings in web.xml, additional container-managed security, and automatic caching and content expiration. These features are very useful in a production environment; intelligent content-expiration settings can boost an application's performance. The orion-web.xml descriptor is placed in the same location (/WEB-INF) as the standard web.xml deployment descriptor. This server-specific deployment descriptor, which inherits from a global file of the same format, resolves any references declared in the standard deployment descriptor, such as EJBs, JMS destinations, and security roles, and configures the web container for the application. Before you get into the nuts and bolts of OC4J deployment descriptor files, let's take a quick look at the basic web development process, including common directory structures, build strategies, and deployment options.

Building and Deploying Applications There are two basic ways to deploy a web application. You can either let OC4J repackage your application from a WAR package to an EAR package or you can use an EAR package. Let's take a look at a very simple application packaged in a WAR file:

WAR Applications In this example, the application's Servlet is mapped to an *.html URL pattern and will simply print "Hello world" to the response stream. The directory structure for this application is shown in Figure 10-1.

Figure 10-1: Directory structure for the HelloWorld application The various directories are described in Table 10-1. Table 10-1: Application Directory Descriptions Directory

Description

/build

Contains Java class files that generated during the build process.

/dist

Contains the distributable application package.

/lib

Contains JAR files used by the application.

/Web

Contains files specific to the web component of the application.

/Web/build

Contains Java class files for the web component.

Table 10-1: Application Directory Descriptions Directory

Description

/Web/dist

Contains the distributable package for the web component (typically the WAR file).

/Web/src/as-web

Contains source codes for the application server (typically JSP files); this directory must also contain the WEB-INF directory with the web.xml application descriptor.

/Web/src/httpdweb

Contains files that can be served by the HTTP server (typically static content such as images, HTML files, stylesheets, and so on).

/Web/src/java

Contains the Java code for the application's web component.

Now that you have the directory structure for the application, you can implement a simple Servlet and create the application descriptor. The Servlet will print "Hello world" to the response stream, regardless of any request parameters, as shown here: package com.apress.oc4j.Webapplications; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SampleServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getOutputStream().print("Hello World"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } There's nothing in the Servlet code worthy of special attention. Similarly, the web.xml descriptor is very basic, as shown here:

OC4J Sample Web Application Chapter 10 sample application sample com.apress.oc4j.webapplications.SampleServlet 1 sample *.html 10 index.html 404 /error.htm To build the application, you need to write an Ant build script. Using the rules in the build.xml file, Ant will compile the Java sources and assemble the WAR file. The build.xml file



Running Ant will result in the creation of a simple.war file in the /web/dist directory. This means that you have the first application and you can deploy it. Provided that you haven't changed the default settings, go to http://localhost:1810/ to open up Application Server Control, as shown in Figure 10-2.

Figure 10-2: Application Server Control main page Then click the instance name to which you wish to deploy the application and select the Applications tab, as shown in Figure 10-3.

Figure 10-3: OC4J list of applications Then click the Deploy WAR File button to start the deployment. Because OC4J needs to convert the WAR file into an EAR file, you'll need to provide the application name and URL to which you want to map the application. Locate the WAR file and set the Application Name setting to sample and the Map to URL setting to /sample. OC4J will wrap the WAR file into an EAR file and deploy it. When OC4J deploys the application, it will be listed among other applications, as shown in Figure 10-4.

Figure 10-4: Deployed applications in OC4J Application Server Control Notice that even though you have deployed the application as a WAR file, OC4J wrapped it into an EAR file and deployed the EAR. Depending on the HTTP_Server configuration, the application will be accessible on http://localhost/sample/.html. Because the URL pattern mapping in the application says "all .html requests are mapped to SimpleServlet," you'll see a nice "Hello world" message, as shown in Figure 10-5.

Figure 10-5: The SampleServlet web application in action

EAR Applications To take full advantage of OC4J's features and to simplify the deployment, you'll modify the build procedure to produce an EAR file instead of a WAR file, as shown in Figure 10-6.

Figure 10-6: Revised project diectory structure for packaging as EAR file You should add another directory, /ear. This includes the META-INF directory, which contains the application.xml descriptor. The descriptor specifies the application's name and configures the web module, as described in the following code sample:

Chapter 10 sample application sample.war /sample

You'll also need to modify the build.xml file to instruct and create an EAR file, as shown in the following code sample:



Running Ant using the new build file will produce a simple.ear application placed in the /dist directory. To deploy the created EAR file, go to OC4J Application Server Control, click the instance name to which you want to deploy the application, select the Applications tab, and click the Deploy EAR File button. Locate the EAR file, specify the application's name and click Continue. OC4J will process the EAR file and suggest a URL mapping from the /METAINF/application.xml file, although you're free to replace it with one of your own. Just as in the WAR deployment, the application will be listed among other applications and you can test it by going to http://localhost/sample/foo.html. The result should be "Hello world," with the exception that this time it comes from the EAR application that you've built.

EAR Deployment Mechanics You know how to deploy an application—that's the first step. Let's take the next step and explore what OC4J does behind the scenes when you tell it to deploy an EAR file. OC4J will decompress the EAR file and the WAR file inside it into a directory of the same name as the one you specified in the Application Name field the earlier. You can see an example of this in Figure 10-7.

Figure 10-7: OC4J home directory and deployed sample application Typically, an application will be decompressed in the orahome/j2ee//applications/ directory. On inspection of the directory structure in orahome/j2ee/home/applications/sample/, you can tell that you've deployed an application called "sample" into the "home" instance. To check that this is indeed the correct directory, let's create a static.htm file and place it into orahome/j2ee/home/applications/sample/. The content of the file isn't relevant; when the file is in the directory, you can try accessing it by navigating to http://localhost/sample/static.htm, as shown in Figure 10-8.

Figure 10-8: Static file served by OC4J Notice that the file extension is htm, not html; HTML files are handled by the Servlet. Renaming the file to static.html and refreshing the page will result in a "Hello world" message printed by the Servlet. Now that you know what OC4J does to deploy an application, you can use it to speed up the development. Programming a web application involves a mix of writing Java code that controls the logic and content creation, which in turn controls how the application is presented to the user. Any change to the logic must result in a rebuild of the application and in redeployment in order to effectively get the changes to the OC4J server. Even though you can change the class files in the WEB-INF/classes directory, there's no guarantee that OC4J will reload the changed class. It's therefore necessary to build and redeploy the entire application if the Java code changes. For example, if you changed the SimpleServlet to print the equally infamous string Foobar! instead of Hello world then you would need to recompile the Java code and repackage the application, resulting in a new EAR file. Next, you could undeploy and then deploy it from scratch, but that would be unnecessarily complicated. Instead, you can select the application in the application list and click Redeploy, thereby specifying the new EAR file. OC4J will redeploy the application in a single step. Changes to a JSP page, however, need not necessitate redeployment of the whole application. Let's take a look at that now.

Updating JSPs If you take the time to explore the uncompressed directory, you must be wondering where the temporary files, such as compiled JSP pages are. The uncompressed directory structure, …/home/applications/sample/, isn't the actual working directory. The working directory is in the application-deployments subdirectory, as shown in Figure 10-9.

Figure 10-9: The application-deployments directory This structure looks much more familiar. OC4J generated all the additional application descriptors and temporary directories for the JSP pages. Even though OC4J runs the application from this directory, don't modify any files in it. To start from a well-defined point, let's remove the sample application from the OC4J instance by selecting it and clicking Undeploy. Then redeploy the application using the procedure described in the "EAR Applications" section. The application is now deployed and it contains an index.jsp file in the sample.war directory. To verify that the new application is deployed, go to http://localhost/sample/index.jsp. OC4J will compile the JSP page and display its contents. Let's now change the content of the JSP page that doesn't require any additional logic (for example, correcting a spelling mistake). You'll change it in the project directory; but you don't want to redeploy the entire application just because you've changed a single JSP file. You can take advantage of the fact that OC4J decompresses the application. You'll overwrite the JSP page in orahome/j2ee/home/applications/sample/sample/index.jsp. Providing you haven't changed the configuration of the JSP container in the instance, OC4J will detect that the

JSP file has been changed and recompile it. The entire process is relatively painless and—most important—doesn't require redeployment of the application

Configuring orion-web.xml Now that you've mastered application deployment, you can move ahead and explore more OC4J features. With the right global settings, many J2EE web application archives (EAR files) can be deployed unchanged, without any special configuration beyond their standard web.xml descriptors. However, if you want to take advantages of OC4J features, you need to add an OC4J-specific descriptor, orion-web.xml, located at /WEB-INF/orion-web.xml, to the web module. Tip

Any orion-web.xml settings not specified for an individual application will inherit values from the global-web-application.xml configuration file in the orahome/j2ee//config directory, which uses the same DTD as orion-web.xml.

The orion-web.xml deployment descriptor does the following: Configures reloading behavior, charsets, and other web container settings. Allows overriding of context parameters and environment entries in web.xml. Configures web application classloading behavior. Configures file types and virtual hosts. Configures clustering for this web application (if clustered). Configures additional Servlet filters. Configures the sessions used to store data for users connected to the web application. Resolves resources (including JDBC data sources, EJBs, JMS destinations and connection factories, and JavaMail sessions) to specific services deployed in OC4J. Resolves security roles to users or groups defined by the configured UserManager or Java Authorization (JAZN) realm. Configures host and IP-based network access controls. Allows overriding of any element in web.xml. The document type declaration (DTD) used for the orion-web.xml deployment descriptor and the global-web-application.xml configuration file can be found on Oracle's website at http://xmlns.oracle.com/ias/dtds/orion-web-9_04.dtd.

First Look at orion-web.xml Now that you know what this descriptor does, you can add it to the project. You'll start off with the most basic orion-web.xml, as shown in the following listing:

When you rebuild, repackage, and redeploy the application, nothing notable is going to happen. The Servlet is still going to print Foobar, and the JSP pages will be compiled as usual. Let's take a look at the full orion-web-app element in the orion-web.xml file.

Before you move any further let's examine each attribute in more detail. Even though the attributes and their values are fairly self-explanatory, there are a few candidates for a more detailed description, as shown in Table 10-2. Table 10-2: orion-web-app Element Attributes Attribute

Description

deployment-version

Default deployment version should be set to 9.0.4.0.0 for 10g application server.

temporary-directory

Directory the server is going to use for temporary files, such as JSP Servlets. The current directory is orahome/j2ee//applicationdeployments//, so ./temp in the home instance maps to orahome/j2ee/home/applicationdeployments/sample/sample/temp.

internationalizeresources

Specifies whether to load resources based on the server's locale.

default-mime-type

Sets the default mime type for the application.

default-buffer-size

Sets the size of the output stream buffer.

default-charset

Specifies the default character set for the application.

source-directory

Used in conjunction with development="true"; specifies the source directory, and that the files in the source directory will automatically be recompiled when they're changed.

simple-jsp-mapping

If set to true, OC4J will use oracle.jsp.runtimev2.JspServlet to compile the JSP pages. This will speed up JSP processing, but if you're using Servlets that map to *.jsp URL pattern, you must set this to false.

servlet-webdir

Specifies the Servlet runner path for invoking a Servlet by class name. Anything appearing after this path in a URL is assumed to be a class name, including the package as appropriate.

persistence-path

Specifies directory to persist session state between redeployments. If this value isn't specified, application state will be lost between redeployments. Note that all objects must be marked by Serializable interface.

jsp-timeout

Sets the timeout after which the JSP page will be removed from memory. This is useful when you have limited resources and want to free up as much memory as possible. Setting timeout to 0 means no timeout; any positive value means a timeout in seconds.

jsp-print-null

If set to true, OC4J will print null for JSP pages that don't generate any content.

Table 10-2: orion-web-app Element Attributes Attribute

Description

jsp-cache-directory

The JSP cache directory is used as a base directory for output files from the JSP translator. It's also used as a base directory for application-level TLD caching. The default value is ./persistence, relative to the deployment directory of the application.

jsp-cache-tlds

Specifies whether to cache tag library definition files.

jsp-taglib-locations

If jsp-cache-tlds is set to true, you can specify the location of well-known TLD files in a semicolon-separated list. The location list can include JAR files.

file-modificationcheck-interval

Sets interval in which the static files (such as images or HTML files) are checked for modification, in milliseconds. It's advisable to set this to a very high value in production environment.

enable-jspdispatcher-shortcut

If your JSP files use numerous include statements, you can improve performance by setting this to true. You can gain further performance boost by setting this attribute to true together with simple-jsp-mapping.

directory-browsing

Specifies whether users are allowed to view the directory structure of your application.

development

Specifies that this application is in the development phase and OC4J will detect changes to files in path defined in source-directory and recompile them. However, this means that your source-directory must match the structure of the application, which is generally not a good practice.

Now that you know what attributes you can set in the root element of the orion-web.xml descriptor, you can move on to all the other settings you can use to modify the behavior of OC4J and the application.

Overriding Context Parameters and Environment Variables Every application will sooner or later have to be changed. Providing that all you need to do to accomplish the change request is to change the configuration file, OC4J allows you to modify the application's settings without changing the original web.xml descriptor. This can be price-less, because you can keep the original web.xml in the source control and still be able to tweak the application's configuration on production servers, by overriding values in this web.xml descriptor from the orion-web.xml descriptor. The following elements in orion-web.xml can override individual context parameters and environment entries defined in web.xml (located in the /WEB-INF directory of the web module), as shown in Table 10-3.

Table 10-3: context-param-mapping Element of the orion-web.xml Descriptor Parameter

Description

context-param-mapping

Overrides a context parameter, replacing the value specified in web.xml with the value specified in the body of this element.

context-parammapping:name

The name of the context-param to override (should match the name in web.xml).

env-entry-mapping

Overrides the value of an environment entry specified in web.xml.

env-entry-mapping:name

The name of the env-entry to override (should match the name in web.xml).

Let's take a look at a practical example that will show how to override values defined in the web.xml file. You'll start with a standard web.xml descriptor, where you'll define a contextparam value, as follows: OC4J Sample Web Application Chapter 10 sample application publisher CHANGE-ME Publisher of the book Ideally, you would still like to keep the web.xml descriptor clean of all deployment-specific settings. This is where orion-web.xml comes in place. You can use the context-parammapping element and override the appropriate context parameter, as shown in the following code sample:

Finally, to see that it actually works, you'll modify the Servlet to read in the context parameter and to print to the response stream, as follows: public class SampleServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Object publisher = getServletContext().getInitParameter("publisher"); response.getOutputStream().print("Foobar, published by " + publisher); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } After redeploying the application and navigating to http://localhost/sample/foo.html, you'll see something like Foobar, published by Apress. You can use the same procedure to override environment settings in web.xml, from orionweb.xml.

Classloading The elements described in this section allow for the customization of classloading behavior for a particular web application. This can be useful for backward compatibility and for resolving a variety of classpath issues. In particular, if a library that dynamically loads classes is used at a higher level in the classloading hierarchy, then setting the search-local-classes-first option may be the only way to avoid classloading issues, without placing the entire web application codebase at the higher level. Note

See Chapter 3 for a review of the mechanics of Java classloading.

The issues with classloading are particularly important when you have more than one application in the container, and each application uses different versions of individual classes. You must configure the container's class loader for each application separately so that it will not try to make its job easier by using an already-loaded class or interface. Consider a situation in which you have two applications that use the same class, but in which each application uses a different version of the class. This isn't too difficult to imagine if you have to support legacy applications. If you placed the JAR containing the class into the applib directory so that the applications can share it then the classloader would ignore classes in the application's lib directory. You can use orion-web.xml to specify classloader settings for each application in an instance, using the following two elements: classpath and web-appclass-loader, which are explained in Table 10-4. Table 10-4: Classloading Mappings Parameter

Description

Default Value

classpath

Specifies an additional codebase that should be placed on the classpath for this web application.

classpath:path

The path to the codebase (either absolute or relative to orion-web.xml).

web-app-classloader

Allows configuration of web application classloading behavior (through the two attributes listed next).

web-app-classloader:searchlocal-classes-first

If true, the server will load classes from the WAR in preference to those found higher in the classloader hierarchy (that is, a class located in WEBINF/someLib.jar would be loaded instead of one on the system classpath).

false

web-app-classloader:include-war-

If true, the server will honor the classpath

true

Table 10-4: Classloading Mappings Parameter

Description

manifest-class-path

specified in the WAR's manifest file. If false, that classpath with be ignored.

Default Value

To try classloading out, you'll create a simple JAR library with a single class, called ClassloaderTester. You'll place the JAR in the orahome/j2ee//applib directory and use it in the application. Then you'll modify the ClassloaderTester code, place it in the application's lib directory and run the application again. You'll follow this process in detail to demonstrate and test the classloading functionality of OC4J. To do this, you'll need to modify the project's directory structure and the build file. The modification to the directory structure is quite straightforward: You'll add util/src/java, util/build and util/dist directories to the project. You need to add these two directories because you'll want to build a JAR file with classes from util/src/java. The additions to the build file aren't too complex, either. All you need to do is to compile the source files in util/src/java and package them into util.jar in util/dist, as shown in the following code sample: Modified /build.xml file



Before you can demonstrate classloading settings, you have to actually use the code from util.jar in the application, as follows: public class SampleServlet extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Object publisher = getServletContext().getInitParameter("publisher"); ClassloaderTester tester = new ClassloaderTester(); response.getOutputStream().print("Foobar, published by " + publisher + ", version " + tester.getVersion()); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } When you deploy the application and navigate to http://localhost/sample/foo.html, you'll see Foobar, published by Apress, version v1. This proves that the Servlet can load the ClassloaderTester class from util.jar, which is in turn placed in the web application's lib directory. Let's now modify the build file further to move the util.jar library out of the lib directory of the web application and place it into orahome/j2ee//applib. To do that, simply remove the line from the element in the dist-web target in the build.xml file, and copy util.jar to the applib directory of the instance you're using and restart the instance. Running the application again will produce the same output. Let's now modify the ClassloaderTester class to return a different value, say v2, and place it back into the lib directory of the application. When you redeploy the application, it will still print Foobar, published by Apress, version v1, because the classloader loaded ClassloaderTester class from util.jar in the applib directory. In order to correct this, modify the orion-web.xml descriptor in /src/web/as-web/WEB-INF, as shown here:

Rebuild and redeploy the application and it prints Foobar, published by Apress, version v2, even though ClassloaderTester class in util.jar in applib still returns v1.

Classpath Settings Sometimes it's necessary to directly modify the classpath that OC4J is to use for the application. To do this, all you need to specify is the element after the root element, as shown here:

File Types, Locations, and Type-Based Filters OC4J sets the MIME type on a response based on file-extension mappings found in a mimemappings file. However, in some cases, you may want to intercept certain types of files (for example, XML) and transform them before they're returned to the client. The Servlet-chaining element allows you to configure a Servlet to intercept outgoing responses of a certain MIME type. At other times, you may want requests for certain files to be mapped to a common shared directory on the server. Using the element, you can map a "virtual" directory within the web application to a real directory somewhere on the server. This can often be useful for sharing large repositories of static content between applications, as shown in Table 10-5.

Table 10-5: MIME Mappings and Servlet Chaining Parameter

Description

mime-mappings

References the file that contains extension to mime-type mappings.

mime-mappings:path

Either an absolute path to the mimemappings file, or a path relative to orion-web.xml.

virtual-directory

Specifies the path of a directory on the server that should be mapped to a "virtual" directory within the web application.

virtualdirectory:real-path

Path of the real directory on the server (for example, /var/sample/static)

virtualdirectory:virtualpath

Path within the web application that should be used to access it (for example, static/)

servlet-chaining

Specifies a Servlet to be called after a response has been generated with a certain MIME type (but before it's returned to the client).

servletchaining:mime-type

The MIME type to intercept.

servletchaining:servletname

The Servlet that should be called for the specified MIME type.

Default Value

./mime.types

We'll discuss the servlet-chaining parameter in more detail later in this chapter; the mimemappings and virtual-directory elements are best demonstrated using an example. Let's consider the following scenario: A client's request is handled by SampleServlet, which sets content type to text/plain depending on a request parameter. The task is to filter the output generated by SampleServlet to make sure it's text/plain. The most elegant way to do this is to implement another Servlet, TextPlainServlet, which will read all input from the request, filter it, and write it to the response. OC4J will take care of chaining the TextPlain-Servlet after SampleServlet. Let's modify SampleServlet and create TextPlainServlet, as follows: public class SampleServlet extends HttpServlet { // doPost omitted protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Object publisher = getServletContext().getInitParameter("publisher"); ClassloaderTester tester = new ClassloaderTester();

if (request.getParameter("plain") != null) { response.setContentType("text/plain"); } response.getOutputStream().print("Foobar, published by " + publisher + ", version " + tester.getVersion()); } } public class TextPlainServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { byte[] buffer = new byte[16384]; int read; while ((read = request.getInputStream().read(buffer, 0, buffer.length)) > 0) { // do some advanced filtering here response.getOutputStream().write(buffer, 0, read); } response.getOutputStream().print(". Filtered by TextPlainServlet"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } You can see that TextPlainServlet doesn't actually do any processing by itself; it simply transforms input received from the request stream to the response stream. There's actually no filtering in the sample code; we'll leave any transformation of the input to the output to you. Next, you need to define the TextPlainServlet in web.xml and specify it in orionweb.xml, as follows:

samplePlain com.apress.oc4j.webapplications.TextPlainServlet 2 Notice that you don't actually map the Servlet to any URL pattern. Next you'll modify the orionweb.xml descriptor so that the TextPlainServlet is executed before the response is returned to the client, as shown here: Let's see if the changes worked: Go to http://localhost/sample/foo.html. The output will be Foobar, published by Apress, version v2, which is exactly what you should be expecting. If you now set the request parameter Plain to any value, the TextPlainServlet will execute the request to http://localhost/sample/foo.html?plain=1 as Foobar, published by Apress, version v2. Filtered by TextPlainServlet.

Virtual Directories To take a break from all the programming you can take a look at MIME types and virtual directories. Sometimes you'll want to store a lot of static content outside of the web application, but you'll want it to be accessible from the application's context. You may have thousands of images you want to display from your application, but you want to keep them in a separate directory on the server's file system. Creating a virtual directory takes care of this situation, as shown here: The content of C:\var\oc4j\sample\static is just one image, as shown in Figure 10-10.

Figure 10-10: File in C:\var\oc4j\sample\static Provided that you have added the virtual-directory element to orion-web.xml and redeployed the application, you should see the cover of Oracle Application Server 10g on http://localhost/sample/static/10gASCover.jpg

Clustering Clustered web applications should specify the following elements listed in Table 10-6 under the element in orion-web.xml. Nonclustered applications should omit them. For more about clustering, see Chapter 21. Table 10-6: Clustering Settings Parameter

Description

Default Value

cluster-config

Specifies a cluster-id and network information used to share HttpSession state. Should only be used within clustered applications.

cluster-config:host

The multicast host or IP to be used for cluster data.

230.0.0.1

cluster-config:id

The cluster identifier for this server instance.

Defaults based on local machine IP address

cluster-config:port

The port to be used for cluster data.

9127

URL-Based Expiration In many situations, you may want to adapt the application's behavior based on particular URL patterns. For instance, you may use a Servlet filter to detect and prevent data mining, or set a special expiration policy for files that never change. The elements defined in orion-web.xml offer the same functionality as the more portable Servlet filter declarations in web.xml. If a with the same

name already exists in web.xml, specifying it again in orion-web.xml will override the definition from web.xml. This is useful for specifying additional configuration parameters for the filter. If the filter doesn't exist in web.xml, but does exist in orion-web.xml, the filter will be added. Unlike all other settings defined OC4J descriptor files, settings in web.xml override settings in global-web-application.xml. The element allows you to customize caching behavior for certain request patterns. If your web application uses images generated on the fly, for example, you should to specify 0 for the expires attribute to make sure the users always see the most up-todate image. The filter settings are listed in Table 10-7. Table 10-7: Servlet Filter Settings Parameter

Description

expiration-setting

Allows the customization of cache expirations based on a particular URL pattern.

expiration-setting:expires

The number of seconds before a matching URL should expire ("never" if it should never expire).

expiration-setting:url-pattern

The URL pattern to be matched (for example, *.png).

The expiration settings are sent to the client; it is therefore up to the client's browser to make another request when the content expires. You may set the content to expire say every hour on all static GIF images by specifying expiration-setting in orion-web.xml:

Session Configuration, Session and Request Tracking HTTP user sessions are generally managed by a Servlet container through browser cookies. Some users, however, may be unable or unwilling to accept cookies, in which case the server will fall back to URL rewriting, in which every link includes a unique session ID that can be used to locate a user's session state across requests. URL rewriting adds additional strain (even if very low) to the server, because the server needs to preprocess each request to include and identify the session ID. The use of this feature depends on the target audience of your application. If you're developing an intranet application, there's no need for URL rewriting because the application is going to run in a controlled environment where you can make sure all client browsers allow cookies. For an application that's required to be accessible to all clients, enabling URL rewriting is necessary. URL rewriting is handled by OC4J; it's transparent to any Java code. You can use request.getSession() and OC4J will make sure that your code will receive a valid HttpServletSession object. The following elements configure the default session behavior and allow you to specify Servlets to track both sessions and requests. These settings are listed in Table 10-8.

Table 10-8: Session Tracking Settings Parameter

Description

Default Value

request-tracker

Allows the specification of a Servlet that should be invoked once for each request (for example, to record it to a log).

requesttracker:servletname

The name of the Servlet to be invoked.

session-tracking

Parameters for how the web app tracks sessions.

sessiontracking:autoencode -absolute-urls

If true and cookies are disabled, causes OC4J to use URL rewriting for session tracking.

false

sessiontracking:autoencode -urls

If true and cookies are disabled, causes OC4J to use URL rewriting for session tracking.

false

sessiontracking:autojoinsession

If true, users are assigned a session immediately when they log in to the application.

false

sessiontracking:cookiedomain

The domain associated with the cookie.

sessiontracking:cookiemax-age

Maximum number of seconds a cookie should be saved by the browser. If unspecified, the cookie doesn't outlive the user's browser session.

sessiontracking:cookies

Whether session cookies should be used.

session-tracker

Allows the specification of a Servlet that should be invoked whenever a session is created (for example, to record it to a log).

sessiontracker:servletname

The name of the Servlet to be invoked.

enabled

We'll demonstrate both request and session tracking using a very basic Servlet called RequestTrackerServlet. The actual implementation isn't going to do any actual tracking; it will simply remind the user that his request is being tracked, as shown here: public class RequestTrackerServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getOutputStream().print(

"Long live bytecode!"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } If you add a request-tracker element to orion-web.xml and register the Servlet in web.xml you'll see a dark reminder printed by the RequestTrackerServlet whenever you make a request to the application. requestTrackerServletmn com.apress.oc4j.webapplications.RequestTrackerServlet Notice that we didn't specify the load-on-startup priority for the Servlet in the web.xml descriptor to make sure the TrackerServlet doesn't get loaded when the application starts, as shown here: Any requests to the application will now pass through the request Servlet. The tracker Servlet can perform any processing; it doesn't necessarily have to modify the output. Session tracking works in exactly the same way as request tracking. Create a Servlet, define it in web.xml and then instruct OC4J to treat it as session filter Servlet in orion-web.xml. Session settings on the other hand are very straightforward, and except for a word of warning to use consistent naming scheme for your cookies, there's nothing tricky or difficult about them.

Resolving Resource References and EJB References Resources and EJBs referenced by the web application (in web.xml) should be mapped to actual Java Naming and Directory Interface (JNDI) locations using the elements in the following code sample. Let's consider this scenario: In JNDI, you wish to configure a DataSource that you'll use in the web application. This instructs OC4J to map an existing JNDI entry into a new one, providing that the value of the

name attribute matches a resource-ref element in a web.xml descriptor. These references are listed in Table 10-9. In the following code example, we've mapped jdbc/HyperSonicDS to jdbc/myDS and you can now use this in the application's Java code, as follows: Context context=new InitialContext(); DataSource ds=(DataSource)context.lookup("java:comp/env/jdbc/myDS"); Table 10-9: EJB References in orion-web.xml Parameter

Description

resource-ref-mapping

Resolves a reference to a DataSource, JMS destination, mail session, or other resource.

resource-ref-mapping:location

JNDI name where the resource can be found.

resource-ref-mapping:name

Name used in the web.xml reference.

lookup-context

Allows the optional specification of a particular context to be used to look up a resource (useful when the resource is outside the server).

lookup-context:location

Name where resource can be found in the specified context.

context-attribute

Specifies JNDI properties to be used for the specified lookup-context. Only the initial context factory property is required.

context-attribute:name

Name of the JNDI property (for example, java.naming.factory.initial).

context-attribute:value

Value of the JNDI property (for example, the class name of the initial context factory).

ejb-ref-mapping

Maps an EJB reference to a deployed EJB.

ejb-ref-mapping:location

The JNDI location where the EJB is located.

ejb-ref-mapping:name

The name of the EJB ref in the web.xml reference.

Finally, it's important to realize that these mappings affect only the web application, not necessarily every component within an EAR file.

Security Configuration and Resolving Security Roles If OC4J can map every application role directly to a group defined in principals.xml with the same names. Then the following security elements aren't necessary. However, for portability, backward compatibility, future security, and other considerations, it's usually more appropriate to explicitly map application roles to actual users and groups using a
mapping>. Specifying any security-role-mappings will disable the implicit mappings to principals.xml. The security configuration settings are listed in Table 10-10. Table 10-10: Security Configuration Settings in orion-web.xml Parameter

Description

security-rolemapping

Maps a J2EE application role to one or more users and groups known to the UserManager.

security-rolemapping:impliesAll

If true, all users are assumed to have this role. If false, individual users and groups should be specified using the and elements.

security-rolemapping:name

The name of the role as specified in web.xml.

user

Allows the assignment of a role to an individual user.

user:user:name

The username of the user who should be given this role.

group

Allows the assignment of a role to a group of users.

group:name

Name of the group that should be given this role.

Default Value

false

A good place to get thorough understanding of security roles is Chapter 7. Here's a quick example that will show you if a user is in a particular role: public class SampleServlet extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Principal principal = request.getUserPrincilal(); if (request.isUserInRole("users")) { response.getOutputStream().print("Only human!"); } else{ response.getOutputStream().print("The One!"); } response.getOutputStream().print(principal.getName()); }

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } This simple example demonstrates how to get the Principal of a user accessing the Servlet. If you need to check role membership, you can use the request.isUserInRole() method, however, you shouldn't have to do this because you'll probably use declarative security and access control in the web.xml descriptor, as shown in the following code sample. Declarative security in web.xml Admin /admin/* Root Administrators Users /users/* Users With these settings in the web.xml descriptor, OC4J will make sure that requests to path /admin/* can be executed only by Root and Administrators, and any requests to /users/* can be allowed from members of the Users role.

Host and Network-Based Access Control The element can be used to allow or deny individual domains or IP addresses. If the default attribute is set to allow, then all hosts and IPs will be allowed to access the application except those specifically denied through or subelements. If default is set to deny, then only the specifically allowed hosts and IP addresses will be able to access the application. The access control is checked by the server itself; you don't need to write any Java code to enforce these checks. It's useful to set up this security scheme for internal applications that will be accessed from a limited range of fixed (and trusted) IP addresses. Table 10-11 lists the element attributes. Table 10-11: access-mask Element Attributes Parameter

Description

Default Value

access-mask

Allows the restriction of access to particular domains and IP addresses, or the exclusion of particular domains and IP addresses.

access-mask:default

Whether unspecified domains and IP addresses should be allowed or denied (allow | deny).

allow

host-access

Restricts or allows access for a particular domain.

allow

host-access:domain

The host or domain (for example, saturn.wrox.com).

host-access:mode

Whether the corresponding host or domain should be allowed or denied.

ip-access

Restricts or allows access for a particular IP address.

ip-access:ip

The IP address (for example, 201.33.155.2).

ip-access:mode

Whether the IP address should be allowed or denied.

ip-access:netmask

Subnet mask.

allow

For example, to only allow requests from saturn.apress.com, you would use the following: By contrast, to block access from saturn.apress.com and all computers in subnet of

62.3.242.*, you would use the following:

Summary of Overriding web.xml Settings In addition to the many server-specific elements and attributes described earlier, a complete element (see the standard J2EE web.xml DTD) can be placed inside the root element. Within this element, you can override or supplement any of the settings found in the application's web.xml file. This lets you adapt and deploy prepackaged J2EE applications with minimal configuration hassle, since you can adjust environment entries, and so on, without editing their original "clean" descriptors.

Using the Application Server Control All settings in orion-web.xml can also be managed using the Application Server Control (ASC). This proves to be a great instrumentation tool. You don't need to redeploy your application. Caution

If the change you're making is permanent, it's a good idea to make the change in orion-web.xml before or immediately after making the change to the running application. Don't forget that once an application is redeployed, the changes made to orion-web.xml using the ASC will be overwritten by the new orion-web.xml descriptor.

Bring up the ASC by navigating to http://localhost:1810 and logging in as ias_admin with the password that you've specified during the installation. You'll see an overview of installed components. Click the instance you used to deploy the application, click the Applications tab, and then click the sample application. This will bring up a page that looks like what's shown in Figure 10-11.

Figure 10-11: ASC displaying the sample application Let's try out something that can be immediately visible: You'll modify the context-param "publisher," which is defined in web.xml and then overwritten in orion-web.xml. The current value is Apress. To change a context-param, click the web module name, sample, then click Environment and change the value simply by typing in a different value, as shown in Figure 1012.

Figure 10-12: Changing context parameters in ASC If you've tried out every example in this chapter, then after applying the changes and going to

http://localhost/sample/foo.html, the browser will show Foobar, 0, published by APRESS, version v2, Long live bytecode!. At this point it's not necessary to go through the ASC in more detail. Detailed coverage of ASC is provided in Chapters 16, 17, and 18. We simply wanted to point out that anything you can set in orion-web.xml you can also set using the ASC. Now that you've read this chapter, the best thing you can do is to write your own web application and try out all the settings in orion-web.xml that you find interesting.

Summary We've discussed various ways to deploy an application, depending on the development stage. The information you've learned will help you to streamline the development process and ease deployment. These sections can be applied to the majority of J2EE containers. We've also discussed the specific configuration settings of OC4J container. Using these special features will further simplify deployment and maintenance. Although these additional configuration files will make the application container-dependent, it's safe to assume that your customers will be happy to accept the fact that the system must be run in OC4J if it will result in a more robust and better performing system. Finally, your client paid for an OC4J license and it would be criminal not to take advantage of any extensions offered by the container.

Chapter 11: Enterprise JavaBeans Overview Oracle 10g AS supports Enterprise JavaBeans (EJBs) based on the EJB 1.1 and 2.0 specifications. EJBs can access all the services deployed in an OC4J server, including Java Message Service (JMS) connection factories and destinations, Java Database Connectivity (JDBC) data sources, and JavaMail sessions. EJBs are typically packaged in an EJB JAR file, which includes the EJB classes and deployment descriptors. This module is then packaged into a J2EE application archive (EAR file). As with other J2EE components, the standard EJB deployment descriptor indicates the resources required by the EJBs. However it's left to the application server to map those requirements to specific services available in the server. OC4J uses an additional deployment descriptor, orionejb-jar.xml, to manage resource mapping and container-managed-persistence (CMP) settings, as well as EJB container configuration.

Basic Deployment Process EJBs can be deployed in OC4J using the processes described in Chapter 9. As a quick review, you'll need to do the following: 1.

Develop and compile the beans.

2.

Create the standard EJB deployment descriptor (ejb-jar.xml).

3.

Create the server-specific orion-ejb-jar.xml (optional in some simple cases) to map Java Naming and Directory Interface (JNDI) locations, resource references, and so on.

4.

Optionally package the application into an enterprise archive (EAR) file.

5.

Configure any resources the EJBs will need to access. This may include setting up data sources in data-sources.xml, configuring security, creating JMS destinations for the message-driven beans, creating database tables for entity bean persistence, and so on.

6.

Create an entry in server.xml pointing to the application (whether to an EAR or an exploded directory structure). Optionally, you can use admin.jar or the Application Server Control (ASC) website to deploy the application instead of manually updating server.xml (see Chapters 9 and 18).

Once deployed, you should be able to test the EJBs from web applications (see Chapter 10) or application clients (see Chapter 13).

About orion-ejb-jar.xml Some very simple EJB applications can be deployed without any special configuration beyond their standard ejb-jar.xml descriptors. However, in most cases, you'll need to map JNDI locations, resource references, EJB references, security settings, and so on in orion-ejbjar.xml, which is packaged in META-INF/ along with ejb-jar.xml. This server-specific descriptor does the following: Maps JNDI locations for the EJBs as well as other resources and components they reference.

Configures timeouts, pool sizes, and other performance settings. Configures persistence for both stateful session beans and entity beans, in particular, it allows for the mapping of container-managed fields and relationships. Configures finder method queries. Specifies transactional behavior. Configures value-added features, including OR mapping and Active Components for Java (AC4J). Configures role mappings and other security settings. Allows the overriding of environment entries and other elements in ejb-jar.xml. Configures CORBA security settings for EJBs accessed over RMI-IIOP. The document type declaration (DTD) used for the orion-ejb-jar.xml deployment descriptor can be found on Oracle's website at http://xmlns.oracle.com/ias/dtds/orion-ejbjar.dtd. The deployment descriptor should always start with a header like this: The overall structure of the deployment descriptor as defined by this DTD is shown in Figure 111.

Figure 11-1: XML-SPY diagram

Overall Structure The root element has two attributes (used internally by the server) and two subelements: one for EJB deployments (enterprise-beans), and one for security role mapping (assembly-descriptor). The elements are listed in Table 11-1.

Table 11-1: /orion-ejb-jar Elements Parameter

Description

orion-ejb-jar:deploymenttime

Used by server, do not edit.

orion-ejb-jar:deploymentversion

Used by server, do not edit.

enterprise-besans

Configures EJBs declared in ejb-jar.xml.

assembly-descriptor

Resolves security settings declared in ejbjar.xml.

Configuring EJB Deployments There are three types of EJBs that can be deployed: entity beans, session beans, and messagedriven beans. In addition, one or more AC4J deployments, in which each one makes an EJB available to other AC4J objects, can be included. In this section you'll look at the following: The headers for each type of EJB The common elements that can appear in any of the EJB deployments Container-managed persistence elements for CMP entity beans Java Expresso Machine (JEM) elements used to deploy EJBs as AC4J objects

Session Bean Deployment Header For every session bean declared in ejb-jar.xml, you can specify a element in orion-ejb-jar.xml with a JNDI location, environment entries, references to other EJBs, resource references, and other optional performance settings. As an example, consider the following session bean definition in ejb-jar.xml: Manages customers CustomerManager com.apress.ejb.CustomerManagerRemoteHome com.apress.ejb.CustomerManagerRemote com.apress.ejb.CustomerManagerHome com.apress. ejb.CustomerManager com.apress.ejb.CustomerManagerBean Stateless Container

You can map CustomerManager to an actual JNDI location and tweak a few performance

settings in orion-ejb-jar.xml like this: ... Environment entries, resource references, EJB references, and other subelements of sessiondeployment are common across EJB types and are described later in this chapter. The element allows the following attributes listed in Table 11-2. Table 11-2: session-deployment Elements Parameter

Description

Default Value

sessiondeployment: poolcache-timeout

The maximum number of seconds to cache bean instances. When this number is reached, all beans of this type will be flushed from the pool. Specifying "never" or a nonpositive integer will disable timeouts so that instances will never be removed from the pool.

60

sessiondeployment: calltimeout

The maximum number of milliseconds to wait for a resource (other than a database connection) before throwing a RemoteException. If set to 0, timeouts are disabled and it will wait forever.

0

sessiondeployment: copyby-value

Specifies whether all parameters should be cloned and serialized before being passed in to this bean's methods. If false, objects will be passed by reference, which is faster but may cause problems if the parameter is an object and you modify its state.

true

sessiondeployment: location

The JNDI location in which to store this bean's Home.

sessiondeployment: maxinstances

The maximum number of instances to keep cached in the pool.

100

sessiondeployment: mininstances

The minimum number of instances to keep cached in the pool.

0

sessiondeployment: maxtx-retries

The maximum number of times to retry transactions that are rolled back because of system failures. When a transaction involves multiple beans, the container will use the value

3

Table 11-2: session-deployment Elements Parameter

Description

Default Value

specified for the first bean involved in the transaction. sessiondeployment:name

The name of the bean as specified in ejbjar.xml.

sessiondeployment: persistencefilename

Path to the file where session state is stored across server restarts. (Note: the survival of session state across server restarts is a nonportable feature.)

sessiondeployment: timeout

Maximum number of seconds of inactivity before removing a stateful session bean. If zero or negative, stateful session beans are never removed by the container and must be explicitly removed by the application.

sessiondeployment: wrapper

Used by OC4J to store the name of the generated remote wrapper class. This value should not be edited.

sessiondeployment: local-wrapper

Used by OC4J to store the name of the generated local wrapper class. This value should not be edited.

1800

Entity Bean Deployment Header For every entity bean declared in the ejb-jar.xml, you can specify an element in orion-ejb-jar.xml. This is particularly relevant to entity beans that use CMP, since you'll need to map fields and finders to the corresponding database values, as shown in Table 11-3. Table 11-3: entity-deployment Elements Parameter

Description

Default Value

entitydeployment: call-timeout

The maximum number of milliseconds to wait for a resource (other than a database connection) before throwing a RemoteException, or to wait for a SQL query to finish before throwing an SQLException. If set to 0, timeouts are disabled and it will wait forever.

90000 ms

entitydeployment: clusteringschema

Not necessary in this release

entitydeployment:

Specifies whether all parameters should be cloned or serialized

true

Table 11-3: entity-deployment Elements Parameter

Description

copy-by-value

before being passed in to this bean's methods. If false, objects will be passed by reference, which is faster but may cause problems if the parameter is an object and you modify its state.

entitydeployment: exclusive-writeaccess

If true, the container assumes that it's the only process with write access to the database. This can provide performance boosts, but can ensure that data integrity should never be used when other processes might update the database.

false

entitydeployment: doselect-beforeinsert

If true, the container will execute a select before every insert to determine if a record already exists with the same key. If false, it will just attempt the insert, possibly causing a SQLException.

true

entitydeployment: instance-cachetimeout

The maximum number of seconds that instances are assigned to a particular identity (that is, one primary key) before being returned to the unassigned pool. Specifying a value of "never" means that instances will keep their identity until they are garbage collected.

60

entitydeployment: location

The JNDI location in which to store this bean's Home.

entitydeployment: isolation

Sets the database isolation level to serializable, srepeatable_read, committed, uncommitted, or none (only serializable and committed should be used for Oracle databases).

committed

entitydeployment: locking-mode

Sets the concurrency mode, which controls how to resolve resource contention between components. Possible values are as follows:

OPTIMISTIC

PESSIMISTIC. Only one user can use an entity bean at a single time. Others will block until it's available.

Default Value

Table 11-3: entity-deployment Elements Parameter

Description

Default Value

OPTIMISTIC. Multiple users can use the same entity bean, which means that data consistency is managed solely by database isolation modes. READ-ONLY. The entity bean cannot be updated, so multiple users can use it without blocking. entitydeployment: maxinstances

The maximum number of instances to keep cached in the pool.

100

entitydeployment: mininstances

The minimum number of instances to keep cached in the pool.

0

entitydeployment: maxinstances-per-pk

The maximum number of instances to keep cached for a single primary key.

entitydeployment: mininstances-per-pk

The minimum number of instances to keep cached for a single primary key.

entitydeployment: maxtx-retries

The maximum number of times to retry transactions that are rolled back because of system failures. When a transaction involves multiple beans, the container will use the value specified for the first bean involved in the transaction.

3

entitydeployment: disable-wrappercache

If true, bean instances aren't cached, but rather created on demand.

false

entitydeployment:name

The name of the bean as specified in ejb-jar.xml.

entitydeployment:poolcache-timeout

The maximum number of seconds to keep an unassigned entity instance before removing it from the pool. Specifying a value of "never" will disable the timeout.

entitydeployment:valid ity-timeout

For read-only beans, specifies how often to reload data. Useful for cases where data very rarely changes, but needs to be occasionally refreshed. Specifying a

60

Table 11-3: entity-deployment Elements Parameter

Description

Default Value

value of "never" will disable the timeout so that data may never be reloaded. entitydeployment:force -update

If true, the container will call ejbStore() (and write to the database in the case of CMP) after every invocation, even if no data changes are detected. If false, it will track changes and only write when necessary.

entitydeployment:wrapp er

Used by OC4J to store the name of the generated remote wrapper class. This value should not be edited.

entitydeployment: local-wrapper

Used by OC4J to store the name of the generated local wrapper class. This value should not be edited.

entitydeployment: delay-updatesuntil-commit

If true, updates aren't written to the database until the current transaction is committed. If false, every incremental update is passed through to the database.

false

true

CMP Entity Bean Configuration All entity beans share the same header information. However, CMP entity beans use a number of additional attributes in the header, and a number of additional child elements as well. The additional header elements are list in Table 11-4. Table 11-4: entity-deployment Elements Parameter

Description

Default Value

entity-deployment: data-source

The JNDI name of a data source to use to access the database for this entity. The name specified here should match the ejb-location configured for the data source in the datasources.xml file (see Chapter 5).

The value of orionapplication:default -data-source in orionapplication.xml for this application, or if that isn't specified, the same value in config/application. xml

entity-deployment: update-changedfields-only

If true, when an EJB is saved, only the modified fields will be updated. If false, all the EJB fields will be updated no matter what

true

Table 11-4: entity-deployment Elements Parameter

Description

Default Value

was changed. entity-deployment: table

The database table this entity should be saved to.

Generated by the server based on the EJB name, JAR name, and so on

Within the main entity-deployment element, you must specify child elements for the following: Mapping CMP fields to database columns (note that Primary Key fields must be listed separately from the rest of the CMP fields) Specifying queries for finders, for EJB 1.1, or when EJB-QL isn't sufficient to specify the query for EJB 2.0 finders Resolving container-managed relationships to database tables and columns Caution

Many of the elements and attributes described in this section can be used for different things (for example, depending on whether they're mapping a CMP field or a CMR field).

Mapping Primary Key Fields The primary key fields must be listed separately from the rest of the CMP fields, but the format is essentially the same. There's one primkey-mapping element that holds a single cmp-fieldmapping element, which can hold one or more field mappings, using any of the syntaxes described in the following sections. For example, for an Order EJB with a single primary key field called OrderId in the EJB mapping to a column named OrderId in the database, the mapping would look like this: For an OrderLine EJB with a multicolumn primary key, you cannot list all the columns directly under the primkey-mapping element, since it only takes a single child. Instead, you'll use one of the following options to embed multiple CMP field definitions. For example, if the OrderLine primary key consists of OrderId and LineNumber properties in the EJB and OrderId and LineNumber columns in the database, the mapping would look like this:

We recommend that you don't use composite primary keys. A primary key should have no relation to any identifiers used in real world. Using a national insurance number, for example, as a primary key isn't the best idea because it may—under the most obscure circumstances—change. The same principle can be applied to orders and order lines. You may have to change the line number for some reason and doing so will impact your primary key. Instead, use a synthetic primary key, such as OrderLineId, which doesn't relate in any way to order and line number. Mapping Simple CMP Fields All CMP fields are mapped using the cmp-field-mapping element. Simple fields just specify a CMP field name (in the name attribute) and a database column name (in the persistencename attribute) directly in the cmp-field-mapping element. For most cases, no child elements are required. The following attributes listed in Table 11-5 are available on the cmp-fieldmapping element. Table 11-5: cmp-field-mapping Elements Parameter

Description

Default Value

cmp-field-mapping

Holds mapping information for one or more CMP or CMR fields. Simple CMP fields just use attributes, while CMR and more complex arrangements use child elements.

cmp-field-mapping: ejb-reference-home

Generally not used. When mapping to other EJBs, you can use the entityref:home attribute described in the following CMR sections.

cmp-field-mapping: name

Identifies the CMP field or CMR field in question. For CMP fields, this must match the value in the field-name element of the ejb-jar.xml file. For CMR fields, this must match the value in the cmr-field-name element of the ejbjar.xml file.

cmp-field-mapping: persistence-name

The name of the database column this CMP field should map to.

Same as the CMP field name

cmp-field-mapping: persistence-type

The database-specific data type of the column this field maps to. This is only necessary if the application is configured to create tables for CMP

Configured in the XML file for the current DBMS in config/databaseschemas/

Table 11-5: cmp-field-mapping Elements Parameter

Description

Default Value

entity beans (see orionapplication:autocre ate-tables). For example, if the User EJB needs to map the FirstName and LastName CMP fields to FirstName and LastName database columns, you could use two simple mappings like this: However, there are two cases in which the cmp-field-mapping element must contain children. One case is for multicolumn primary keys—as discussed previously, the primkey-mapping element only allows one cmp-field-mapping child, so to map to multiple primary key fields that cmp-field-mapping child must have a fields child or a properties child that can enumerate the primary key fields. The other case in which the cmp-field-mapping element must contain children is when the CMP or CMR field itself is a complex type: an EJB, an array or collection, and so forth. The mappings for these situations are described in the following sections. Explicitly Mapping EJB 1.1-style CMP Fields In cases in which you want to explicitly indicate that a group of CMP fields should be represented by EJB 1.1-style public fields on the bean implementation class, you can use the fields child of the cmp-field-mapping element. For example, if the User EJB needs to map the FirstName and LastName CMP fields to FirstName and LastName database columns, and you wanted to indicate that those CMP fields are represented by Java fields (not EJB 2.0-style properties), you could a fields element like this: Explicitly Mapping EJB 2.0-style CMP Properties In cases in which you want to explicitly indicate that a group of CMP fields should be represented by EJB 2.0-style abstract properties on the bean implementation class, you can use the properties child of the cmp-field-mapping element. For example, if the User EJB needs to map the FirstName and LastName CMP fields to FirstName and LastName database columns, and you wanted to indicate that those CMP fields are represented by Java properties (not EJB 1.1–style fields), you could define the properties element like this:

Mapping Complex Objects as CMP Fields In OC4J, CMP fields aren't restricted to simple data types. For example, the User EJB might include a CMP field whose type is FullName, whereas the FullName object has fields for the first name and the last name as well as a helper method to access the full name as one String. This one CMP field would still map to two separate columns in the database—one for the first name, and one for the last name. You can use the fields or properties elements described earlier to provide mappings for either fields or properties of the complex object. The elements are listed in Table 11-6. Table 11-6: cmp-field-mapping Elements Parameter

Description

properties

Holds one or more cmp-field-mapping entries that represent Java properties on the complex data type.

fields

Holds one or more cmp-field-mapping entries that represent Java fields on the complex data type.

For example, if the FullName looked like this: public class FullName implements Serializable { public String firstName; public String lastName; } then you could declare a CMP field (in this example, named fullName) of type FullName, and use a mapping like this: If the FullName used properties instead, like this: public class FullName implements Serializable { public String getFirstName() { } public String getLastName() { }

public void setLastName(String) { } public void setFirstName(String) { } then you could use a very similar mapping with the properties element, as follows: Mapping CMP Fields to Custom Persistence Managers Though it's not commonly used, you can actually map individual CMP fields to a third-party persistence manager, using the field-persistence-manager element. The elements are shown in Table 11-7. Table 11-7: Persistence Manager Elements in field-persistence-manager Parameter

Description

field-persistence-manager

Specifies an alternate persistence manager to use for the specified field.

field-persistence-manager:class

The class name of the persistence manager.

property

A property used to configure the persistence manager.

property:name

The name of the property.

property:value

The value for the properties.

Note

For a description of the pluggable persistence architecture, see http://otn.oracle.com/tech/java/oc4j/1003/how_to/how-toejb-switchPM.html.

Specifying Queries for Finders and Selectors In EJB 1.1, you must specify the query for each finder in the orion-ejb-jar.xml deployment descriptor. In EJB 2.0, you only need to specify a query for a finder or selector here if you can't construct the correct query in EJB-QL, or you want to override the EJB-QL definition. However, the format is the same in either case. The query syntax uses $fieldName to refer to CMP fields, and $1 to refer to argument one, $2 to refer to the second argument, and so on. Beyond that, the query uses simple SQL syntax, starting with the WHERE clause if the partial attribute is true (the default), or including the entire query if the partial attribute is false and the query is complex (for example, including a join). The elements used to specify a query for a finder are listed in Table 11-8.

Table 11-8: finder-method Elements Parameter

Description

finder-method

The parent element for providing finder queries.

findermethod:partial

If true, the query begins with the WHERE clause (the word WHERE should not be included). If false, the entire query must be provided, making sure to include all necessary fields in the SELECT clause.

finder-method:query

The query to use for this finder.

method

Indicates which finder method the query is for.

ejb-name

The name of the EJB that the method is in. The body of this element holds its value.

method-intf

The interface for the finder method. The body of this element must be Home for finders, and Remote for selectors.

method-name

The body of this element is the name of the method in question.

method-params

A list of parameters to distinguish between overloaded methods. A method with no parameters should include a methodparams element with no children. Otherwise, this element has one methodparam child for each parameter of the method (in order).

method-param

The body of this element is the fully qualified Java name of a single method parameter type.

Default Value

true

If the User EJB has an Integer for a primary key, but still needs to look users up by their username, it might include a finder definition like this: User Home findByUsername java.lang.String

If you also wanted a finder to find people whose boss has a specified first name, you might use a more complex query, as follows: User Home findByBossFirstName java.lang.String Mapping One-to-One Container-Managed Relationships In a one-to-one relationship, each bean maps to a single bean of the other type. This is usually represented by a foreign key on one table, but you need to take special care with the database design with OC4J. For example, if a User has an Address, you might naturally include the UserId as a column on the Addresses table. This is good enough for OC4J to create a one-way relationship, but unfortunately in this case, it's probably the wrong way—an Address can find its User, but a User can't find its Address. In order to map the relationship the other way, the foreign key needs to go on the User table, and if you wanted it to be a bidirectional relationship (in which both beans can see the other), you need to include foreign keys on both tables! Further, in OC4J, CMR fields can't be set before a bean is created, which means that the initial rows will be inserted before the foreign keys are populated, and thus the foreign key columns must be nullable. However, you can get around this requirement if you declare the foreign key column as INITIALLY DEFERRED DEFERRABLE and set the CMR field in the same transaction where you create the bean. Deferred foreign key modifiers instruct the database not to perform data integrity checks to see whether the referenced row exists during the current transaction, but only upon commit. This will allow you to use "proper" foreign keys with NOT NULL constraints. Finally, the foreign key fields should not be part of the primary key of either bean. So, for example, you couldn't make the UserId act as the primary key for the Address table, even though users are unique and there's exactly one address per user. So here's a recap of the database requirements: Each bean that has a CMR field that accesses the referenced bean must declare a foreign key in its table. It's best if each foreign key has only one column. The foreign key columns must be declared nullable, or INITIALLY DEFERRED DEFERRABLE. The foreign key columns should not overlap with the primary key columns of the same bean.

The XML tags used to map a one-to-one relationship are listed in Table 11-9. Table 11-9: cmp-field Elements Parameter

Description

cmp-field-mapping

This element encloses the CMR field definition.

cmp-field-mapping:name

The name of the CMR field, which must match the cmr-field-name tag in the ejb-jar.xml file.

Entity-ref

Indicates that this CMR field maps to a single entity.

Entity-ref:home

Holds the JNDI name where the server can find the entity that this CMR field maps to.

cmp-field-mapping

This element appears again to map the CMR field to a specific foreign key column.

cmp-field-mapping:name

The CMR field name, again.

cmp-field-mapping:persistencename

The name of the foreign key column in the table for this entity bean.

For example, you'll use the User EJB and the Address EJB. You'll assume a bidirectional oneto-one relationship; the Users table has an Address column, and the Addresses table has a User column. Their relationship might look like this in ejb-jar.xml: UserAddress User One User address Address One

Address user
Notice that each bean has a CMR field to access the other. To map this relationship to database columns, you must add entries to orion-ejb-jar.xml for each of the two entity beans, as shown here: Note that the User bean maps the "address" CMR field to the Address foreign-key column, and the Address bean maps the user CMR field to the User foreign-key column. We've used many different foreign key naming schemas, but the one we're most comfortable using is this parent table: Parents with primary key ParentId and a child table Children with primary key ChildId. We named the foreign key in the Children table that references a row in Parents table Parent. This describes the entity the foreign key is referencing and makes all updates much easier because you cannot use aliases in UPDATE statements. Mapping One-to-Many Container-Managed Relationships In a one-to-many relationship, the parent bean maps to a group of child beans, while each child bean maps to only one parent bean. For example, the User bean maps to many PhoneNumbers, but each PhoneNumber is only used by one User. Again, this is typically modelled with a single foreign key in the child table. In this example, the PhoneNumber table would typically have a User field that references Users(UserId). Additionally, the same foreign-key considerations apply to one-to-many relationships, as follows:

It's best if each foreign key has only one column. The foreign key columns must be declared nullable, or INITIALLY DEFERRED DEFERRABLE. The foreign key columns should not overlap with the primary key columns of the same bean. To map a one-to-many relationship to database tables, you need to use different syntax for each bean in the relationship. The child bean uses the same syntax as for one-to-many relationships. The elements are listed in Table 11-10. Table 11-10: cmp-field-mapping Elements and One-to-Many Relationship Parameter

Description

cmp-field-mapping

This element encloses the CMR field definition.

cmp-field-mapping:name

The name of the CMR field, which must match the cmr-field-name tag in the ejb-jar.xml file.

entity-ref

Indicates that this CMR field maps to a single entity.

entity-ref:home

Holds the JNDI name where the server can find the entity that this CMR field maps to.

cmp-field-mapping

This element appears again to map the CMR field to a specific foreign key column.

cmp-field-mapping:name

The CMR field name, again.

cmp-field-mapping:persistencename

The name of the foreign key column in the table for this entity bean.

However, the parent bean definition uses new syntax, as shown in Table 11-11. Table 11-11: cmp-field-mapping Elements for the Parent Bean Parameter

Description

cmp-field-mapping

This element encloses the CMR field definition.

cmp-fieldmapping:name

The name of the CMR field, which must match the cmr-field-name tag in the ejb-jar.xml file.

collection-mapping

Used to hold the persistence settings for the many side of a relationship when the cmr-field-type declared in ejb-jar.xml is java.util.Collection. Otherwise the same as the set-mapping element.

Default Value

Table 11-11: cmp-field-mapping Elements for the Parent Bean Parameter

Description

collectionmapping:table

The name of the mapping table (if a mapping table is used) or the table for the many bean (with the foreign key) if no mapping table is used.

set-mapping

Used to hold the persistence settings for the many side of a relationship when the cmr-field-type declared in ejb-jar.xml is java.util.Set. Otherwise the same as the collection-mapping element.

set-mapping:table

The name of the mapping table (if a mapping table is used) or the table for the many bean (with the foreign key) if no mapping table is used.

primkey-mapping

Defines the foreign key column in the "many" table.

cmp-field-mapping

Appears within the primkey-mapping element.

cmp-fieldmapping:name

Holds the name of the foreign key column in the "many" table.

cmp-field-mapping: persistence-name

Also holds the name of the foreign key column in the "many" table.

value-mapping

Indicates the expected data type of the values in the Collection as well as how to map them to records in the database.

valuemapping:immutable

Whether the value can change once added to the collection (mutable) or will always stay the same (immutable). Immutable values are more efficient for the server.

value-mapping:type

The fully qualified Java class name of the objects stored as values in the collection, which amounts to the Local interface of the "many" bean.

cmp-field-mapping

Appears within the value-mapping element.

entity-ref

Indicates that the values are mapped to EJBs.

entity-ref:home

Holds the JNDI name where the server can find the entity whose interface is listed in value-mapping:type.

Default Value

true for Sets, false for Collection s

Table 11-11: cmp-field-mapping Elements for the Parent Bean Parameter

Description

cmp-field-mapping

Appears within the entity-ref element to provide the primary key of the "many" table.

cmp-fieldmapping:name

Holds the name of the primary key column in the "many" table.

cmp-field-mapping: persistence-name

Also holds the name of the primary key column in the "many" table.

Default Value

For example, you'll use the User EJB and the PhoneNumber EJB. You'll assume a bidirectional one-to-many relationship; the PhoneNumber table has PhoneNumberId as its primary key, and a foreign key User that references Users(UserId). Their relationship might look like this in ejb-jar.xml: UserPhoneNumbers User One User phoneNumbers java.util.Collection PhoneNumber Many PhoneNumber user Notice that each bean has a CMR field to access the other, and the User bean uses a

Collection to access the group of PhoneNumbers for a user. To map this relationship to database columns, you must add entries to orion-ejb-jar.xml for each of the two entity beans. The PhoneNumber bean is the easier "many" bean, while the User bean is the more complex "one" side, as shown here: The PhoneNumber bean maps the user CMR field to the User foreign key field.

The User bean indicates that the primary key in the PhoneNumbers table is the PhoneNumberId column, and the foreign key in the PhoneNumbers table is the User column. Mapping Many-to-Many Container-Managed Relationships In a many-to-many relationship, each bean maps to a group of beans of the other type. For example, the User may have many Roles, and each Role may include many Users. This relationship is always modelled with a third join table (such as UserRoles) in which each row in the join table is nothing but a pair of foreign keys, one to each of the bean tables. The foreign key considerations in the other CMR cases don't apply here because neither bean table needs to include a foreign key. However, it's important to note that the join table cannot have any columns other than the foreign keys.

To map a many-to-many relationship to database tables, you'll use the following syntax for each bean in the relationship, as shown in Table 11-12. Table 11-12: cmp-field-mapping for Many-to-Many Mappings Parameter

Description

cmp-field-mapping

This element encloses the CMR field definition.

cmp-fieldmapping:name

The name of the CMR field, which must match the cmr-field-name tag in the ejb-jar.xml file.

collection-mapping

Used to hold the persistence settings when the cmr-field-type declared in ejbjar.xml is java.util.Collection. Otherwise the same as the set-mapping element.

collectionmapping:table

The name of the mapping table.

set-mapping

Used to hold the persistence settings when the cmr-field-type declared in ejbjar.xml is java.util.Set. Otherwise the same as the collection-mapping element.

set-mapping:table

The name of the mapping table.

primkey-mapping

Maps the foreign key in the join table to the primary key in this table.

cmp-field-mapping

Appears within the primkey-mapping element.

cmp-fieldmapping:name

Holds the name of the foreign key column for this bean in the join table.

cmp-field-mapping: persistence-name

Holds the name of the primary key column that foreign key maps to in the bean table.

value-mapping

Indicates the expected data type of the values in the Collection as well as how to map them to records in the database.

valuemapping:immutable

Whether the value can change once added to the Collection (mutable) or will always stay the same (immutable). Immutable values are more efficient for the server.

value-mapping:type

The fully qualified Java class name of the objects stored as values in the Collection, which amounts to the Local interface of the opposite bean.

Default Value

true for Sets, false for Collectio ns

Table 11-12: cmp-field-mapping for Many-to-Many Mappings Parameter

Description

cmp-field-mapping

Appears within the value-mapping element.

entity-ref

Indicates that the values are mapped to EJBs.

entity-ref:home

Holds the JNDI name where the server can find the entity whose interface is listed in value-mapping:type.

cmp-field-mapping

Appears within the entity-ref element to provide the mappings for the other table.

cmp-fieldmapping:name

Holds the name of the primary key column in the table for the other bean.

cmp-field-mapping: persistence-name

Holds the name of the foreign key column in the join table for the foreign key that maps to the other bean.

Default Value

As an example, you'll use the User EJB and the Role EJB. You'll assume a bidirectional manyto-many relationship; the UserRoles table has a User foreign key that references Users(UserId), and a Role foreign key referencing Roles(RoleId). The primary key in the Users table is named UserId and RoleId for the Roles table. Their relationship might look like this in ejb-jar.xml: UserRole User Many User roles java.util.Collection Role Many Role

users java.util.Collection


Notice that each bean has a CMR field to access the other, and both use a Collection. To map this relationship to database columns, you must add entries to orion-ejb-jar.xml for each of the two entity beans, as follows: When you compare the preceding User mapping to the following Role mapping, you see that each side effectively includes all the information required for the relationship, and the positions in which the different field names appear are opposite.
persistence-name="UserId" />
Mapping Relationships in EJB 1.1 Though EJB 1.1 doesn't include standard features for relationships between entity beans, OC4J provides proprietary methods for mapping relationships to the database. We won't cover those features in detail, since the standard EJB 2.0 CMR features are available, but in short, relationships are mapped more or less the same way as CMR. In addition to individual Entities, Sets, and Collections, these mappings can include Lists, Vectors, and Arrays (using the list-mapping element), and Maps, Hashtables, and java.util.Properties (using the map-mapping element). The new elements used listed in Table 11-13. Table 11-13: list-mapping Elements Parameter

Description

list-mapping

Indicates how to persist a List, Vector, or array, with a primkey-mapping child and a value-mapping child.

map-mapping

Indicates how to persist a Map, Hashtable, or Properties, with a primkey-mapping child, a mapkey-mapping child, and a value-mapping child.

map-key-mapping

Specifies the persistence of the keys of the map.

map-key-mapping:type

The fully qualified Java class name of the key type.

Message-Driven Bean Deployment Header For every message-driven bean (MDB) declared in ejb-jar.xml, you need to specify a element in orion-ejb-jar.xml with the locations of JMS connection factories and destinations. Within this element, you can also declare environment entries, reference other EJBs, reference resources, and configure a few optional performance settings. For example, if the ejb-jar.xml declares the following message-driven bean: Order Confirmation Mailer OrderConfirmationService OrderConfirmationService com.apress.ejb.OrderConfirmationService Container

javax.jms.Topic Durable
Then you need to add something like this to the orion-ejb-jar.xml: ... Table 11-14 lists the message-driven-deployment elements. Table 11-14: message-driven-deployment Elements Parameter

Description

message-drivendeployment

Contains container-specific settings for an individual message-driven bean. In particular, it links the MDB to an actual JMS topic or queue.

message-drivendeployment: cachetimeout

Should not be used for MDBs. (For stateless session beans, this specifies the number of seconds to keep instances in the pool.)

message-drivendeployment: connection-factorylocation

The JNDI location of the JMS connection factory to use. Should be specified in the form: "java:comp/resource" plus the resource-provider name plus the "TopicConnectionFactories" or "QueueConnectionFactories" plus the user-defined name, where the resource-provider name matches the resource provider defined in application.xml.

message-drivendeployment: destinationlocation

The JNDI location of the queue or topic to use. Should be specified in the form "java:comp/resource/" plus the resource-provider name plus the "/Topics/" or "/Queues/" plus the name of the topic or queue.

message-drivendeployment: max-

Should not be used for MDBs—use listener threads instead. (For other types

Default Value

Table 11-14: message-driven-deployment Elements Parameter

Description

instance

Default Value

of beans, this specifies the max number of instances to keep in the pool.)

message-drivendeployment: mininstances

Should not be used for MDBs—use listener threads instead. (For other types of beans, this specifies the minimum number of instances to keep in the pool.)

message-drivendeployment: name

The name of the message-driven bean, as defined in ejb-jar.xml.

message-drivendeployment: subscription-name

For topics, the name of the subscription.

message-drivendeployment: listener-threads

The number of threads created to consume messages concurrently.

1

message-drivendeployment: transaction-timeout

The number of seconds before a container-managed MDB transaction is rolled back automatically.

86400 (1 day)

Resolving EJB References Within ejb-jar.xml, EJBs can declare references to other EJBs using the element. This allows you to look up the referenced EJBs within the component environment (java:comp/env) using a logical name. These logical names need to be mapped to the actual JNDI locations of the EJBs with the element in orion-ejb-jar.xml. For example, if the EJB needed to reference an Invoice bean, you might declare the following in its ejb-jar.xml: ejb/accounting/Invoice Entity com.apress.ejb.accounting.InvoiceHome com.apress.ejb.accounting.InvoiceHome Then, within its orion-ejb-jar.xml, you would map that name to the JNDI location of an actual deployed EJB, as follows: Note

If the logical ejb-ref-name matches the actual JNDI location, you don't need to provide a mapping. Even if it doesn't match, you can avoid this mapping by specifying the actual JNDI location in the
link> element inside in the ejb-jar.xml. The element can be used inside session, entity, and message-driven deployments, and allows for the specification of the following attributes listed in Table 11-15. Table 11-15: ejb-ref-mapping Elements Parameter

Description

ejb-ref-mapping:location

The actual JNDI location where the referenced EJB can be found (as specified in that bean's orion-ejb-jar.xml).

ejb-ref-mapping:name

The logical name given to the referenced bean in the element.

Resolving Resource References Within ejb-jar.xml, EJBs can declare references to JDBC data sources, JavaMail sessions, URLs, and other resources using the element. This element allows the EJB to look up the resource within its component environment (java:comp/env) using a logical name. Unless these logical names match the real JNDI locations exactly, they need to be mapped to actual resource locations using the resource-ref-mapping element in orion-ejbjar.xml. For example, if you assign the logical name jdbc/CustomerDS to a DataSource in ejbjar.xml like this: jdbc/CustomerDS javax.sql.DataSource Application Now you define the following data source in the data-sources.xml configuration file, as follows:

You need to map the resource reference to the actual data source in orion-ejb-jar.xml like this: If you need to look up a resource in a location outside the server, then you can link to an external JNDI context like this:

The element can be used inside session, entity, and messagedriven deployments, and contains the following elements listed in Table 11-16. Table 11-16: resource-ref-mapping Elements Parameter

Description

resource-ref-mapping:name

Matches the logical resource-ref name used in ejb-jar.xml.

resource-ref-mapping:location

The actual JNDI location of the resource to map to.

lookup-context

Allows the optional specification of a particular context to be used to look up a resource (useful when the resource is outside the server).

lookup-context:location

Name where the resource can be found in the specified context.

context-attribute

Specifies JNDI properties to be used for the specified lookup-context. Only the initial context factory property is required.

context-attribute:name

Name of the JNDI property (for example, java.naming.factory.initial).

context-attribute:value

Value of the JNDI property (for example, the class name of the initial context factory).

Resolving Resource env References The ejb-jar.xml descriptor can also define elements for administered objects associated with other resources (for example, JMS destinations). These references are mapped very similarly to the resource references described earlier. For example, if the ejb-jar.xml references a JMS topic like this:

Registration Events jms/regEventsTopic
javax.jms.Topic and you've declared the corresponding topic in the jms.xml like this: Broadcasts user registration events then the orion-ejb-jar.xml should contain something like this: The element can be used inside session, entity, and message-driven deployments, and contains the following elements in Table 11-17. Table 11-17: resource-env-ref-mapping Elements Parameter

Description

resource-env-ref-mapping:name

Matches the logical resource-env-ref name used in ejb-jar.xml.

resource-env-refmapping:location

The actual JNDI location of the resource to map to.

Overriding Environment Entries In some cases, you may want to override an environment entry specified in an ejb-jar.xml (perhaps to avoid altering the standard descriptor of a third-party component). OC4J allows you to do this in orion-ejb-jar.xml with the env-entry-mapping element. For example, if the ejb-jar.xml contains the following environment entry: pastDueDays java.lang.Integer 15 then you can override it to a different value in orion-ejb-jar.xml like this: 30 The elements are listed in Table 11-18.

Table 11-18: env-entry-mapping Elements Parameter

Description

env-entry-mapping

In session-deployment, message-driven deployment, and entity-driven deployment. Body is the new value.

env-entry-mapping:name

Matches the env entry name in ejbjar.xml.

Asynchronous Invocation with AC4J In addition to the standard J2EE message-driven beans described earlier, OC4J allows asynchronous calls to EJBs using the proprietary AC4J architecture. If you want the beans to be accessible through AC4J, you need to configure the names, Databus, and security that will be used to invoke them. In the following example (within orion-ejb-jar.xml) you make the CustomerManager EJB accessible through AC4J as jem/CustMgr, and configure it to use the caller's identity and require that the caller possess the manager role. You also need to specify the data source that contains the AC4J Databus, using the element, as follows: AC4J configuration CustomerManager bean pass through caller identity true Without changing the CustomerManager implementation in any way, you've now allowed clients to invoke its methods asynchronously through AC4J. For example, to issue a credit check, a client might do something like this: Context context = new InitialContext(); String dsName = "java:comp/env/jdbc/DataBusDS"; DataSource ds = (DataSource) context.lookup(dsName); Connection dsCon = ds.getConnection("user", "password"); JEMConnection jemCon = new JemConnection(dsCon);

JEMSession jemSession = new JEMSession(jemCon); JEMHandle custMgr = (JEMHandle) context.lookup("jem/CustMgr"); Object[] params = new Object[] { accountNumber, expiration }; JEMEmitToken call = jemSession.call(custMgr, "processCreditCheck", null, params, null, 0, 0); dsCon.commit(); At this point, the Data Bus takes control and invokes CustomerManager.processCreditCheck() at the next opportunity without forcing the client to wait for CustomerManager to be available. For more information about using AC4J, check the OC4J Enterprise JavaBeans Developer Guide and the AC4J JavaDocs, both available at http://otn.oracle.com. The following elements listed in Table 11-19 may be used inside the element to configure AC4J deployments. Table 11-19: jem-server-extension Elements Parameter

Description

jem-serverextension

Contains AC4J configuration information for JEM deployments.

jem-serverextension: datasource-location

JNDI location of the DataSource (defined in data-sources.xml) that contains the Data Bus.

jem-serverextension: scheduling-threads

Number of OC4J threads that can act in parallel.

jem-deployment

Contains information about how to locate the EJB and invoke its methods securely.

jem-deployment:ejbname

Specifies the name of the EJB as defined in ejb-jar.xml.

jem-deployment:jemname

Specifies the name AC4J clients will use to find this EJB.

called-by

Specifies which callers are allowed to invoke this EJB through AC4J.

caller

Represents a single caller allowed to invoke this EJB through AC4J.

caller:calleridentity

The specific security role the caller must possess.

security-identity

Specifies whether to propagate security identities through AC4J or always use a specified identity.

use-caller-identity

If true, caller's identity will be used.

run-as-specified-

If specified, the identity AC4J will use to

Default Value

1

Table 11-19: jem-server-extension Elements Parameter

Description

identity

invoke this EJB's methods.

role-name

The specific security role to use

Default Value

RMI/IIOP Security Interoperability Most CORBA configuration takes place at the server level. For each individual CORBAaccessible EJB, however, you need to configure security settings in ejb-jar.xml. In particular, you need to specify which transport security features are supported or required, whether or not callers must be authenticated, and how caller identities will be propagated. In the following example, you'll require one transport security element and support all the others. Callers to this EJB will need to authenticate with a username and password against the default realm. Finally, if provided by other servers, delegated identities will be used. required supported supported supported username_password default true supported

The element may be used within session and entity deployments, and includes the following elements listed in Table 11-20.

Table 11-20: transport-config Elements Parameter

Description

transport-config

Contains settings for CSIv2 security properties.

integrity

Specifies whether CSIv2 integrity is required, supported, or not supported (none).

confidentiality

Specifies whether CSIv2 confidentiality is required, supported, or not supported (none).

establish-trustin-target

Specifies whether CSIv2 establish-trust-in-target is required, supported, or not supported (none).

establish-trustin-client

Specifies whether CSIv2 establish-trust-in-client is required, supported, or not supported (none).

as-context

Contains settings for caller authentication

auth-method

Specifies how the caller should authenticate. May be set to username_password or none.

realm

The realm to use for authentication. Must be set to default in current releases.

required

Whether authentication is required to use this EJB.

sas-context

Contains settings for caller identity propagation.

caller-propagation

Specifies whether this EJB accepts propagated identities. If set to required, then servers must pass in an identity. If supported, then it will allow identities to be propagated. If set to none, then identity propagation isn't supported.

Resolving Security Roles If OC4J can map every application role referenced in ejb-jar.xml directly to a physical group with the same name, then the security elements in the following example aren't necessary. However, for portability, backward compatibility, future security, and other considerations, it's usually more appropriate to explicitly map application roles to actual users and groups using a . For example, if the ejb-jar.xml contains the following assembly-descriptor: Allowed to check inventory inventory inventory

ProductManager checkInventory
Now you can map the Inventory role to one or more specific groups and users within orionejb-jar.xml, as follows: The element may contain the following elements listed in Table 1121. Table 11-21: security-role-mapping Elements Parameter

Description

securityrole-mapping

Maps a J2EE application role to one or more users and groups known to the UserManager.

securityrole-mapping: impliesAll

If true, all users are assumed to have this role. If false, individual users and groups should be specified using the and elements.

securityrolemapping:name

The name of the role as specified in ejbjar.xml.

Group

Allows the assignment of a role to a group of users.

group:name

Name of the group that should be given this role.

User

Allows the assignment of a role to an individual user.

user:name defaultmethod-access

The security settings for methods that aren't included in a method-permission in the ejb-jar.xml. This element contains a security-role-mapping with an impliesAll attribute. If impliesAll is set to true, then all users will be assumed to have that role and thus any methods without security settings will be accessible by all. If set to false, then callers must have the default role specified.

Default Value

false

Summary You've learned about EJB-specific configuration details in OC4J. We've pointed out the notable features of OC4J that will allow you to write more effective EJB applications. We've pointed out differences between EJB 1.1 and EJB 2.0 persistence mapping.

Chapter 12: J2EE Connectors Overview J2EE data sources let you easily manage JDBC connections, but what about connections to other enterprise information systems like SAP or Siebel? Using the J2EE Connector Architecture, you can configure resource adapters that allow secure, transactional access to these systems from the J2EE applications. In this chapter, we'll cover the following: How J2EE Connectors work OC4J support for the J2EE Connector Architecture Finding and configuring Connectors Deploying Connectors

What are J2EE Connectors? Years ago, when an application needed to talk to a database, it had to open a socket, connect to the database server, and communicate according to some proprietary protocol. All of this connection code polluted the business logic and limited the database portability. Fortunately, Java Database Connectivity (JDBC) now allows you to use a common API to access a great variety of databases. Under the covers, JDBC drivers (or "resource adapters") translate the JDBC calls into database-specific commands. J2EE Connectors are resource adapters that let you communicate generically with all sorts of external systems, not just databases. Each Connector obeys some application-level client API (like JDBC) and translates those calls to protocols understood by the remote system. The Connector also implements system-level interfaces that let the J2EE container manage connection pooling, transactions, and security. In the end, instead of worrying about how to connect to a remote system, the EJBs and Servlets can just look up a generic connection factory, get a connection, and interact with the system through the client API, as shown in Figure 12-1.

Figure 12-1: J2EE Connector Architecture The following terms are commonly used when talking about J2EE Connectors: Resource adapter. A resource adapter is a common term used to describe a single Connector. Essentially, it's a system-level software driver that the application server or application client can use to connect to an Enterprise Information Systems (EIS) tier. A

resource adapter is usually packaged into a resource adapter archive (RAR) file using the Java archive (JAR) format. Client API. The programming interface that business components use to interact with a Connector. Several Connectors may be implemented that share the same application API. These Connectors allow developers to write portable application code that will work with all of them. System contract. A collection of interfaces defined by the Java Connector Architecture (JCA) specification and implemented by each Connector. The container uses these interfaces to interact with the Connector generically—initializing transactions, obtaining connections, and so on. Enterprise information system (EIS). A common term used to describe an external system (for example, SAP, PeopleSoft, a legacy mainframe).

OC4J Support for Connectors The container plays an important part in the J2EE Connector Architecture by managing connection pools, transactions, security, and more. OC4J supports all of the features required by the JCA specification. However, it doesn't support two-phase commit, local transaction optimization, or connection sharing for J2EE Connectors. A J2EE Connector is much less scalable than a JDBC or message-based interface to your EIS; in some cases, it may even be better to use alternatives outside of the J2EE specification instead of Connectors. In some cases you have no other option because the Connector contains native code, but make sure you examine all the alternatives before assuming that a J2EE Connector is appropriate. Before deploying to OC4J, all Connectors should be packaged in RAR files as described in the JCA specification. In addition to the standard ra.xml descriptor, an optional oc4j-ra.xml descriptor can be placed in the META-INF directory within the RAR to configure OC4J-specific settings or override ra.xml values. The format of oc4j-ra.xml is described later in this chapter. Once configured and packaged, RARs can be deployed to OC4J as either standalone or embedded Connectors. Standalone Connectors are configured in the global Connectors file (usually "connectors/oc4j-connectors.xml", but this can be changed through the "system.xml" configuration file). Connectors are available for use by all deployed applications. Embedded Connectors are packaged inside an enterprise archive (EAR) file and are only made available to the application inside which they're deployed. We'll cover the OC4J descriptor files in more detail later in the chapter.

Finding a Connector Once you've decided to use JCA to connect to an external system from J2EE, the next step is to locate an appropriate Connector. While it's certainly possible to write your own Connector, it's almost always cheaper and easier to use an existing implementation. Fortunately, J2EE is well enough established that EIS vendors now offer prepackaged J2EE Connectors for the most popular products and platforms. Thus, the first place to look is always the vendor who supplied the original system. If that company is unable or unwilling to provide J2EE support, you may able to find a third-party provider that supports your configuration. Many enterprise integration companies offer large catalogs of adapters for everything from SAP and PeopleSoft. Also, most integration server platforms offer dozens of built-in Connectors for the most common types of systems. Finally, it's worth checking out SourceForge.net (see http://sourceforge.net/index.php), and other

free distribution sites. Of course, if you need to talk to a homegrown or highly customized system, it's time to start writing code. First, you'll need to define a client API that your J2EE components will use to interact with this resource. Next, you'll actually implement that API along with a number of system interfaces for connection management, transactions, and security. Finally, you'll package your new resource adapter in a RAR with an ra.xml deployment descriptor. None of these steps are specific to OC4J, and Sun provides a complete walk-through in the online J2EE Connector tutorial.

Writing a Connector Let's take a look at a very simple implementation of a J2EE Connector. It will not actually do anything, but it will serve as a good starting point for writing your own Connectors. Before examining the code, let's take a look at the directory structure of the Connector, as shown in Figure 12-2.

Figure 12-2: Directory structure of the Resource Adapter project The web/src/java and util/src/java directories contain Java source code for the web application and the resource adapter. These Java source codes aren't very important right now, but what is important is the location of descriptor files. The EAR descriptors are located in ear/src/META-INF and the resource adapter descriptors are in rar/src/META-INF. A

resource adapter RAR file must contain a correctly formatted deployment descriptor (/METAINF/ra.xml). We've included the generic ra.xml deployment descriptor as well as the OC4Jspecifc oc4jra.xml descriptor. The descriptors in ear/src/META-INF are pretty standard EAR descriptors; you simply identify modules that make up the application, in this case a web module and a Connector. The oc4jconnectors.xml file is an OC4J-specific configuration file that specifies the JNDI location for the adapter, as shown here: Next, let's examine the ra.xml descriptor, as shown in the following sample, and then we'll move on to describe the crucial points of the actual implementation. Sample Resource Adapter Testing adapter Apress 1.0 ConnectionFactory 1.0 com.apress.oc4j.connectors.SampleManagedConnectionFactory javax.resource.cci.ConnectionFactory com.apress.oc4j.connectors.SampleConnectionFactory javax.resource.cci.Connection

com.apress.oc4j.connectors.SampleConnection NoTransaction false
You need to implement the three classes shown in bold. You'll start with the simplest class: SampleConnection. The purpose of this class is to manage connections to the resource, as shown in the following sample: SampleConnection source package com.apress.oc4j.connectors; import javax.resource.NotSupportedException; import javax.resource.ResourceException; import javax.resource.cci.Connection; import javax.resource.cci.ConnectionMetaData; import javax.resource.cci.Interaction; import javax.resource.cci.LocalTransaction; import javax.resource.cci.ResultSetInfo;

public class SampleConnection implements Connection, LocalTransaction { public Interaction createInteraction() throws ResourceException { SampleInteraction interaction = new SampleInteraction(); interaction.setConnection(this); return interaction; } public LocalTransaction getLocalTransaction() throws ResourceException { return this; } public ConnectionMetaData getMetaData() throws ResourceException { return new SampleConnectionMetadata(); } public ResultSetInfo getResultSetInfo() throws ResourceException { throw new NotSupportedException("Result Set support not

implemented"); } public void close() throws ResourceException { // noop } public void begin() throws ResourceException { // noop } public void commit() throws ResourceException { // noop } public void rollback() throws ResourceException { // noop } } As you can see, we've implemented the Connection and LocalTransaction interfaces. The Connection interface allows the application to use the Connector; the LocalTransaction interface manages transactions. It's important to keep in mind that transactions need to be managed by the Connector; we aren't actually implementing any transaction management code. Next, you have to implement SampleConnectionFactory, which is a class that is responsible for creating SampleConnection objects, as shown in the following sample: SampleConnectionFactory implementation package com.apress.oc4j.connectors; import javax.naming.NamingException; import javax.naming.Reference; import javax.resource.ResourceException; import javax.resource.cci.Connection; import javax.resource.cci.ConnectionFactory; import javax.resource.cci.ConnectionSpec; import javax.resource.cci.RecordFactory; import javax.resource.cci.ResourceAdapterMetaData; import javax.resource.spi.ConnectionManager; import javax.resource.spi.ManagedConnectionFactory;

public class SampleConnectionFactory implements ConnectionFactory { private SampleRecordFactory recordFactory = new SampleRecordFactory(); private Reference reference; private ConnectionManager connectionManager = new SampleDefaultConnectionManager(); private ManagedConnectionFactory managedConnectionFactory; public Connection getConnection() throws ResourceException { return getConnection(new SampleConnectionData()); } public Connection getConnection(ConnectionSpec connectionSpec) throws ResourceException { SampleConnectionData info; if (connectionSpec instanceof SampleConnectionData) { SampleConnectionData sd = (SampleConnectionData)connectionSpec; info = sd; } else { throw new ResourceException("ConnectionSpec object is of type " + connectionSpec.getClass().getName() + " not SampleConnectionData"); } return (Connection)connectionManager.allocateConnection(managedConnectionFacto ry, info); } public RecordFactory getRecordFactory() throws ResourceException { return recordFactory; } public ResourceAdapterMetaData getMetaData() throws ResourceException { return new SampleResourceAdapterMetadata();

} public void setReference(Reference reference) { this.reference = reference; } public Reference getReference() throws NamingException { return reference; } public ConnectionManager getConnectionManager() { return connectionManager; } public void setConnectionManager(ConnectionManager connectionManager) { this.connectionManager = connectionManager; } public ManagedConnectionFactory getManagedConnectionFactory() { return managedConnectionFactory; } public void setManagedConnectionFactory(ManagedConnectionFactory managedConnectionFactory) { this.managedConnectionFactory = managedConnectionFactory; } } Again, we've taken a minimalist approach; you simply return the SampleConnection class without checking the ConnectionSpec data. A full-blown Connector would check that ConnectionSpec is of the correct type and that it contains valid data. The data passed in ConnectionSpec can include login information, data source names, filenames, and so on. Finally, you need to implement ManagedConnectionFactory. This class is used to return the appropriate ConnectionFactory implementation. The Connector is a very simple one, so you'll only return one implementation of ConnectorFactory , as shown here: package com.apress.oc4j.connectors; import java.io.PrintWriter; import java.util.Set; import javax.resource.ResourceException;

import javax.resource.spi.ConnectionManager; import javax.resource.spi.ConnectionRequestInfo; import javax.resource.spi.ManagedConnection; import javax.resource.spi.ManagedConnectionFactory; import javax.security.auth.Subject;

public class SampleManagedConnectionFactory implements ManagedConnectionFactory { private PrintWriter logWriter; public Object createConnectionFactory(ConnectionManager connectionManager) throws ResourceException { return new SampleConnectionFactory(); } public Object createConnectionFactory() throws ResourceException { return new SampleConnectionFactory(); } public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo connectionRequestInfo) throws ResourceException { return new SampleConnectionFactory().getManagedConnectionFactory().createManagedCo nnection (subject, connectionRequestInfo); } public ManagedConnection matchManagedConnections(Set connections, Subject subject, ConnectionRequestInfo connectionRequestInfo) throws ResourceException { return new SampleConnectionFactory().getManagedConnectionFactory().createManagedCo nnection (subject, connectionRequestInfo); } public void setLogWriter(PrintWriter logWriter) throws ResourceException { this.logWriter = logWriter; }

public PrintWriter getLogWriter() throws ResourceException { return logWriter; } } This provides the basic skeleton of a resource adapter. We've implemented Connection and LocalTransaction interfaces in the SampleConnection class; we've implemented Connection–Factory to return appropriate Connection instances, and we've also implemented Managed-ConnectionFactory to return implementations of ConnectionFactory. Next, you need to package the Connector into a RAR file. This is simply a JAR file with a different extension. The build script for the entire application looks like this: The build.xml script As you can see, the build script is very basic and the RAR file is simply a glorified JAR file. The rest of the implementation is quite straightforward, and all is explained in the source code. It's important to keep in mind that this Connector doesn't actually do anything. It's merely a skeleton that you can extend. You can now have a look at how to configure a Connector.

Configuring a Connector Whether you download, buy, or create your own RAR, unless you get it from Oracle, it's unlikely to come preconfigured for OC4J. The next sections will describe how to take this generic RAR and customize it with server-specific settings. Once you have a RAR, you can customize it for OC4J by adding the server-specific oc4jra.xml descriptor to its META-INF directory, as we'll discuss shortly. Usually, nothing else in the archive needs to be changed.

Basic Packaging and Configuration A typical RAR contains Java libraries (JARs), native libraries (for example, something.dll, something.so), and a META-INF directory with one or more descriptors, as shown here: /META-INF/ra.xml /connector-impl.jar /netutils.jar /winnt.dll /solaris.so /linux.so

The code in the resource adapter is usually vendor specific. It doesn't need to contain any platform-specific binaries; it can be purely Java code. Most importantly, it must contain the META-INF/ra.xml descriptor that defines the resource Connector. However, as noted earlier, you need to add the OC4J-specifc Connector descriptor, oc4j-ra.xml, before you can use the Connector in OC4J.

OC4J Connector Descriptor In order for OC4J to load a resource Connector, it must contain the oc4j-ra.xml descriptor in its META-INF directory, alongside the standard ra.xml descriptor. If you obtain a Connector from a vendor other than Oracle, you'll need to add an oc4j-ra.xml descriptor to the METAINF directory. An example oc4j-ra.xml might look as follows: CICS pool jdoe

somepassword
scott scott tiger
Each of these elements is described in the following sections.

Configuring the Name and JNDI Location The root element allows you to specify a name and a global JNDI location, as shown here: ... The global JNDI location specified here can be used directly by the J2EE components, or it can be remapped to local JNDI locations in the descriptors for those components. The Connector name is used when managing the Connector (for example, when deploying or undeploying it from the command line). The JNDI name differs depending on the deployment mode (embedded or standalone). For standalone, the name will be eis/CICS; for the embedded Connector it will be java:comp/env/eis/CICS.

Overriding Values from ra.xml Within , you can use one or more elements to override property values set in the ra.xml descriptor. This is useful if you prefer not to change theresource archive provided by the EIS vendor. The following example overrides the HostName property to be "cicsserver.acme.com":



Configuring Connection Pooling Since connections often tie up system resources and are costly to initialize, it's usually appropriate to configure a connection pool. This lets you improve performance by reusing connections, and can also throttle requests to avoid overloading a resource. A typical connection pool configuration might look like this: The following four connection properties may be specified, as described in Table 12-1. Table 12-1: Setting the Connection Pool Properties Property

Description

Default

maxConnections

Maximum number of connections kept open in this pool. If specified, choose a scheme for handling additional requests.

none (unlimited)

minConnections

Minimum number of connections kept open in this pool. OC4J will attempt to open this many connections during initialization of the pool, though this may not be possible if connection creation depends on other services such as JNDI. If this is the case, OC4J will create as many connections as possible.

0

scheme

How additional requests should be handled when the maximum number of connections is in use. Setting this to dynamic allows additional connections to be created, which are closed immediately after use. Fixed will cause an exception to be thrown if there are no free connections. Fixed_wait will cause the request to block until a connection becomes available (subject to waitTimeout).

none

nonewaitTimeout

Maximum number of seconds to wait for a free connection (if using fixed_wait) before throwing an exception.

none

The optimal values for these properties vary depending on system limitations (memory, processing power) and typical usage patterns. If resource access is infrequent and connections are costly to maintain, it may be best to leave minConnections at 0. More often, you'll want to maximize runtime performance by ensuring that there are enough open connections to handle the typical number of concurrent requests. In either case, it's usually prudent to set an upper limit to avoid overwhelming the resource. Tip

When a software license only allows a certain number of concurrent connections to a resource, you can stay within this limit by setting the maxConnections to the appropriate value and using the fixed_wait scheme.

Configuring Security Typically, you'll be connecting to a resource that requires authentication. Since the credentials used to log in to an application are often different from those used to access a different system, OC4J allows you to choose one of the options described in the following sections.

Signing On Programmatically from Within the Application One of the most straightforward options is to have the application authenticate programmatically. In this case, credentials are often stored in properties files, environment entries, or database tables, and passed inside a ConnectionSpec object (basically a Java bean) defined by the Connector when requesting a connection from a ConnectionFactory. The ConnectionSpec implementation is used by the ConnectionFactory implementation in the Connector's archive to pass details of the connection. The ConnectionSpec object is implemented in the SampleConnectionData class from the Connector you've created in the previous section of the chapter, as shown here: package com.apress.oc4j.connectors; import java.io.Serializable; import javax.resource.cci.ConnectionSpec; import javax.resource.spi.ConnectionRequestInfo; public class SampleConnectionData implements ConnectionSpec, ConnectionRequestInfo, Serializable { private String username; private String password; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; }

public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } } You can then use this ConnectionSpec implementation to pass custom connection data to the ConnectionFactory to obtain an instance of the Connection implemented by the Connector, as follows: Context ctx = new InitialContext(); ConnectionFactory connectionFactory = (ConnectionFactory)ctx.lookup("java:comp/env/SomeConnector"); SampleConnectionData spec = new SampleConnectionData(); spec.setUserName("scott"); spec.setPassword("tiger"); Connection c = connectionFactory.getConnection(connectionSpec);

The code in the previous example translates to a call to ConnectionFactory.getConnection (ConnectionSpec), which can be implemented like this in the Connector: package com.apress.oc4j.connectors; import javax.naming.NamingException; import javax.naming.Reference; import javax.resource.ResourceException; import javax.resource.cci.Connection; import javax.resource.cci.ConnectionFactory; import javax.resource.cci.ConnectionSpec; import javax.resource.cci.RecordFactory; import javax.resource.cci.ResourceAdapterMetaData; import javax.resource.spi.ConnectionManager; import javax.resource.spi.ManagedConnectionFactory; public class SampleConnectionFactory implements ConnectionFactory { public Connection getConnection(ConnectionSpec connectionSpec) throws ResourceException { SampleConnectionData info;

if (connectionSpec instanceof SampleConnectionData) { SampleConnectionData sd = (SampleConnectionData)connectionSpec; info = sd; } else { throw new ResourceException("ConnectionSpec object is of type " + connectionSpec.getClass().getName() + " not SampleConnectionData"); } // normally we would check the username/password here return (Connection)connectionManager.allocateConnection(managedConnectionFacto ry, info); } }

Container-Managed Sign-On with XML Mapping Another option is to provide mappings between application users and resource users and let OC4J manage the rest. These mappings can be either be specified in oc4j-ra.xml or handled dynamically by a Java Authentication and Authorization Service (JAAS) login module. To specify the mappings in oc4j-ra.xml, place a element (with one or more mapping entries) inside the element, as follows: scott tiger jsmith admin cheetah

The entry is optional. If present, it will be used for any user principal that doesn't match another mapping entry. A should be specified for every application user that will not use the default. In the preceding example, requests on behalf of the application user jsmith will authenticate to the resource as admin/cheetah. All other requests will authenticate as scott/tiger. When using XML mapping, any references to the resource within EJB or web deployment descriptors should set res-auth to Container to make sure that the container is managing the user principals and roles.

Container-Managed Sign-On with a JAAS Login Module The JAAS provides standard interfaces for managing authentication. Rather than embed credentials in a descriptor or handle them within the application, you can find or implement a JAAS login module to handle the mapping. This can be very useful in Single Sign-On (SSO) environments. Note

For more information on JAAS, see Chapter 7.

Once you have a working JAAS login module, use the element inside /oc4jconnector-factories/connector-factory/security-config in oc4j-ra.xml to tell it which module to use. In the following example, the container will use the JAAS login module that's registered under the name KerberosLoginModule: KerberosLoginModule

Configuring Transactions There are no Connector-level transaction settings. It's also worth noting that the Connector must be able to support transactions. The Connector may declare that it can support transactions, but not actually implement the internal transaction control methods. The Connector, for example, implements LocalTransaction interface, but doesn't actually perform any transaction processing—the transaction control methods are implemented only as stubs.

Configuring Logging Logging for Connectors is disabled by default. To enable it, include the element in /oc4j-connector-factories/connector-factory with a valid file path such as this: If the directory or the log file itself exists and is writable, OC4J will begin logging this Connector's activity.

Deploying a Connector Once you've configured the Connector with oc4j-ra.xml, you can choose to deploy it as a standalone Connector at the container level, or as an embedded Connector within the application. In either case, an oc4j-connectors.xml file will end up containing a reference to the Connector along with its native library path and security permissions. Typically, this will look something like this:

grant {permission java.lang.RuntimePermission "LoadLibrary.*"};
In this case, we've configured a Connector named "embedded", which is packaged in the "embedded_ra.rar" file, which contains a lib directory with native libraries (*.dll, *.so, and so on). We've also granted it permission to load libraries. Note

The ra.xml descriptor should list all of the security permissions required by a Connector. When manually adding a connector to oc4j-connectors.xml, you must make an entry that specifically grants each permission by setting enabled to true.

The following sections show which oc4j-connectors file and deployment method to use for standalone vs. embedded Connectors.

Deploying Standalone Connectors During development, you can deploy standalone Connectors simply by adding the appropriate entry to the existing global oc4j-connectors.xml file. This file is located by default in orahome/j2ee//connectors; however, the location can be changed in server.xml. The next time the server is started, the Connector should be deployed. Many times, it's more practical to deploy or undeploy a Connector using deployment tools such as admin.jar. In this case, instead of working with XML, you simply pass in the appropriate values as parameters and let the server update oc4j-connectors.xml. In the following example, the server will deploy the Connector found in standalone_ra.rar under the name standalone, and it will expect native libraries to be contained in a lib directory inside that RAR, and finally, it will copy and grant all permissions contained in the ra.xml descriptor, as shown here: java -jar admin.jar ormi://localhost admin welcome -deployconnector -file standalone_ra.rar -name embedded -nativeLibPath lib grantAllPermissions

Deploying Embedded Connectors Embedded Connectors are deployed inside an enterprise application, as defined in the J2EE specification. To configure and package an embedded Connector, do the following: 1.

Place the RAR inside the application EAR.

2.

Update the generic application.xml descriptor to reference it.

3.

Place an oc4j-connectors.xml file inside the EAR (see previous examples).

4.

Update the OC4J-specific orion-application.xml descriptor to point to it.

Let's take a look at how to build an EAR archive with an embedded Connector using Ant. You'll start with a directory structure of the project. You'll create a simple web application as well as a Connector, and package the WAR and RAR file into an EAR file. The source for the Connector is in util/src/java; the source for the web application is in web/src. You also need to include the META-INF directories for the EAR and RAR archives. The directory structure of the EAR archive with an embedded Connector should be this: /embedded_ra.rar META-INF/ra.xml META-INF/oc4j-ra.xml META-INF/application.xml sample.war WEB-INF

To build an EAR file, you'll create a build script that will compile all source files and package them into appropriate WAR, RAR and EAR files, as shown in Figure 12-3.

Figure 12-3: Directory structure for an EAR application with an embedded Connector Let's review this directory structure: dist will contain the EAR archive; rar/dist will contain the RAR archive; rar/src/META-INF contains Connector descriptors (oc4j-ra.xml and ra.xml); util/src/java contains Java source codes for the Connector; web/src contains source codes for the web application, and finally ear/src/META-INF contains descriptors for the EAR archive. When deploying embedded Connector, you need to modify ear/src/METAINF/ application.xml descriptor to include a reference to the embedded Connector, as follows: Chapter 12 sample application Chapter 12 sample application's description

sample.war /sample
embedded_ra.rar
Once you have EAR and RAR descriptor files and Java source files, you can create an Ant build script to build the entire application, as shown here: The build.xml script





Let's take a look at what you've achieved. You've compiled Java sources that make up the Connector and a web application. You packaged the compiled class files, together with the appropriate descriptor files, into RAR and WAR archives, and then you packaged these archives into an EAR archive that you can deploy as a standard J2EE application in OC4J.

Summary J2EE Connectors are an important part of the J2EE developer's toolkit. They let you connect to non-J2EE systems with the same manageability and ease of use that you've grown to love in JDBC. Furthermore, Connectors make it easy to take advantage of existing resource adapters instead of writing your own integration code. However, you should remember that using Connectors will most likely make your application more difficult to deploy and manage. The last point to make is that if the Connector uses a native library, you cannot move your application to a different platform. OC4J provides a solid implementation of the JCA specification, thereby allowing you to quickly customize, deploy, and use any standard J2EE Connector.

Chapter 13: Configuring Web Services Overview In Chapter 11, we talked about application clients that call EJBs directly over RMI. Though these are great behind the firewall, they're not as useful when you need to support hundreds of custom clients or integrate with remote partners running non-Java systems. Fortunately, the software industry has defined standard web services protocols that let you expose your applications to the world through XML messages passed over HTTP. Configuring a web service in OC4J is as simple as adding a few lines to a web-application descriptor. In this chapter, we'll cover the following: Building and deploying both stateless and stateful web services Configuring and deploying EJB-based web services Creating web-service clients using Java and Microsoft .NET

Choosing a Web-Service Implementation Type Every web service needs to be backed by an implementation class with some number of public business methods. Depending on the type of service, you can choose one of the following implementation types: Stateless Java class. This is just a "plain old" Java class. By default, all public methods will be exposed through the web service, but you can narrow that by pointing to an interface with only the appropriate subset of methods. Every time a request is received for the web service, OC4J will create or reuse an object of this class. Stateful Java class. This option also uses a normal Java class, but ties it to a user's HTTP session so that the same instance is used across multiple requests. This lets you save state in instance variables between calls. Session timeouts can be configured as described in Chapter 10. Stateless session bean. This option wraps a stateless session EJB, exposing all of the methods found in its remote interface. It can be very useful when the functionality has already been implemented in an EJB, or when it needs to use EJB services. PL/SQL functions can also be exposed as web services, but the implementation code isn't deployed through J2EE. For more information about PL/SQL web services, visit the Oracle Technology Network (OTN) website.

Creating the Echo Web Service Creating web services with Oracle 10g AS is remarkably simple. In fact you'll find that building a web service is very much a case of implementing your logic and letting Oracle 10g AS worry about SOAP and all the other web-service plumbing. The web-service implementation class itself is very straightforward. It's just a normal Java class or session EJB with normal Java methods. Of course, since all communication will be traveling over SOAP and will be processed by JAX-RPC, you need to stick to parameter and return types allowed by those protocols. Essentially, you can use any of the primitive types along with their corresponding wrapper classes. On top of this you can use java.util.Date and java.util.Map, plus some of the XML classes. In addition you're able to use JavaBeans and single-dimension arrays of the types mentioned here. When using JavaBeans you must ensure that the properties of the class are of the types described here. For a fuller list of the appropriate types, check out the documentation at http://download-

uk.oracle.com/ocs/cd/B10464_02/web.904/b10447/javaservices.htm#g1034081. In this section we'll demonstrate how to build two of the three kinds of web services: stateless and stateful. The web service you're going to implement is a simple echo service where the parameter passed to the service is echoed back to the client. In the stateful example you'll append a counter to the end of the message to see the state management in action.

Building the Web-Service Interface To start with you need to build an interface for your web service. Oracle 10g AS uses the methods defined in the interface as the guide for which methods to expose as operations of your service. You can skip this stage and have Oracle 10g AS generate the service directly from your implementation class, which will result in all public methods of the implementation class being exposed as service operations. Although not obligatory, in our experience it's always a better to use an interface to explicitly define the operations of your service, because it makes it simpler to modify the implementation class or even to change the class altogether. For the echo web service you just need to define a basic interface, as shown here: package com.apress.oracle10g.webservices; public interface EchoWebService { public String echo(String message); } As you can see, the interface for the echo service defined a single operation, echo, which accepts a single String parameter and returns a String value. Now let's move on to the stateless implementation.

Building the Stateless Implementation The next step toward building your web service is to create the implementation of the stateless service. You won't be surprised to know that the implementation is trivial, as shown here: package com.apress.oracle10g.webservices; public class EchoWebServiceStatelessImpl implements EchoWebService { public String echo(String message) { return message; } } Not much to it! So far you've done nothing that's specifically related to a web service. I could use this class just as well in a web application, a Swing application and a command-line application. You're free to use almost any class as a web service, provided the method arguments and return types meet the type requirements stated earlier.

Building the Stateful Implementation The final block of Java code required for the web service is the implementation of the stateful service, as shown here. Again this is very simple. package com.apress.oracle10g.webservices; public class EchoWebServiceStatefulImpl implements EchoWebService { private int count = 0; public String echo(String message) { return message + count++; } } As you can see, the only difference is that this class has some state, which is reflected in the value returned from the echo() method. As far as implementation of the actual service logic goes—that is it. Again, nothing that you've created is specifically related to a web service, which is good because it means that you could use these classes elsewhere if you desired.

Configuring and Deploying the Web Service Technically, there are two ways you can configure and deploy the web service. The first involves creating and configuring a web application for the web service, using the Oracle web-service Servlets to expose your classes as web services. The drawback of this approach is that the exact details of how a web service is actually configured and deployed are likely to change in the future, and thus you'll need to change your code. Also you'll find this method requires many different steps and is quite error prone. The second, and better, solution is to use the WebServices Assembler (WSA) tool, which takes a generically defined configuration file, creates a correctly configured web application for your services, and packages it up in an EAR file. If the details of how Oracle implements web services in the future change, then you simply run the newer version of WSA using your application's configuration file to create an up-to-date deployment package. You'll also find that the WSA configuration file is simple to understand and requires less work than creating the web application manually. The configuration file for the echo web service, as shown here, isn't particularly complex, but it does introduce some tags you haven't seen before so we'll explain it piece by piece. Echo Web Service Oracle 10g Web Service Example ./echows.ear /ws

./tmp The configuration file starts with the tag and directly under that are tags that control the overall behavior of the WSA: The tag specifies the full path, including the filename, of the EAR file that the WSA will create. The tag specifies the context path for the web application. All web services defined will be accessible under this path. The As you can see, the configuration for both services is very similar. In fact, you'll find that both and share mostly the same set of configuration parameters, with stateful services having a few additional parameters. We won't

cover all of the remaining configuration options here as they're covered in greater detail in the documentation. However, we do want to discuss two parameters that you can use to control the behavior of stateful services: and . Using the tag, you can specify how long (in seconds) that the client state should be kept active. By default this option is set to 60 seconds, but you may wish to increase or decrease this as appropriate. The tag allows you to specify where state is kept. By default is set to a value of session—the state information is user specific, and stored using the HTTP session capabilities of the Servlet container. Setting to a value of application will mean that state is stored globally, thereby making the same state available to all clients.

Using Stateless Session Beans Many times you'll just want to expose functionality that has already been implemented in a stateless session EJB. In this case, you just implement the EJB as usual, and make sure that all of the methods you want to expose are included in the remote interface. Tip

If the remote interface has more methods than you want to make available, then just create a second, more limited one and deploy the EJB a second time with the same home and implementation classes.

We won't build an EJB example here because there are plenty of EJB examples in Chapter 11. There are no special requirements for EJBs used in web services other than that they should be stateless session beans. Deploying an EJB-based web service requires you to add a tag to your WSA configuration file, as follows: /HelloService HelloService

You should also ensure that the
-->

principals.xml Description: Stores user and group configuration for the default UserManager. DTD link: http://xmlns.oracle.com/ias/dtds/principals-9_04.dtd Sample: A sample principals.xml file is provided. users guests administrators no description The default user The default guest/anonyomous user

The default administrator Password for database user Scott Password for database user Scott Password for database user Scott


rmi.xml Description: Contains RMI, port, and clustering settings. DTD link: http://xmlns.oracle.com/ias/dtds/rmi-server-9_04.dtd Sample: A sample rmi.xml file is provided.



server.xml Description: Root configuration file, which contains server settings, references to other configuration files, and deployed applications. DTD link: http://xmlns.oracle.com/ias/dtds/application-server-9_04.dtd Sample: A sample server.xml file is provided.



Appendix B: Deployment Descriptors and Document Type Declaration In this appendix we'll identify the deployment descriptors for the sample Petstore application and the corresponding document type declaration (DTD). The Petstore application is a demonstration program that's available for testing. It and other sample programs are available from http://otn.oracle.com/sample_code/tech/java/oc4j/index.html.

Deployment Descriptor Files In this section we'll identify key deployment descriptor files, their location, and describe them.

Location Located in the OC4J $ORACLE_HOME/application-deployments/application_name directory and in subdirectories beneath it.

Files and Descriptions In the following sections we'll list each deployment descriptor file, provide a description and DTD link, and show you a sample file.

orion-application.xml Description: Root application configuration file containing application configuration settings and references to application component files (EJB and WAR). DTD link: http://xmlns.oracle.com/ias/dtds/orion-application-9_04.dtd Sample: A sample orion-application.xml file is provided.



jazn-data.xml Description: Stores JAAS security data when using the XML provider type. DTD link: http://xmlns.oracle.com/ias/dtds/jazn-data.dtd Sample: A sample jazn-data.xml file is provided.

jazn.com


principals.xml Description: Stores user and group configuration for the application. DTD link: http://xmlns.oracle.com/ias/dtds/principals-9_04.dtd Sample: A sample principals.xml file is provided.



orion-web.xml Description: Contains application settings for web application component. DTD link: http://xmlns.oracle.com/ias/dtds/orion-web-9_04.dtd Sample: A sample orion-web.xml file is provided.

orion-ejb-jar.xml Description: Contains EJB settings within the deployed Petstore mailerEjb.jar file. There is one of these files for each deployed EJB JAR file. DTD link: http://xmlns.oracle.com/ias/dtds/orion-ejb-jar-9_04.dtd Sample: A sample orion-ejb-jar.xml file is provided.



web.xml Description: Located in $ORACLE_HOME/applications/application_name/application_name/WEB-INF. Contains configuration settings for a web application. DTD link: http://java.sun.com/j2ee/dtds/web-app_2.2.dtd Sample: A sample web.xml file is provided. WebTier Web Tier DD for the PetStore application

webTierEntryPoint centralServlet no description com.sun.j2ee.blueprints.petstore.control.web.MainServlet webTierEntryPoint /control/* populateServlet Populate Servlet no description com.sun.j2ee.blueprints.tools.populate.web.PopulateServlet populateServlet /populate 54 index.html jdbc/EstoreDataSource javax.sql.DataSource Container

ejb/catalog/CatalogDAOClass java.lang.String com.sun.j2ee.blueprints.shoppingcart.catalog.dao.CatalogDAOImpl ejb/profilemgr/ProfileMgrDAOClass java.lang.String com.sun.j2ee.blueprints.personalization.profilemgr.dao.ProfileMgr DAOImpl server/ServerType Oracle9iAS (1.0.2.2) Containers for J2EE java.lang.String ejb/catalog/Catalog Session com.sun.j2ee.blueprints.shoppingcart.catalog.ejb.CatalogHome com.sun.j2ee.blueprints.shoppingcart.catalog.ejb.Catalog ejb/cart/Cart Session com.sun.j2ee.blueprints.shoppingcart.cart.ejb.ShoppingCartHome com.sun.j2ee.blueprints.shoppingcart.cart.ejb.ShoppingCart

ejb/customer/Customer Session com.sun.j2ee.blueprints.customer.customer.ejb.CustomerHome com.sun.j2ee.blueprints.customer.customer.ejb.Customer ejb/profilemgr/ProfileMgr Entity com.sun.j2ee.blueprints.personalization.profilemgr.ejb.ProfileMgr Home com.sun.j2ee.blueprints.personalization.profilemgr.ejb.ProfileM gr ejb/scc/Scc Session com.sun.j2ee.blueprints.petstore.control.ejb.ShoppingClientContro llerHome com.sun.j2ee.blueprints.petstore.control.ejb.ShoppingClientCont roller ejb/inventory/Inventory Entity com.sun.j2ee.blueprints.inventory.ejb.InventoryHome com.sun.j2ee.blueprints.inventory.ejb.Inventory


Appendix C: Command-Line Utility Usage Overview In this appendix we'll identify the syntax and common usage for the following key utilities: opmnctl. Controls 10g AS Oracle Process and Management Notification (OPMN). dcmctl. Controls 10g AS Distributed Configuration Management (DCM). emctl. Controls 10g AS Application Server Control (ASC) utility. admin.jar. Used to manage OC4J application deployments and starts and stops the server.

opmnctl Usage In this section we'll cover the purpose, location, common usage, and syntax for the opmnctl utility.

Purpose OPMN system is a background process that manages all the individual components for a given 10g AS instance. Each of these interrelated processes is managed by OPMN. If a process dies, OPMN will attempt to restart it. It continually polls the processes that it expects to be up and restarts them if they die or become unreachable. Though OPMN is a background process, it has a command-line interface that can be used to stop or start all the processes for a given installation. The opmnctl utility is a handy way to start or stop the software without having to use the web GUI ASC utility.

Location Located in the 10g AS $ORACLE_HOME/opmn/bin directory.

Common Usages Common usages for opmnctl are shown in the following sections. Start up all processes $ opmnctl startall opmnctl: starting opmn and all managed processes...

Shut down all processes $ opmnctl stopall opmnctl: stopping opmn and all managed processes... Start and stop individual processes (OHS, for example) $ opmnctl stopproc ias-component=HTTP_Server opmnctl: stopping opmn managed processes... $ opmnctl startproc ias-component=HTTP_Server

opmnctl: starting opmn managed processes... Restart individual processes (OHS or OC4J, for example) $ opmnctl restartproc ias-component=HTTP_Server opmnctl: restarting opmn managed processes... $ opmnctl restartproc ias-component=OC4J process-type=home opmnctl: restarting opmn managed processes... Check status $ opmnctl status Processes in Instance: 904mt1.mike.wessler.name -------------------+--------------------+-------+--------ias-component

| process-type

|

pid | status

-------------------+--------------------+-------+--------OC4J

| home

| 30930 | Alive

HTTP_Server

| HTTP_Server

| 31207 | Alive

dcm-daemon

| dcm-daemon

| 30611 | Alive

LogLoader

| logloaderd

|

N/A | Down

$

Syntax To get a list of available arguments, issue opmnctl -help, as follows: $ opmnctl -help usage: /u01/app/oracle/product/9.0.4inf1/OraHome1/opmn/bin/opmnctl [verbose] [] [] verbose: print detailed execution message if available Permitted // combinations are: scope

command

options

-------

---------

---------

start

- Start opmn

startall

- Start opmn & all managed

stopall

- Stop opmn & all managed

shutdown

- Shutdown opmn & all managed

processes processes processes [] startproc

[= ..] - Start opmn managed processes

[] restartproc [= ..] - Restart opmn managed processes [] stopproc

[= ..] - Stop opmn managed processes

[] reload opmn.xml [] status

- Trigger opmn to reread []

- Get managed process status

ping

[]

- Ping local opmn

validate

[]

- Validate the given xml file

help usage description

- Print brief usage description []

- Print detailed usage

$

dcmctl Usage In this section we'll cover the purpose, location, common usage, and syntax for the dcmctl utility.

Purpose DCM works in conjunction with OPMN and has the primary responsibility of synchronization of the instance components (for example, OC4J and OHS) with the repository. Though OPMN works internally within the instance, DCM communicates instance updates externally to other instances and the infrastructure. This is especially important when the mid-tier instance is part of a farm (attached to an infrastructure) or part of a cluster. DCM makes sure that the configuration files on the file system are in sync with the repository, and any updates are propagated accordingly. DCM is also used to deploy J2EE applications to the embedded OC4J instances within 10g AS. The dcmctl utility is useful for several tasks such as the following: Checking the status of the application server instance. Starting and stopping individual components within the instance. Synchronizing configuration files with the repository. Making backups of the instance configuration. Deploying applications to OC4J embedded 10g AS instances. Redeploying applications to OC4J embedded 10g AS instances. Undeploying applications from OC4J embedded 10g AS instances.

Location Located in the 10g AS $ORACLE_HOME/dcm/bin directory.

Common Usages Common usages for dcmctl are shown in the following sections.

Check status $ dcmctl getstate Current State for Instance:904mt1.mike.wessler.name Component

Type

Up Status

In Sync Status

======================================================================= == 1

home

OC4J

Up

True

2

HTTP_Server

HTTP_Server

Up

True

$ Start an individual process (OHS, for example) $ dcmctl start -co HTTP_Server Current State for Instance:904mt1.mike.wessler.name Component

Type

Up Status

In Sync Status

======================================================================= ===== 1

HTTP_Server

HTTP_Server

Up

True

$ Stop an individual process (OHS, for example) $ dcmctl stop -co HTTP_Server Current State for Instance:904mt1.mike.wessler.name Component

Type

Up Status

In Sync Status

======================================================================= ===== 1

HTTP_Server

HTTP_Server

Down

True

$

Restart an individual process (OHS, for example) $ dcmctl restart -co HTTP_Server Current State for Instance:904mt1.mike.wessler.name Component

Type

Up Status

In Sync Status

======================================================================= ===== 1

HTTP_Server

HTTP_Server

Up

True

$ Verify autoarchiving $ dcmctl set Verbose: true Sort: false Warning: true Debug: true Default Timeout: 120 Auto Archive Count : 15 $ Create an archive $ dcmctl exportarchive -arch 904mt1bk-02012004_1 –f /home/oracle/archives/904mt1bk-02012004_1 $ ls -altr /home/oracle/archives/904mt1bk-02012004_1 -rw-r-----

1 oracle

dba

370770 Feb

1 11:53

/home/oracle/archives/904mt1bk-02012004_1 $ Import an archive from a specific file backup $ dcmctl importarchive -arch 904mt1restore-02012004_1 -f /home/oracle/archives/ 904mt1bk-02012004_1 Import an archive from the local repository $ dcmctl applyarchiveto -arch 904mt1bk-02012004_1 Deploying a J2EE application (ojspdemos) to an embedded 10g AS OC4J instance (webdev, for example) $ dcmctl deployapplication -file ./ojspdemos.ear -co webdev – application ojspdemos

Redeploying a J2EE application (ojspdemos) to an embedded 10g AS OC4J instance (webdev, for example) $ dcmctl redeployapplication -file ./ojspdemos.ear -co webdev application ojspdemos Undeploying a J2EE application (ojspdemos) from an embedded 10g AS OC4J instance (webdev, for example) $ dcmctl undeployapplication -co webdev -application ojspdemos

Syntax To get a list of available arguments, issue dcmctl help, as follows:

$ dcmctl help DCMCTL Command Help !! addopmnlink applyarchiveto applyclusterto applyinstanceto configrepositoryssl createarchive createcluster createcomponent deployapplication destroyinstance echo exit exportarchive exportrepository getcomponenttype geterror getopmnport getrepositoryid getreturnstatus getstate help importarchive importrepository isclusterable iscompatible joincluster joinfarm leavecluster leavefarm listapplications listarchives listclusters listcomponents listcomponenttypes listinstances listopmnlinks quit

redeployapplication removearchive removecluster removecomponent removeopmnlink repositoryrelocated resetdcmcacheport resetfiletransaction resethostinformation restart restoreinstance resyncinstance saveinstance set setloglevel shell shutdown start stop undeployapplication updateconfig validateearfile whichcluster whichfarm whichinstance $ To get usage for a particular command, issue dcmctl help argument_name, as follows: $ dcmctl help restart restart Restarts processes. Type Process Management Syntax restart [[-cl cluster_name] | [-i instance_name] | [-co

component_name] | [-ct component_type]] | [-admin] Description Restarts running processes in the specified scope. This command does not restart OPMN or the DCM daemon, it leaves them running. Only the processes that were running when the command was issued are restarted. If the -admin option is used, then the DCM daemon is restarted. Example To restart the local instance: restart To restart a remote instance: restart -i myInstance To restart a component across a cluster: restart -cl myCluster -co myComponent $

emctl Usage In this section we'll cover the purpose, location, common usage, and syntax for the emctlm utility.

Purpose ASC is the GUI 10g AS administration utility. It can be used to control all components within a 10g AS instance and can do everything done by the opmnctl and dcmctl tools. The key difference is that ASC is a web-based graphical utility. By default, the URL for the ASC tool is http://hostname.domain:1810. The username is ias_admin and the password is whatever was selected at product installation time (unless it was changed post installation). The default port (1810) and the HTTP Protocol can be changed (to HTTPS). Prior to accessing the ASC URL, you must first start the utility by emctl. Common usages are to start, stop, and check the status of ASC.

Location Located in the 10g AS $ORACLE_HOME/bin directory.

Common Usages Common usages for emctl are shown in the following sections. Start Application Server Control $ emctl start iasconsole TZ set to US/East-Indiana Oracle Enterprise Manager 10g Application Server Control 9.0.4.0.0 Copyright (c) 2002, 2003 Oracle Corporation.

All rights reserved.

Starting Oracle 10g Application Server Control ...... started. $ Stop Application Server Control $ emctl stop iasconsole TZ set to US/East-Indiana Oracle Enterprise Manager 10g Application Server Control 9.0.4.0.0 Copyright (c) 2002, 2003 Oracle Corporation.

All rights reserved.

Stopping Oracle 10g Application Server Control ... ... Stopped. $ Check status of Application Server Control $ emctl status iasconsole TZ set to US/East-Indiana Oracle Enterprise Manager 10g Application Server Control 9.0.4.0.0 Copyright (c) 2002, 2003 Oracle Corporation. All rights reserved. Oracle 10g Application Server Control is running. $ Change start Application Server Control password $ emctl set password tigerpassword newpassword1 TZ set to US/East-Indiana Oracle Enterprise Manager 10g Application Server Control 9.0.4.0.0 Copyright (c) 2002, 2003 Oracle Corporation. All rights reserved. $

Syntax To get a list of available arguments, issue emctl -help, as follows: $ emctl -help

TZ set to US/East-Indiana Oracle Enterprise Manager 10g Application Server Control 9.0.4.0.0 Copyright (c) 2002, 2003 Oracle Corporation. All rights reserved. Invalid arguments Unknown command option -help Usage:: Oracle Enterprise Manager 10g Application Server Control commands: emctl start| stop| status| startifdown iasconsole emctl set password emctl secure em emctl config agent credentials [[:]] $

admin.jar Usage In this section we'll cover the purpose, location, common usage, and syntax for the admin.jar utility.

Purpose Used to manage J2EE application deployments to OC4J Standalone Edition. It can be used to deploy, bind, or undeploy applications. It is also used to stop and start the OC4J server.

Location Located in the OC4J standalone $ORACLE_HOME/j2ee/home directory.

Common Usages Common usages for admin.jar are shown in the following sections. Application deployment $ java -jar admin.jar ormi://192.168.1.11:11888 admin tigerpassword deploy -file petstore.ear -deploymentName petstore Binding application to URI $ java -jar admin.jar ormi://192.168.1.11:11888 admin tigerpassword -bindWebApp petstore petstore http-web-site /petstore

Undeployment $ java -jar admin.jar ormi://192.168.1.11:11888 admin tigerpassword -undeploy petstore Starting server

$ java -jar oc4j.jar -config $ORACLE_HOME/j2ee/home/config/server.xml -verbosity 10 -err $ORACLE_HOME/j2ee/home/log/err.log Stopping server $ java -jar admin.jar ormi://mike.wessler.name:11888 admin tigerpassword -shutdown

Syntax To get a list of available arguments, issue java -jar admin.jar help, as follows: $ java -jar admin.jar -help Usage: java -jar admin.jar [-help] - print out this usage java -jar admin.jar ormi://host.domain.com<:port> username password [command] Commands are: -shutdown [force|ordinary] [reason] - shuts the entire server down -restart [reason] - restarts the entire server -deploy [subswitches] - (re)deploys an application. Sub-switches are: -file [filename] - Enterprise Archive to deploy -deploymentName [name] - Name of the application deployment -targetPath [path] - The path on the remote OS to place the archive at. If not specified the applications directory is used -parent [name] - Specifying parent application of this application, the default is the global ('default') application -deploymentDirectory [path] - Root of the deployment configurations, "[NONE]" to place them inside the .ear -cluster - Signals that the deployment should be propagated to other live cluster nodes if part of a cluster -iiopClientJar - the path on the local OS to place the jar file containing the application client stubs -undeploy [application name] - remove a previously deployed application -site [subswitches] - configures a site. Sub-switches are: -add - adds a site -host [host] - host/IP of this site -port [port] - port of this site -display-name [display-name] - display name of this site -virtual-hosts [virtual-hosts] - virtual hosts of this site -secure [secure] - true if this site is secure; otherwise false

-factory [factory] - name of SSLServerSocketFactory implementation if not using JSSE -keystore [keystore] - the relative/absolute path to a keystore used by this site -storepass [storepass] - keystore password -provider

[provider] - the provider used if not using JSSE

-needs-client-auth [needs-client-auth] - true if needs client auth; otherwise false -remove - removes a site -host [host] - host/IP of the site to be removed -port [port] - port of the site to be removed -test - tests a site -host [host] - host/IP of the site to be tested -port [port] - port of the site to be tested -list - lists all sites -update - updates a site -oldHost [host] - old host/IP of this site -oldPort [port] - old port of this site -newHost [host] - new host/IP of this site -newPort [port] - new port of this site -display-name [display-name] - display name of this site -virtual-hosts [virtual-hosts] - virtual hosts of this site -secure [secure] - true if this site is secure; otherwise false -factory [factory] - name of SSLServerSocketFactory implementation if not using JSSE -keystore [keystore] - the relative/absolute path to a keystore used by this site -storepass [storepass] - keystore password -provider [provider] - the provider used if not using JSSE -needs-client-auth [needs-client-auth] - true if needs client auth; otherwise false -bindWebApp [application deployment name] [web-app name] [web-site name] [context root] - binds a web app to the specified site + root -application [name] [command] - application specific command, subcommands includes:

-dataSourceInfo - gets info about the installed datasources -restart - restarts the application, this will trigger auto-deployment if enabled and a file has been touched -addUser [username] [password] - adds a user to the application -listDataSource - lists the installed datasources -removeDataSource - removes an existing datasource, arguments are: -location [location] - the namespace location for the source, for instance jdbc/DefaultDS -testDataSource - tests an existing datasource, arguments are: -location [location] - the namespace location for the source, for instance jdbc/DefaultDS -username [username] - the username to login -password [password] - the password to login -installDataSource - installs a new datasource, arguments are: -jar [path] - path to a jar file to add to the server's library -url [url] - the JDBC database URL -location [location] - the namespace location for the raw source, for instance jdbc/DefaultRawDS -pooledLocation [pooledLocation] - the namespace location for the pooled source, for instance jdbc/DefaultPooledDS -xaLocation [xaLocation] - the namespace location for the XA source, for instance jdbc/xa/DefaultXADS -ejbLocation [ejbLocation] - the namespace location for the EJB source, for instance jdbc/DefaultEJBDS - this is the source usually used by applications -username [username] - the username to login -password [password] - the password to login -connectionDriver [drivername] - the JDBC database driver class, for instance com.mydb.Driver -className [className] - the datasource class name, for instance com.evermind.sql.DriverManagerDataSource -sourceLocation [sourceLocation] - the underlying data source of this specialized data source -xaSourceLocation [xaSourceLocation] - the underlying XADataSource of this specialized data source

-updateDataSource - updates an existing datasource, arguments are: -oldLocation [oldLocation] - the old namespace location for the source, for instance jdbc/DefaultDS -newLocation [newLocation] - the new namespace location for the source, for instance jdbc/DefaultDS -jar [path] - path to a jar file to add to the server's library -url [url] - the JDBC database URL -pooledLocation [pooledLocation] - the namespace location for the pooled source, for instance jdbc/DefaultPooledDS -xaLocation [xaLocation] - the namespace location for the XA source, for instance jdbc/xa/DefaultXADS -ejbLocation [ejbLocation] - the namespace location for the EJB source, for instance jdbc/DefaultEJBDS - this is the source usually used by applications -username [username] - the username to login -password [password] - the password to login -connectionDriver [drivername] - the JDBC database driver class, for instance com.mydb.Driver -className [className] - the datasource class name, for instance com.evermind.sql.DriverManagerDataSource -sourceLocation [sourceLocation] - the underlying data source of this specialized data source -xaSourceLocation [xaSourceLocation] - the underlying XADataSource of this specialized data source -deployconnector - deploy a Connector Architecture compliant resource adapter (RAR), arguments are: -file [path] - path to the Resource Adapter Archive to deploy -name [name] - name of the resource adapter deployment -nativeLibPath [path] - path to the native libraries within the RAR archive -grantAllPermissions - grant all runtime permissions requested by the RAR -undeployconnector - undeploy a Connector Architecture compliant resource adapter (RAR), arguments are: -name [name] - name of the resource adapter deployment

-updateConfig - trigger oc4j server to check the configuration file changes $

Appendix D: Debugging Tips Overview In this appendix we'll identify some options that you can use when debugging OC4J applications. Specifically, we'll identify the following: •

Debugging options within the 10g AS Application Server Control (ASC) utility.



Logging options within 10g AS.



Logging and debug switches within OC4J.

10g AS Application Server Control Utility In this section we'll cover the debugging options within ASC.

Description Once a J2EE application has been deployed to the 10g AS mid-tier server, the ASC utility provides a wide range of management options to the administrator. Among these management options is the ability to turn on debugging. Figure D-1 shows you the available JSP debugging options.

Figure D-1: JSP debugging options In Figure D-1, you can see that it's possible to do the following: •

Turn debug mode on or off.



Emit debug information.



Specify if a recompilation will occur when a JSP changes.



Run a precompile check.



Validate XML.



Use a different Java compiler.

Changing options for JSP isn't all that you can do. At the bottom of the OC4J Server Properties page (see Figure D-2), you can specify command-line options that OC4J will use.

Figure D-2: Specify command-line options In Figure D-2, you can see that it's possible to do the following: Specify a different Java executable. •

Provide different OC4J options.



Specify different Java options such as memory heap size. You can also specify debug switches, as shown at the end of this appendix.



Add environment variables.

These provide useful capabilities for when debugging applications and for performance tuning.

10g AS Application Server Control Logging In this section we'll cover the logging options within ASC.

Description 10g AS provides a wide range of logging options for all server components: OHS, OC4J, OPMN, DCM, BC4J and even deployed J2EE applications. These are managed and viewed within the graphical ASC utility. Figure D-3 shows you some of the available component logs.

Figure D-3: Logs available In Figure D-3, you can see that there are many different components that generate logs. In the case shown in Figure D-3 you only wanted to see logs for the OC4J home container instance. This provided 62 log files that could be reviewed from the GUI screen. Searching through this many log files for a specific error can be tedious and can cause errors. 10g AS provides advanced searching options, as shown in Figure D-4.

Figure D-4: Advanced log searching options In Figure D-4 you can see that it's possible to do the following: •

Select one or many different components to review logs for (for example, OHS, BC4J, DCM, OC4J applications).



Look for specific types of messages: Internal Error, Error, Warning, Notification, Trace, and Unknown.



Search based on a specific message text.



Search based on a regular expression.



Limit the result-set size.



Enter a date range.

These options allow you to automate the review of multiple log files when tracking down a problem, thus improving efficiency.

Logging and Debugging Options within OC4J In this section we'll cover the logging and debugging options within OC4J.

Logging The OC4J server is based on the Orion web application server. Therefore, the logging and debugging features within Orion are also within OC4J (although Oracle may make some changes). There are six log file types that can be found within OC4J: application, global application, server, HTTP web access, RMI, and JMS.

Application Log Each deployed application generates an application.log located in $ORACLE_HOME/j2ee/home/application-deployments/application_name. This log file shows application deployments, stopping, starting, and any errors with timestamps that occurred within the application. This is specific to a deployed application.

Global Application Log The server tracks startup and shutdown errors in the global-application.log located in the $ORACLE_HOME/j2ee/home/log directory.

Server Log The server.log file shows startup, shutdown, and internal errors with timestamps within the OC4J container. It's located in the $ORACLE_HOME/j2ee/home/log directory.

HTTP Web Access Log The HTTP web access log shows Apache style access to the application as shown in httpweb-access.log, as follows: 192.168.1.39 - - [27/May/2004:19:36:14 -0500] "GET / HTTP/1.1" 200 2919 192.168.1.39 - - [27/May/2004:19:36:14 -0500] "GET /blaf.css HTTP/1.1" 200 5832

192.168.1.39 - - [27/May/2004:19:36:34 -0500] "GET /examples/servlets HTTP/1.1" 301 0 You can use this file to see what traffic is reaching your server, from where, and what it is doing. This file is located in $ORACLE_HOME/j2ee/home/log. The format and location of this log file is configured within $ORACLE_HOME/j2ee/home/config/http-web-site.xml.

RMI Log Remote Method Invocation (RMI) messages are written to rmi.log, which is located in the $ORACLE_HOME/j2ee/home/log directory.

JMS Log Java Message Service (JMS) messages are written to jms.log, which is located in the $ORACLE_HOME/j2ee/home/log directory.

Debug Switches It's possible to pass debug switches to OC4J, both with the OC4J standalone and as part of a 10g AS mid-tier installation. To set a switch within the 10g AS mid-tier server, put it in the Java Options box of the ASC Server Properties page, as shown in Figure D-2. To run the OC4J standalone with a debug switch, you need to adjust your startup command. Place -Dswitch_name after the java command when starting OC4J. For example, to start up OC4J with the http.error.debug option on, issue the following: $ java -Dhttp.error.debug -jar oc4j.jar -config config/server.xml verbosity 10 Here are some multiple debug switches that are available. •

ApplicationServerDebug



jdbc.debug



jdbc.connection.debug



datasource.verbose



DataSourceConnection.debug



rmi.debug



http.error.debug



http.session.debug



ajp.debug



ejb.debug.state



tag.library.loadgin.debug



debug.corruptbinary



multicast.debug



zip.debug

Other debug switches are also available. For more information see Appendix A of the OTN at http://downloadwest.oracle.com/docs/cd/B12314_01/web.904/b10323/toc.htm as well as the Orion application server website (www.ironflare.com). Go to Documentation and then Debugging.

Oracle Application Server 10g J2EE Deployment And Administration.pdf

Manufacturing Manager: Tom Debolski. Page 3 of 537. [Indo-Book.com] Oracle Application Server 10g J2EE Deployment And Administration.pdf. [Indo-Book.com] Oracle Application Server 10g J2EE Deployment And Administration.pdf. Open. Extract. Open with. Sign In. Main menu. Displaying [Indo-Book.com] Oracle ...

6MB Sizes 3 Downloads 274 Views

Recommend Documents

Oracle Application Server 10g Administration Handbook (McGraw ...
Try one of the apps below to open or edit this item. Oracle Application Server 10g Administration Handbook (McGraw-Hill 2004).pdf. Oracle Application Server ...

pdf-1882\solarwinds-server-application-monitor-deployment-and ...
Connect more apps... Try one of the apps below to open or edit this item. pdf-1882\solarwinds-server-application-monitor-deployment-and-administration.pdf.

and Oracle 10g databases
the server level go to the windows service manager, MSSQL service, and add -t1211. ...... on this raid 5 the transaction log resided for a production database.

pdf oracle 10g
Whoops! There was a problem loading more pages. pdf oracle 10g. pdf oracle 10g. Open. Extract. Open with. Sign In. Main menu. Displaying pdf oracle 10g.

Oracle Database 10g - DBA.pdf
Page 1 of 98. Oracle Database 10. g. : Managing the Self- Managing Database. הדר פייס. יונתן טולדנו. Certified Oracle 10g Technician. Page 1 of 98 ...

oracle dba syllabus 10g pdf
Retrying... Download. Connect more apps... Try one of the apps below to open or edit this item. oracle dba syllabus 10g pdf. oracle dba syllabus 10g pdf. Open.

Oracle Database 10g - DBA.pdf
Sign in. Loading… Whoops! There was a problem loading more pages. Whoops! There was a problem previewing this document. Retrying... Download. Connect ...

oracle jdeveloper 10g handbook pdf
There was a problem previewing this document. Retrying... Download. Connect more apps... Try one of the apps below to open or edit this item.

oracle 10g xe tutorial pdf
oracle 10g xe tutorial pdf. oracle 10g xe tutorial pdf. Open. Extract. Open with. Sign In. Main menu. Displaying oracle 10g xe tutorial pdf.

Polycom® Proxias™ Application Server and Application Development ...
A key element in Polycom's scalable IMS-compliant architecture, the Proxias application server works in conjunction with the Polycom InnoVox® 4000IP media ...

Polycom® Proxias™ Application Server and Application Development ...
A key element in Polycom's scalable IMS-compliant architecture, the Proxias application server works in conjunction ... modifiable, with automatic detection of new ... Linux® operating system. • JBoss Enterprise Middleware. • JAIN SIP Interface.

oracle sql optimization deployment and statisti
Expert oracle sql pdf free it ebooks download. Expert. oracle sql pdf ... tstats online vimeo on. ... Presentation esri international user conference san diego, ca.

man-99\oracle-developer-suite-10g-tutorials.pdf
man-99\oracle-developer-suite-10g-tutorials.pdf. man-99\oracle-developer-suite-10g-tutorials.pdf. Open. Extract. Open with. Sign In. Main menu.