Professional Documents
Culture Documents
Version 6.3.0
J2EE Development and
Deployment Guide
ATG
25 First Street
Cambridge, MA 02141
www.atg.com
Document Version
Doc6.3.0 J2EEDEVv1 3/22/04
Copyright
Copyright 1998-2004 Art Technology Group, Inc.
This publication may not, in whole or in part, be copied, photocopied, translated, or reduced to any electronic medium or machine-readable
form for commercial use without prior consent, in writing, from Art Technology Group (ATG), Inc. ATG does authorize you to copy
documents published by ATG on the World Wide Web for non-commercial uses within your organization only. In consideration of this
authorization, you agree that any copy of these documents which you make shall retain all copyright and other proprietary notices
contained herein.
Trademarks
Dynamo is a registered trademark of Art Technology Group, Inc.
ATG Dynamo Application Server, ATG Relationship Management Platform, ATG Scenario Personalization, ATG Portal, ATG Commerce, ATG
Publishing, ATG Data Anywhere Architecture, and ATG Control Center are trademarks of Art Technology Group, Inc.
Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and
other countries.
This product includes software developed by the Apache Software Foundation (http://www.apache.org/).
All other company and product names are the trademarks or registered trademarks of their respective companies.
No Warranty
This documentation is provided as is without warranty of any kind, either expressed or implied, including, but not limited to, the implied
warranties of merchantability, fitness for a particular purpose, or non-infringement.
The contents of this publication could include technical inaccuracies or typographical errors. Changes are periodically added to the
information herein; these changes will be incorporated in the new editions of the publication. ATG may make improvements and/or changes
in the publication and/or product(s) described in the publication at any time without notice.
Limitation of Liability
In no event will ATG be liable for direct, indirect, special, incidental, economic, cover, or consequential damages arising out of the use of or
inability to use this documentation even if advised of the possibility of such damages. Some states do not allow the exclusion or limitation of
implied warranties or limitation of liability for incidental or consequential damages, so the above limitation or exclusion may not apply to
you.
Contact
ATG
25 First Street
Cambridge, MA 02141
617.386.1000 phone
617.386.1111 fax
www.atg.com
Contents
Introduction
3
3
4
6
6
6
7
9
10
11
12
13
13
14
15
15
16
16
19
19
20
21
22
22
25
26
27
27
27
28
30
31
31
iii
Contents
Web Applications
Overview of Web Applications
web.xml File
Standalone WAR Files
Web Services
How Dynamo Processes a JSP Request
Resources in web.xml
Optional Resources
Adding New Resources to web.xml
Creating Filters and Servlets
Specifying Session Timeouts
Enabling Session Failover
Additional Configuration for Web Applications
Specifying Web Mappings
Enabling Listing of Directories
Configuring Servlet Pooling
Specifying the Ordering of Filters
33
35
36
37
37
38
38
38
38
40
40
41
41
43
44
44
44
45
46
47
49
49
53
53
55
55
60
61
61
61
62
62
62
63
65
66
66
66
67
68
68
Enterprise JavaBeans
EJB Examples
71
72
iv
Contents
Application Clients
Application Client Overview
Deploying Application Clients
Resolving JDBC Resource References
Resolving JavaMail Resource References
Running Application Clients
Application Clients and EJB Clustering
Running an Application Client Remotely
Lightweight Application Clients
Lightweight Application Clients and EJB Clustering
J2EE Security
Dynamo J2EE Security Architecture
Configuring Dynamo Security for J2EE
Single Login
J2EE Security Example
Deploying the J2EE Security Example
Running the J2EE Security Example
The J2EE Security Example Explained
SQL Repository Configuration Example
Hashing Passwords
Administrative Users
73
73
75
77
78
80
81
83
85
87
87
88
89
93
95
96
99
100
104
107
109
109
110
110
113
114
114
115
116
120
123
123
125
129
129
130
131
132
137
138
141
v
Contents
143
145
Index
145
146
149
vi
Contents
1 Introduction
Java 2 Enterprise Edition (J2EE) is a standard platform for writing enterprise applications in Java. It is
defined by a set of specifications that is maintained and extended by Sun through the Java Community
Process (JCP). It dictates the way server-side applications should be written and packaged in order to be
portable across J2EE implementations, and also mandates what services a J2EE application server must
provide to the applications it hosts.
Dynamo supports the J2EE 1.3 standard. You can create J2EE applications in Dynamo and deploy them on
any J2EE-compliant application server (including, of course, Dynamo itself), and you can deploy and run
J2EE applications on Dynamo that were developed on other J2EE application servers.
This book discusses all aspects of developing and deploying J2EE applications in Dynamo. It includes the
following chapters:
Dynamo and J2EE
Creating a Sample J2EE Application
Web Applications
Using the Dynamo Deployment Editor
Enterprise JavaBeans
Application Clients
J2EE Security
Appendix A: Darina Command Options
Appendix B: Sun JMS Reference Implementation
1
1 - Introduction
2
1 - Introduction
One of the key advantages of J2EE applications is portability. To ensure that they are portable between
application servers, J2EE applications make only generic references to system resources. For example, an
application may require a JDBC connection, but the application code does not directly create or refer to
this connection. Instead, the application refers to the resources generically, and when the application is
deployed, the deployment descriptors map these generic references to specific resources on the
application server.
Therefore, to develop and run J2EE applications on a specific application server, you need to understand
the unique features of that application server. This chapter discusses key features of Dynamo Application
Server (DAS) that the J2EE developer and deployer must be familiar with. It includes the following topics:
Accessing Dynamo Services
Mapping Resource References
Mapping Applications to Repositories
Deploying an Existing J2EE Application in Dynamo
Developing a New J2EE Application in Dynamo
J2EE Demo Applications
Nucleus, which is the application framework through which you access Dynamo
services
Nucleus
Dynamo includes an application framework called Nucleus. In Nucleus, each service is packaged as a
JavaBean or set of JavaBeans. These JavaBeans are configured individually and mounted into a
namespace. The beans then interconnect with the beans representing other services. Nucleus is
responsible for interpreting the component configurations and the management of the component
namespace.
3
2 - Dynamo and J2EE
Dynamo uses the Nucleus framework to organize components into a hierarchical structure (similar to a
directory structure). Each Nucleus service has a unique Nucleus name. For example, the default
javax.sql.DataSource component is located at /atg/dynamo/service/jdbc/JTDataSource.
Developers and deployers can change the configurations of individual components, inspect components
at runtime, and add new components to the namespace. You can create these components from existing
ATG classes, or from classes you write yourself. The details of Nucleus configuration, and the services
maintained by Dynamo, are explained in the ATG 6 Dynamo Programming Guide.
There are two distinct ways you can use Nucleus components with J2EE-based applications:
Most DAS services (servers, database connections, EJB and Web containers, schedulers,
loggers, etc.) are implemented as Nucleus components. As part of deploying a J2EE
application in Dynamo, you may need to map resources required by the application to
Nucleus components. The Mapping Resource References section (below) discusses
mapping the resources used by J2EE applications to Nucleus services.
You can incorporate Nucleus components in your applications directly, and access
them in JavaServer Pages using the DSP tag libraries. Using Nucleus enables you to
incorporate the personalization, commerce, and publishing features of ATG 6 in your
J2EE applications. The ATG 6 Page Developers Guide provides information about the
DSP tag libraries.
Repositories
ATG 6 has several features that require persistent storage. The security manager, for example, requires a
mechanism to store usernames, passwords, and user/group associations.
Unlike some application servers, Dynamo does not handle persistence directly through a SQL database.
Instead, Dynamo uses an intermediate data access layer called the Repository API. Whenever Dynamo
needs to load, store, or query a data source, it makes the appropriate calls through this API. The repository
translates the API calls into whatever calls are needed to access that particular data source.
Dynamo provides implementations of the Repository API for various data sources. Perhaps the most
powerful implementation is the SQL repository, which interfaces the Repository API to an SQL database.
However, the Repository API can access other data sources such as LDAP or content management
systems.
Because of this approach, applications that use only the Repository API to access data can interface to any
number of back-end data sources solely through configuration. For example, the security system can be
directed to maintain its list of usernames and passwords in an SQL database by pointing the security
system at the SQL repository. Later, the security system can be changed to use LDAP by reconfiguring it to
point to the LDAP repository.
Dynamos container-managed persistence (CMP) for entity EJBs is based on the SQL repository; other
repository implementations cannot be used for CMP. As is always the case for CMP, the mapping of CMP
fields to the data source is handled through configuration files. The code within the EJB implementation
classes does not need to be aware of repositories or persistence.
4
2 - Dynamo and J2EE
5
2 - Dynamo and J2EE
You can resolve the resource globally to a resource factory shared by all applications
running on the server.
You can resolve the resource reference to a resource factory used only by the specific
application.
Global Resources
Mapping a resource on the global (server) level involves setting the resource reference to the JNDI form of
a Nucleus name. A Nucleus services JNDI name is formed by prepending dynamo: to the Nucleus name;
so, for example, the default component for JDBC connection pooling is
dynamo:/atg/dynamo/service/jdbc/JTDataSource. A resource reference to this component would
look something like this:
<resource-ref>
<res-ref-name>
jdbc/db
</res-ref-name>
<resource-name>
dynamo:/atg/dynamo/service/jdbc/JTDataSource
</resource-name>
</resource-ref>
Nucleus components referenced this way must be configured through properties files. In the case of the
JTDataSource component, properties files are used to set values such as the minimum and maximum
pool size. The values in these files are read by Dynamo when it starts up. This means that if you change
any of these values, you must restart Dynamo before the change takes effect.
Note that application clients cannot use global resources, because they do not have access to Nucleus
components.
Application Resources
Mapping a resource on the application level involves setting the resource reference to a resource link, as
in this example:
<resource-ref>
<res-ref-name>
jdbc/db
</res-ref-name>
<resource-link>
6
2 - Dynamo and J2EE
jdbc1
</resource-link>
</resource-ref>
The resource factory is then configured directly in the Dynamo J2EE specifier file. For example, you might
configure a JDBC connection pool like this:
<jdbc-service>
<resource-service-name>
jdbc1
</resource-service-name>
<jdbc-lookup>
DriverManager
</jdbc-lookup>
<jdbc-url>
jdbc:solid://localhost:1313
</jdbc-url>
<jdbc-driver-class>
solid.jdbc.SolidDriver
</jdbc-driver-class>
<min-pool-size>
10
</min-pool-size>
<max-pool-size>
10
</max-pool-size>
<max-pool-free>
10
</max-pool-free>
<resource-username>
admin
</resource-username>
<resource-password>
admin
</resource-password>
</jdbc-service>
Dynamos J2EE container automatically handles the startup and shutdown of application services. As a
result, you can shut down the application, make changes to the configuration, and restart the application
with the new settings without needing to restart Dynamo.
7
2 - Dynamo and J2EE
Repositories can be configured either as global or application resources. To map a system to a repository,
there are typically several settings you need to configure.
First, you need to specify which repository the system should use. Next, you specify the name of the item
descriptor or repository view the system should use to access its data. Some systems will need to use
several item descriptors. In addition, you specify which properties of these item descriptors to use. For
example, if you map the Dynamo security system to an item descriptor in a repository, you must specify
which property of that item descriptor represents the login name, and which property represents the
password. The process of configuring the security system is discussed in the J2EE Security chapter.
For a container-managed entity EJB, the fields of the EJB must be mapped to properties of a repositorys
item descriptor. Each entity EJB with CMP must be configured with a reference to the repository its data is
stored in, and the name of the item descriptor that will represent the EJB. Each persistent field must then
be mapped to a property of that item descriptor. Finally, applications that use CMP may need to execute
specific queries at certain times. These queries are specified using Dynamos Repository Query Language
(RQL) for EJB 1.1 CMP, or using the J2EE-standard EJB query language (EJB-QL) for EJB 2.0 CMP. This
process is discussed in more detail in the Enterprise JavaBeans chapter of this manual.
The J2EE deployer must become familiar with the repository system to use it effectively, and to debug
applications when things go wrong. The use of repositories gives Dynamo a great deal of flexibility, but
also introduces some complexity. For CMP, for example, there are three layers of naming: columns of a
table in a SQL database map to properties of an item descriptor in a repository, which in turn map to fields
of an EJB. This means that you need to organize your data carefully to keep this complexity under control.
8
2 - Dynamo and J2EE
The security system can be configured to use the same SQL repository instance. Of course, the
appropriate tables must exist in the database and the SQL repository must be configured to map item
descriptors to those tables. The security system can then be configured to map its repository
requirements to those item descriptors and properties.
Entity EJB
GSA instance
JTDataSource
JDBC driver
Database
Security
In addition to using a common repository, the security system and the entity EJBs can even use the same
item descriptors. For example, there may be a Person entity EJB that maps to a Person item descriptor in
the SQL repository, which maps to a PERSON table in the database. At the same time, the security system
might also map to the same Person item descriptor in the SQL repository, using properties of that item
descriptor to represent the login name and password. Because the Person EJB maps to the same data
source as the security system, the database of users authenticated by the security system can be
managed by using Person EJBs. This is just one example of how powerful features follow from the
flexibility of the repository system.
9
2 - Dynamo and J2EE
An existing application is typically packaged as an enterprise archive (EAR) file. An EAR file contains all of
the application code, and the deployment process largely consists of supplying the necessary mappings
between the application and Dynamo resources.
Dynamo includes a command-line tool called Darina, which automates portions of the deployment
process, such as unpacking the EAR file, compiling the source files, and creating deployment descriptor
files. In addition, the ATG Control Center includes a J2EE Deployment Editor that provides a menu- and
dialog-based environment for deploying applications. Darina and the Deployment Editor call the same
underlying code for building and validating the application, so they produce similar results. Typically, you
will want to use the Deployment Editor most of the time. However, this section, and the following
chapter, describe the deployment process using Darina. Its important for you to be familiar with this tool,
both to understand what happens when you deploy an application, and in case you need to use any of
the options available only through the command line.
To deploy an EAR file, the deployer must specify information that links the application to the services in
Dynamo. This Dynamo-specific configuration is placed in a Dynamo J2EE Specifier file,
dynamoJ2EESpecifier.xml. In addition, the deployer can use this file to override settings in other
deployment descriptors. For example, if the web.xml file declares an env-entry, the
dynamoJ2EESpecifier.xml file can specify the value of this env-entry (if the value is not set in
web.xml), or override the existing value (if it is set in web.xml). After filling in all of the necessary
information in the dynamoJ2EESpecifier.xml file, the deployer then runs Darina to deploy the
application.
Creating the Dynamo J2EE Specifier file can be a complex process, but Darina can alleviate some of this
complexity by creating a template Dynamo J2EE Specifier file. The process of deploying the application
works like this:
1.
2.
Go through the Dynamo J2EE Specifier file and enter the appropriate values.
3.
Run Darina again, this time passing it the name of the directory containing the
unpacked application, to create a DAR (Dynamo Archive) file.
4.
Add the DAR file to the list of applications managed by Dynamos J2EE container, and
restart Dynamo to start up the application.
10
2 - Dynamo and J2EE
myApp/
web-app.war/
(JSP pages and content resources)
WEB-INF/
web.xml (deployment descriptor)
classes/
(java files, classes and resources)
lib/
(class and resource .jar files)
ejbs.jar/
(java files, classes and resources)
META-INF/
ejb-jar.xml (deployment descriptor)
META-INF/
application.xml (deployment descriptor)
DYNAMO-INF/
dynamoJ2EESpecifier.xml
Specify the values of any env-entry values that have not yet been filled in. You can
also supply env-entry values that override the values specified in development or
assembly.
Resolve all EJB references. You can resolve local EJB references (references to EJBs in
the same application) in the assembly stage or in the deployment stage. You must
resolve remote EJB references in the deployment stage.
Map each entity EJB that uses container-managed persistence (CMP) to a repository
view in a SQL repository, and each container-managed field to a property in the
repository view.
Map each security role to a persona defined in a UserAuthority. The persona is the
name of an entry in the UserAuthority that represents a J2EE role.
Map Web applications to URLs. Multiple Web applications can run simultaneously on a
single application server, so the overall URL space must be divided among the
applications.
11
2 - Dynamo and J2EE
Configure the behavior of entity EJBs. There are several settings for entity beans to
control when their data is synchronized with the backing store. You can modify these
settings to make tradeoffs between performance and distributed data integrity.
Note that the tags available in the Dynamo J2EE Specifier file are all described in the DTD for the file,
which you can view at:
http://www.atg.com/j2ee/dtds/dynamoJ2EESpecifier_1_3.dtd
dynamoJ2EE.xml File
As mentioned above, the dynamoJ2EESpecifier.xml file can contain a mix of Dynamo-specific tags and
tags that override entries in the standard deployment descriptors, such as web.xml and ejb-jar.xml.
When Darina generates a DAR file, it extracts all of the Dynamo-specific tags and puts them in a file
named dynamoJ2EE.xml.
The remaining tags are merged into the deployment descriptors that they apply to. Darina does not
actually modify the original deployment descriptors, however. Instead, it creates a copy of each file being
overridden, modifies the copy, and adds an alt-dd tag to the application.xml file to point to the
modified copy. This mechanism ensures that you can easily revert to the original descriptors.
For example, suppose the web.xml file declares an env-entry named defaultValue, and sets its value
to 10; in the dynamoJ2EESpecifier.xml file, you override this value, setting it to 15. When you generate
a DAR file, Darina creates a copy of the web.xml file that includes the new setting, names the file based
on the name of the WAR file, and places the file at the top level of the DAR file (rather than within the WAR
file, where the web.xml file is found). The application.xml file then declares the Web module like this:
<module>
<web>
<web-uri>web-app.war</web-uri>
<context-root>myApp</context-root>
</web>
<alt-dd>web-app_altdd.xml</alt-dd>
</module>
To revert to the original settings, remove the alt-dd tag. The application will then use the original
web.xml file.
12
2 - Dynamo and J2EE
ejb-client-jar File
If the application includes EJBs, Darina generates an ejb-client-jar file for each EJB module and
includes it in the DAR file. The ejb-client-jar contains the classes that clients need in order to access
the EJBs. These files include, at a minimum, the home and remote interfaces, and any classes referenced
by those interfaces.
For more information about debugging options in Dynamo, see the ATG 6 Dynamo Programming Guide.
For more information about logging SQL messages, see the ATG 6 Installation and Configuration Guide for
Dynamo Application Server.
13
2 - Dynamo and J2EE
(copy to server)
(add to J2EEContainer.applications)
(restart server)
14
2 - Dynamo and J2EE
Finally, to streamline the development process as much as possible, Darina can handle incremental
compilation of changed Java files. If the source Java files are included in the directory structure, Darina
can determine which files have changed, and can compile just those files into their appropriate .class
files. For EJB interfaces, Darina also regenerates the associated implementation and RMI or IIOP classes.
This incremental model enables you to concentrate on writing and modifying Java and JSP source files. To
make a change to your application, you modify the source files, run Darina, and restart the application. If
you change or add only JSPs, you do not need to do anything to make the changes available; Dynamo
automatically compiles a new or modified page when it is accessed.
Note, however, that if you want to deploy the application on another instance of Dynamo, the application
must still be packaged as a DAR file. To run the application on another Dynamo instance, you need to
create a Dynamo module, copy the DAR file into that modules directory, and add the DAR file to the
applications property of the J2EEContainer.
15
2 - Dynamo and J2EE
<DAS6dir>/J2EE-Default
You do not need to restart the application to access the new JSP. Dynamo automatically compiles a new
or modified JSP the first time it is accessed.
16
2 - Dynamo and J2EE
DynamoPath "/meeting"
See the ATG 6 Installation and Configuration Guide for Dynamo Application Server for information about
configuring Apache, IIS, and Sun ONE Connection Modules.
17
2 - Dynamo and J2EE
18
2 - Dynamo and J2EE
Developing a J2EE application is a much more rigorous task than developing a J2SE application. The Java
coding itself isnt much more difficult; in fact, the Java coding is often much simpler. What makes the task
more complex is the requirement that the classes must be packaged in a specific way, with deployment
descriptors filled out in a specific format.
This chapter presents a sample application, simpleJ2EE, that developers can use as a starting template
for building their own applications. This application uses one each of several different J2EE component
types: Servlet, JSP, JSP Tag, EJB, and application client. These components all perform trivial tasks.
However, the point of the application is to illustrate the form of a J2EE application, rather than
demonstrating J2EE functionality. Once developers have mastered the form, experimenting with complex
J2EE features becomes much easier.
This chapter also uses the simpleJ2EE sample application to demonstrate Dynamos J2EE build and
deployment tools, along with many of the options these tools have for working in different kinds of
development environments. This chapter discusses the following topics:
Structure of the Application
Building and Running the Application
Variations on the Build/Deploy Process
A single JSP (index.jsp) contains a reference to a JSP Tag. The Tag adds two numbers
together by connecting to a stateless session EJB and having that EJB perform the
calculation. The result is then printed in the JSP.
The JSP also contains a link to a Servlet in the same application, whose only function is
to print out a simple HTML page.
An application client is also included which just invokes the EJB to add two numbers
from the command line.
19
3 - Creating a Sample J2EE Application
J2EE Project
Dynamo organizes J2EE applications into projects. A J2EE project includes one or more J2EE applications,
stored in a specific directory structure. Typically, all of the applications in a single project are related.
Dynamo manages a J2EE project as a Dynamo application module. A Dynamo module is the smallest unit
that Dynamo can run. If you store multiple J2EE applications in a J2EE project, running the project will run
all of the applications in the project.
A Dynamo module is a directory found under either the <DAS6dir> directory, which corresponds to the
system property atg.j2eeserver.root, or the <ATG6dir> directory, which corresponds to the system
property atg.dynamo.root. A module is named by its position relative to one of these directories, using
the dot character (.) to separate directory levels. The module that includes the simpleJ2EE application is
in the directory J2EE-Examples/SimpleJ2EE under <DAS6dir>. This module is therefore named J2EEExamples.SimpleJ2EE. To start up Dynamo and run the applications in this module, the command
would be:
startDynamo m J2EE-Examples.SimpleJ2ee
The top-level directory of a Dynamo module containing a J2EE project typically looks like this:
META-INF/
config/
j2ee-apps/
The META-INF directory stores the manifest file (named MANIFEST.MF) that specifies configuration
information about the module. The manifest file for a J2EE project typically looks like this:
Manifest-Version: 1.0
ATG-Config-Path: config/
ATG-Required: DAS
This file adds the config directory at the top level of the module to Dynamos CONFIGPATH , and it
specifies that this module requires the DAS module. Every J2EE project requires the DAS module, which
includes the J2EE container functionality.
The j2ee-apps directory contains one or more subdirectories, each representing an individual J2EE
application. The SimpleJ2EE project includes only one application, so j2ee-apps contains only one
subdirectory, named simpleJ2EE. This subdirectory is located at <DAS6dir>/J2EEExamples/SimpleJ2EE/j2ee-apps/simpleJ2EE.
Note that the j2ee-apps directory is not strictly required. The application directories can be in the toplevel directory of the Dynamo module, rather than being subdirectories of j2ee-apps. The main
advantage of having a j2ee-apps directory is that it provides a clearer separation between the top-level
directories of the Dynamo module, which contain configuration that applies to the entire project, and the
subdirectories that contain the individual applications.
The config directory stores properties files for global services that the J2EE project uses. Each J2EE
project must have a config directory, and use it to configure Dynamos J2EE Container to add the
projects applications to the list of applications it can run. This is done in the file
20
3 - Creating a Sample J2EE Application
This names the location of the staging directory that contains the compiled and deployed J2EE
application. If the project includes more than one application, the line above is a comma-separated list,
such as:
applications+=\
{atg.j2eeserver.root}/J2EE-Examples/SimpleJ2EE/j2ee-apps/simpleJ2EE,\
{atg.j2eeserver.root}/J2EE-Examples/SimpleJ2EE/j2ee-apps/anotherJ2EE
More complex J2EE projects may include other configuration files. For example, if a J2EE project includes
an application that uses container-managed persistence (CMP), configuration files may be needed to map
the SQL repository used for CMP to the underlying database.
For more information about application modules in Dynamo, see the ATG 6 Installation and Configuration
Guide for Dynamo Application Server.
J2EE Application
As mentioned above, the j2ee-apps directory of the SimpleJ2EE project contains a single subdirectory
called simpleJ2EE. The complete simpleJ2EE application is stored in this directory, which serves as the
staging directory for developing and deploying the application.
The simpleJ2EE directory looks like this:
META-INF/
web-app/
ejbs/
appclient/
The META-INF directory contains the application.xml deployment descriptor. The other directories
contain the various J2EE modules that make up the application. (Note that J2EE modules are not the same
thing as Dynamo modules. A single Dynamo module can contain multiple J2EE applications, each of
which may be made up of multiple J2EE modules.)
There are several different types of J2EE modules, corresponding to various types of J2EE components.
For example, an EJB module contains EJBs, while a Web application module contains JSPs, JSP Tags, and
Servlets. In the simpleJ2EE application, there is a Web application module at web-app, an EJB module at
ejbs, and an application client module at appclient.
21
3 - Creating a Sample J2EE Application
Note that Darina does not have to be run from the <DAS6dir>/home directory, but the examples in this
document assume that to be the case.
The -build flag indicates that Darina should compile any necessary source files. In the simpleJ2EE
example, all of the source files are contained in the applications directory hierarchy.
If all of the necessary configuration information has been supplied, the command above produces a DAR
file. The name of the file is the name of the staging directory, plus the .dar extension. For example:
../J2EE-Examples/SimpleJ2EE/j2ee-apps/simpleJ2EE.dar
Note that if a DAR file by that name already exists, it is replaced by the newly created DAR file. If you want
to keep the older DAR file, move it to a different location before running Darina.
If you are iteratively modifying, building, and testing the application, you can use the no-dar flag to
instruct Darina not to create a DAR file. You can then run the application directly from the staging
directory. The command to run Darina would be:
bin/runDarina ../J2EE-Examples/SimpleJ2EE/j2ee-apps/simpleJ2EE
build no-dar
22
3 - Creating a Sample J2EE Application
The first time Darina is run against a new J2EE application, it creates a new dynamoJ2EESpecifier.xml
file, marking out the portions that need to be filled in, and stores it in the META-INF/DYNAMO-INF/
directory. You must modify this file and to supply the Dynamo-specific information needed to deploy the
application, such as mappings of resource references, and mappings of container-managed entity beans
to repositories.
In the case of the simpleJ2EE example, the first time Darina is run, it creates a
dynamoJ2EESpecifier.xml file that looks like this:
<?xml version="1.0"?>
<!DOCTYPE dynamo-j2ee-specifier SYSTEM
"http://www.atg.com/j2ee/dtds/dynamoJ2EESpecifier_1_3.dtd">
<dynamo-j2ee-specifier>
<application-name>
simpleJ2EE
</application-name>
<ejb-jar>
<module-uri>
ejbs
</module-uri>
<enterprise-beans>
<session>
<ejb-name>
AddNumbers
</ejb-name>
</session>
</enterprise-beans>
</ejb-jar>
<war>
<module-uri>
web-app
</module-uri>
</war>
<app-client>
<module-uri>
appclient
</module-uri>
</app-client>
</dynamo-j2ee-specifier>
The application-name gives the application a name that is used by Dynamo in the administrative
interfaces, and is also used to form the remote JNDI names for EJB homes. Two applications running in
Dynamo cannot have the same application-name.
Each J2EE module then has an entry identified by the modules URI. Within each ejb-jar module, each
EJB is listed, identified by its ejb-name.
23
3 - Creating a Sample J2EE Application
At this point, you typically need to fill in additional Dynamo-specific deployment information. However,
simpleJ2EE doesnt have any resource references, references to external EJBs, or entity EJBs, so it doesnt
require any additional deployment information. The dynamoJ2EESpecifier.xml file is complete as it
stands, without any additional blanks to fill in.
Therefore, you can now run Darina again to complete the deployment process. The second time Darina is
run, it validates the application directory hierarchy, compiles any necessary files, and optionally creates
the file simpleJ2EE.dar.
Notice that any generated files, such as .class files, are placed in the same directories as the
corresponding source files. Darina does not modify any source files, but it does create new files in the
applications directory hierarchy. This can cause problems if these directories are under source control.
For information about how to use Darina with applications that are under source control, see Variations
on the Build/Deploy Process.
Typically, while developing an application, you need to make incremental changes to the source code,
update the dynamoJ2EESpecifier.xml file, and rebuild the application. You may need to perform these
steps many times. Running Darina with the no-dar flag and then running the application from the
staging directory simplifies this process greatly.
When your application is complete, however, it is a good idea to create a DAR file. The DAR file contains
the complete, deployed J2EE application that can be run on a Dynamo server. The DAR file can be moved
to a different location, distributed to multiple Dynamo instances, or archived for later use.
ejb-client-jar Files
The classes in a J2EE module can reference each other, but they cannot reference classes in other
modules. For example, classes in a Web application do not have free access to classes in an EJB module, or
even in another Web application module in the same application. This means that the namespaces of the
modules are separated - two Web application modules might have classes with the exact same name, but
they will be treated as separate classes. This allows modules to be combined without danger of
namespace collisions.
Of course, this presents an immediate problem since the classes in a Web application may need to access
the home and remote interfaces in an EJB module. In the case of simpleJ2EE, the AddNumbersTag in the
Web application makes reference to the AddNumbersHome and AddNumbers EJB interfaces.
To address this problem, J2EE includes the notion of an ejb-client-jar. This is a JAR file, stored at the top
level of the application, that contains just the class files needed by clients of an EJB module. For example,
clients will need access to the home and remote interfaces (such as AddNumbersHome and AddNumbers),
but do not need access to the EJB implementation classes (such as AddNumbersEJB). So the ejbclient-jar will contain a subset of the classes in the EJB module.
Application developers can create ejb-client-jar files manually. However, this can be a tedious task
that is best left to Darina. If an application does not supply its own ejb-client-jar, Darina will
automatically construct the ejb-client-jar, taking its best guess as to what classes need to go into
that JAR file. Darina does this by compiling each home and remote interface and implementation class,
and seeing what class files the home and remote interfaces depend on. The result should be class files
corresponding to the home and remote interfaces, as well as any classes referenced by those interfaces,
24
3 - Creating a Sample J2EE Application
any classes referenced by those classes, etc. Those class files are put into a JAR file and used as the ejbclient-jar.
These ejb-client-jars are then added to the CLASSPATH of any other modules that have ejb-links
to that modules EJBs. For example, when simpleJ2EEs Web application is compiled, the ejb-clientjar from the EJB module is included in the CLASSPATH, thereby allowing the AddNumbersTag to
reference the AddNumbersHome and AddNumbers interfaces at compile and run time.
Compiling a JSP is a two-step process. First, the JSP is translated into a Java source file, and then the Java
file is compiled into a .class file. The .class file is a servlet that is executed when a user accesses the
page.
The compiled .class files are stored in the WEB-INF/DYNAMO-INF/jspbuild subdirectory of the Web
application (in both the staging directory and the DAR file). Note that each time an JSP file is modified, it
must be recompiled to pick up the changes. Darina compiles JSPs incrementally; i.e., if a JSP file has a
corresponding .class file that was created more recently than the modification date on the JSP, Darina
does not compile the JSP, because its .class file is assumed to be up to date.
By default, Darina precompiles only files with the extension .jsp. If you have any page fragments that
cannot be compiled on their own, give these files a different extension (such as .jspf), so Darina will not
attempt to compile them.
25
3 - Creating a Sample J2EE Application
any files whose names dont match this pattern. By default, matches files with the
extension .jsp.
excludeFiles
A regular expression pattern to determine which files to exclude from compilation. If a
files name matches the excludeFiles pattern, Darina does not compile the file,
regardless of whether its name also matches the includeFiles pattern. Default is
null.
The JspBatchCompiler component calls the /atg/dynamo/servlet/pagecompile/PageProcessor
component, which performs the actual compilation. For more information about the PageProcessor
component, see the ATG 6 Installation and Configuration Guide for Dynamo Application Server.
This line adds the simpleJ2EE staging directory to the list of applications that run in the J2EE container. If
the application were in a DAR file, the entry would be:
applications+=\
{atg.j2eeserver.root}/J2EE-Examples/SimpleJ2EE/j2ee-apps/simpleJ2EE.dar
To run the module, start up Dynamo and specify the module using the m switch:
bin/startDynamo -m J2EE-Examples.SimpleJ2EE
You can specify multiple modules using this switch. For example:
bin/startDynamo -m J2EE-Examples.SimpleJ2EE DSSJ2EEDemo
Once Dynamo has completed its startup, the simpleJ2EE application should be running. Verify this by
accessing the following URL:
http://{hostname}:8840/simpleJ2EE/
26
3 - Creating a Sample J2EE Application
This URL displays the applications index.jsp page, which calculates the sum of 17 and 49 and prints the
result. The page also contains a link to a servlet named SimpleServlet. Clicking this link executes the
servlet, which displays a page containing the text This page was generated by a servlet.
This command runs the application client, which prints the sum of 18 and 95, and then exits.
Note that the runAppClient command can only run an application client if it is part of a J2EE application.
It is also possible to write clients that are not part of any J2EE application, but still communicate with EJBs
in a J2EE application. For information about running this type of application client, see the Lightweight
Application Clients section of the Application Clients chapter.
Rebuilding an Application
Once you have built and deployed an application, you may need to modify it to fix bugs or add features.
After you make changes, you must rebuild the application for the changes to take effect. Darina makes
this simple through its incremental build feature, available through the build command-line flag. When
you rebuild an application that has already been deployed, Darina determines which files have changed
and recompiles only those files.
For example, modify the SimpleServlet.java source code found in the web-app/WEBINF/classes/atg/simpleJ2EE directory of the simpleJ2EE application. Find this line:
out.println ("<p>This page was generated by a servlet");
Change it to this:
27
3 - Creating a Sample J2EE Application
Then, from the <DAS6dir>/home directory, re-run Darina using the build flag:
bin/runDarina ../J2EE-Examples/SimpleJ2EE/j2ee-apps/simpleJ2EE
build no-dar
Darina will detect that SimpleServlet.java is the only file that has changed, and will recompile it.
If you shut down Dynamo and restart it, it will run the new version of the application. You can also run the
new version of the application without restarting Dynamo, as described in the Reloading an Application
section.
There are some instances when an incremental build will not work correctly. If an interface changes, for
example, that affects not only the interface class, but also those classes that implement the interface.
Darina cannot detect all of these dependencies, so it will recompile only the interface class, because it is
the only source file that changed. The same situation arises for classes that resolve other classes
dynamically by name, or for classes that act as superclasses for other classes, etc.
In these situations, you should rebuild the entire application. To do that, run Darina with the -buildall
flag. Darina will recompile all source files, regardless of whether they have changed. For example:
bin/runDarina ../J2EE-Examples/SimpleJ2EE/j2ee-apps/simpleJ2EE
-buildall no-dar
A complete rebuild takes longer than an incremental rebuild, but it ensures that all of the compiled
classes are up to date. In a typical development cycle, incremental rebuilds should generally be sufficient.
A complete rebuild is necessary only if you see problems, such as class loading errors, that indicate that
some classes are not up to date.
When creating a final build for release onto a live site, however, you should always do a complete (rather
than incremental) build. In addition, you should run Darina without the no-dar flag, so that Darina
creates a DAR file that you can then copy to the site.
Reloading an Application
As mentioned in the previous section, if you modify an application and then restart Dynamo, it will run
the new version of the application. However, Dynamo can also reload a J2EE application on the fly,
without restarting the server. This is very convenient at development time, when you may need to modify
and restart the application frequently.
During the development process, you can run Darina with the no-dar flag, and then run the application
from the staging directory. This approach is much faster than creating a DAR file each time you make
changes to the application, because it avoids both the packaging and unpacking of the DAR file:
1.
On the J2EE Container page of the Dynamo Administration UI, click on the link for the
application. This takes you to a page with information about the application.
2.
28
3 - Creating a Sample J2EE Application
3.
4.
5.
Click the Reload Application link to run the new version of the application.
Note that the previous version of the application is no longer available at this point. If you need to keep
an older version of the application, you should create a DAR file from that version before making any
changes.
2.
Run Darina (without the no-dar flag) to create a new DAR file.
3.
Replace the DAR file in the Dynamo module with the new DAR file.
4.
On the J2EE Container page of the Dynamo Administration UI, click on the link for the
application. This takes you to a page with information about the application.
5.
The new DAR file is unpacked into the <ATG6dir>/home/j2ee/runtime directory, but under a different
name from the old unpacked DAR file. After unpacking the new DAR file, Dynamo starts up the new
version of the application. The old version will finish handling any existing requests and threads, but all
new ones will be directed to the new version.
Note that depending on the differences between the two versions, this switchover can result in errors; for
example, a session that started in the old version might be missing some data that the new version
requires. Also, if an external client has references to EJBs in the old version, these references will become
invalid and the client will need to acquire references to EJBs in the new version. Therefore this approach is
not recommended on production systems.
29
3 - Creating a Sample J2EE Application
So, for example, to reload the simpleJ2EE DAR file (assuming the current directory is <DAS6dir>/home
and you are using the default admin account), the command would be:
bin/reloadDarFile user admin password admin
../J2EE-Examples/SimpleJ2EE/j2ee-apps/simpleJ2EE.dar
Create a new DAR file each time you make changes to the application, and then run
the application from the DAR file.
Skip the creation of the DAR file, and run the application from the staging directory
Having both of these options gives you a great deal of flexibility, but there is a potential pitfall. You must
make sure that the applications property of the J2EEContainer component is set properly, or you
may inadvertently run the wrong version of the application.
For example, suppose you have the applications property set to run the application from a DAR file. If
you make subsequent changes to the application, you must be sure to generate a new DAR file.
Otherwise, the version of the application in the DAR file will be older than the version in the staging
directory, but Dynamo will still run the DAR version, since thats what the applications property points
to.
In practice, though, this situation is easy to avoid. On development machines, it is a good idea to run the
application directly out the staging directory, since this is fastest and easiest, and simplifies the iterative
modify/build/test process. On the live site, however, it is generally easiest to run the application from a
DAR file, since you will typically be deploying applications built on development machines, and it is much
30
3 - Creating a Sample J2EE Application
easier to copy over a single DAR file than a set of directories. In addition, Darina validates the application
when you build the DAR file, so it does not have to be validated when it is loaded.
The recommended development/deployment approach, then, is as follows:
1.
2.
Iteratively modify, build, and test your application. Each time you build the
application, run Darina with the no-dar flag.
3.
When you are satisfied that the application is complete, run Darina again, this time
without the no-dar flag, so that Darina generates a DAR file. For this build, it is also a
good idea to use the buildall flag, so Darina recompiles all of the source files.
4.
On the live site, create a Dynamo module for the application. Set the applications
property of the J2EEContainer to run the application from the DAR file.
5.
Copy the DAR file from the development machine to the appropriate location on the
live site, and restart Dynamo.
If you follow this approach, you never need to switch the J2EEContainer.applications property
between running the application from the staging directory and running it from a DAR file. Even when
you generate a DAR file on the development machine, the version of the application in the staging
directory will always be up to date, because the application is always built in the staging directory first,
regardless of whether it is subsequently packaged as a DAR file. And since the builds are never actually
done on the live site, the live site has only the DAR file available to run.
Note that this approach works even if you need to make further changes to the application once it is on
the live site. Just make the changes on the development machine (once again iteratively modifying,
building, and testing), and when you are finished, generate a DAR file. Then copy the DAR file to the live
site (overwriting the existing DAR file), and restart Dynamo.
31
3 - Creating a Sample J2EE Application
/sources/Java/
/sources/Java/atg/
/sources/Java/atg/simpleJ2EE/
/sources/Java/atg/simpleJ2EE/AddNumbers.java
/sources/Java/atg/simpleJ2EE/AddNumbersEJB.java
/sources/Java/atg/simpleJ2EE/AddNumbersHome.java
/sources/Java/atg/simpleJ2EE/AddNumbersLocal.java
/sources/Java/atg/simpleJ2EE/AddNumbersLocalHome.java
/sources/Java/atg/simpleJ2EE/AddNumbersTEI.java
/sources/Java/atg/simpleJ2EE/AddNumbersTag.java
/sources/Java/atg/simpleJ2EE/SimpleServlet.java
/sources/Java/atg/personalizationDemo/...
/sources/Java/atg/website/...
...
In this setup, the source files are no longer located in the J2EE-Examples/SimpleJ2EE/j2eeapps/simpleJ2EE directory, and are instead drawn from this external directory tree. The J2EE
application directory is still required, containing all of the deployment descriptors and Dynamo J2EE
Specifier file.
Darinas incremental build process can still work in this environment. Darina just needs to be told that the
source files are not in the application directory, but are instead located in an external directory. This is
done in the Dynamo J2EE Specifier file, on a per-module basis. For example:
<dynamo-j2ee-specifier>
<ejb-jar>
<module-uri>
ejbs
</module-uri>
<build>
<source>
<source-type>
ExternalJavaSource
</source-type>
<base-dir>
/source/Java
</base-dir>
<sub-dir>
atg/simpleJ2EE
</sub-dir>
</source>
</build>
...
</ejb-jar>
<war>
<module-uri>
web-app
32
3 - Creating a Sample J2EE Application
</module-uri>
<build>
<source>
<source-type>
ExternalJavaSource
</source-type>
<base-dir>
/source/Java
</base-dir>
<sub-dir>
atg/simpleJ2EE
</sub-dir>
</source>
</build>
...
</war>
</dynamo-j2ee-specifier>
Notice that a build tag must be specified for each module, thereby allowing different modules to draw
upon different source trees. Also notice that both the root of the source tree (/source/Java) and the
actual subdirectory to be compiled (atg/simpleJ2EE) must be specified. Multiple subdirectories may be
specified. Multiple source tags may also be specified, in which case they will be built in the order they
appear in the file.
If Darina is run with the -build flag, it will run in an incremental build mode, compiling source files from
the specified directories into class files within the application directory. The compilation occurs
recursively - if a source directory has subdirectories, then those subdirectories will also be compiled.
The advantage of this development model is that it keeps all of an organizations Java source files in a
single place. The disadvantage is that it does not take advantage of the namespace separation offered by
J2EE modules. For example, the ejbs module might contain a class called atg.simpleJ2EE.Constants,
while the web-app module might also contain a completely different class with the same name. This is
legal in a J2EE application, but if all source files are in the same directory tree, then this cannot be done.
Modules must instead be separated into different subpackages - for example, atg.simpleJ2EE.ejb and
atg.simpleJ2EE.web. This is, in fact, not a bad way to organize application source files.
/build/
/build/atg/
/build/atg/simpleJ2EE/
/build/atg/simpleJ2EE/AddNumbers.class
/build/atg/simpleJ2EE/AddNumbersEJB.class
/build/atg/simpleJ2EE/AddNumbersHome.class
33
3 - Creating a Sample J2EE Application
/build/atg/simpleJ2EE/AddNumbersLocal.class
/build/atg/simpleJ2EE/AddNumbersLocalHome.class
/build/atg/simpleJ2EE/AddNumbersTEI.class
/build/atg/simpleJ2EE/AddNumbersTag.class
/build/atg/simpleJ2EE/SimpleServlet.class
/build/atg/personalizationDemo/...
/build/atg/website/...
...
In this case, Darina does not need to know where the source files are. Darina just needs to be told where
the class files are so they can be copied into the DAR file. Once again this is done by using a build tag,
but using a source-type of ExternalClassSource:
<dynamo-j2ee-specifier>
<ejb-jar>
<module-uri>
ejbs
</module-uri>
<build>
<source>
<source-type>
ExternalClassSource
</source-type>
<base-dir>
/build
</base-dir>
<sub-dir>
atg/simpleJ2EE
</sub-dir>
</source>
</build>
...
</ejb-jar>
<war>
<module-uri>
web-app
</module-uri>
<build>
<source>
<source-type>
ExternalClassSource
</source-type>
<base-dir>
/build
</base-dir>
<sub-dir>
34
3 - Creating a Sample J2EE Application
atg/simpleJ2EE
</sub-dir>
</source>
</build>
...
</war>
</dynamo-j2ee-specifier>
A major drawback of this approach is that the ejb-client-jar files may not be created properly, since
Darina does not have access to the Java source files. Unless a development organization is prepared to
create the client-jar files itself, it should avoid this approach.
<build>
<source>
<source-type>
JavaSource
</source-type>
<base-dir>
/users/rsmith/Java
</base-dir>
</source>
<source>
<source-type>
ExternalClassSource
</source-type>
<base-dir>
/build
</base-dir>
<sub-dir>
atg/simpleJ2EE
</sub-dir>
</source>
</build>
The base-dir tag is required, and must specify a directory relative to the modules root. The sub-dir tag
is optional; there can be any number of sub-dir tags that specify directories relative to the base-dir.
35
3 - Creating a Sample J2EE Application
<build>
<source>
<source-type>
JavaSource
</source-type>
<compile-command>
javac -classpath {1} -d {2} {0}
</compile-command>
</source>
...
</build>
This specifies that source files will be found in the application directory (the default), and they will be
compiled using the command javac -classpath {1} -d {2} {0} (also the default). The {?}
expressions are placeholders for the actual values that will be supplied by Darina at runtime:
Another compile command may be specified using this format. A different compile command can be
specified for each source tag
You can also specify a compiler using the DAR_COMPILER environment variable in your environment.sh
or environment.bat file. For example, you might include an environment setting like this:
DAR_COMPILER="/usr/local/bin/jikes +E -classpath {1} -d {2} {0}"
Note that if the compile command is specified both in the dynamoJ2EESpecifier.xml file and in the
environment.sh or environment.bat file, Darina uses the command specified in the
dynamoJ2EESpecifier.xml file.
36
3 - Creating a Sample J2EE Application
4 Web Applications
This chapter discusses key aspects of building, configuring, and deploying web applications in Dynamo. It
includes the following topics:
Overview of Web Applications
How Dynamo Processes a JSP Request
Resources in web.xml
Adding New Resources to web.xml
37
4 - Web Applications
web.xml File
The main deployment descriptor for a web application is the web.xml file. This file, which is stored in the
WEB-INF directory of the WAR file, contains configuration information for the web application and its
components (servlets, tag libraries, and JSPs).
There is a META-INF directory at the top level of the WAR file that is similar to the
META-INF directory of an EAR or DAR file. Dynamo puts the DYNAMO-INF directory,
which contains the dynamoJ2EESpecifier.xml file, in this META-INF directory.
There is no application.xml deployment descriptor, so the context root for the web
application is declared in the web.xml file. You do this by declaring a context
parameter named context-root, and setting its value to the context root.
Web Services
Most of the information in this chapter concerns web applications that end users interact with through a
web browser client. However, there is another type of web application, in which the client is a remote
application that interacts with ATG 6 through Web services. The web application contains one or more
Web services, which are implemented based on the JAX-RPC (Java API for XML-based RPC) specification.
The web.xml file defines how calls these Web services are dispatched. For more information about Web
services in ATG 6, see the ATG 6 Web Services and Integration Framework Guide.
38
4 - Web Applications
Requested page
displays
DAS
Dynamo
Handler
Web
Application
Dispatcher
Web
Application
Custom
servlets
(JSPs
included)
Custom
filters
The Web server passes the HTTPServletRequest to DAS, which initiates the DAS servlet pipeline by
calling the first servlet. That servlet, DynamoHandler, creates an instance of a
DynamoHTTPServletRequest (referred to as the request) that wraps the HTTPServletRequest so that
servlets are not only able to read information on the request (standard functionality provided by
HTTPServletRequest), they can also modify the request itself (added benefit provided by
DynamoHTTPServletRequest).
The request is passed on to a series of pipeline servlets that are designed to insert themselves in the
pipeline when the information they process is included in the request. Although some servlets process
standard information thats common to all requests, the ordering and variety of the servlets in the
pipeline depends on the request contents. For more information about request handling, see Request
Handling and the DAS Servlet Pipeline chapter of the ATG 6 Installation and Configuration Guide for Dynamo
Application Server.
All requests to J2EE applications encounter the ContextPathServlet pipeline servlet, which takes the
context path supplied by the request and matches it to the context root/Web application pair in the
application.xml deployment descriptor. ContextPathServlet appends the Web application name
to the request so that WebApplicationDisplatcherServlet asserts itself next in the pipeline and
passes the request to the J2EE container.
Once the Web container receives the request, it passes the request to the Web application named in the
request, which then invokes the resources defined in web.xml in the manner outlined by the Servlet 2.3
specification.
39
4 - Web Applications
Resources in web.xml
Each Web application comes with a deployment descriptor called web.xml that includes information that
the J2EE application requires to run the module. This section describes how the application server
accesses web.xml and the resources it contains. For general information about web.xml, see the Servlet
2.3 Specification.
The Web application deployment descriptor specifies a series of resources that are instantiated and
configured based on the settings specified here. You are required to include the DTD declaration and the
Web application name in your web.xml just as you would for any other J2EE application. Remember to
use the same name for the Web application in web.xml and the J2EE deployment descriptor
(application.xml). There are no additional ATG-specific resources that you need to include here,
although you may want to browse the list of optional resources provided by ATG 6. Most applications will
require site-specific resources.
Optional Resources
Although these resources are not required, they are provided with your ATG 6 installation because they
may be of use to you.
Context Parameters
The context-root context parameter is a mechanism for making a Web application context root visible
to the Scenario engine when a change is made to the context root defined for a live site. See the Setting
the Web Application Context Root for Scenarios section of the Configuring Scenarios chapter of the ATG 6
Personalization Programming Guide.
Tag Libraries
There are two ways to make a tag library available to a Web application. The first way is to put the tag
library class files and TLD in the Web application WEB-INF directory and specify the URI value, which
matches the value in the JSPs that use the tag library, in the TLD itself. All ATG tag libraries are
implemented in this fashion. The second way uses web.xml to define the tag library URI and TLD location.
Again, the URI indicated here must match the one used in JSPs. It makes no difference which method you
use.
One benefit to having two ways to implement a tag library is that, if you find it more convenient to use
two URIs for one tag library, you can do so by declaring the tag library in web.xml with one URI and
keeping the tag library files, including the TLD that defines a second URI, in WEB-INF.
Heres how you would declare the DSP tag library declaration in web.xml:
<taglib>
<taglib-uri>/dspTaglib</taglib-uri>
<taglib-location>/WEB-INF/taglibs/dspjspTaglib1_0.tld</taglib-location>
</taglib>
For more information about the DSP tag libraries, see the ATG 6 Page Developers Guide.
40
4 - Web Applications
Web Services
The Web services that are made available by your Web application need to be described here. It is
recommended that you designate a separate J2EE application for some or all of your Web services so Web
services and application code are kept in distinct packages. Also, keeping your Web services in a
dedicated J2EE application means that each Web application (perhaps some Web services are kept in one
application, some are kept in another) is started as a distinct module in ATG 6.
ATG 6 includes several Web services, which are packaged in one of three J2EE applications. See the
chapter for a particular Web service to find out the J2EE and Web applications that contain it. Any new
Web services that you create using the ATG Web Service Creation wizard will automatically come with
fully-configured web.xml files.
For more information about Web services and ATG 6, see ATG 6 Web Services and Integration Framework
Guide.
Import atg.servlet.DynamoHttpServletRequest,
atg.servlet.DynamoHttpServletRequest, and atg.servletServletUtil.
2.
Add filters and servlets to web.xml by following the J2EE 1.3 instructions.
The example described in the Filter Example section accesses the request and response in this manner. It
also resolves a component in Nucleus, which is another common operation that could be handled by a
filter. Any resource that makes calls to a Nucleus component must also provide a means for discerning
that components Nucleus address. For instructions on how to do this, see the Basic Nucleus Operation
section of the Nucleus: Organizing JavaBean Components chapter of the ATG 6 Dynamo Programming
Guide.
41
4 - Web Applications
Filter Example
This filter accesses the Dynamo request and response objects and retrieves the Profile object attached
to the request. Next, the filter finds the Profile ID on the Profile object and saves is an attribute of the
request. Finally, the filter passes control to the filter chain so it will determine the next resource to call.
Keep in mind that this code sample may not provide the most efficient means for obtaining the Profile
object, but rather it demonstrates an easy to follow method that illustrates how a filter operates in the
context of a filter chain.
import atg.servlet.ServletUtil;
import atg.servlet.DynamoHttpServletRequest;
import atg.servlet.DynamoHttpServletResponse;
import atg.userprofiling.Profile;
import javax.servlet.*;
import javax.servlet.http.*;
/*
* An example filter that demonstrates how
* to get the DynamoHttpServletRequest
* in a Filter.
*/
public class MyFilter
implements Filter {
/*
* Called when MyFilter is started
* by the application server.
*/
public void init(FilterConfig pConfig) {
// Initialize MyFilter here.
}
/*
* Called when MyFilter is about to
* be destroyed by the application server.
*/
public void destroy() {
// Cleanup MyFilter here
}
/*
* Called by the application server
* when this filter is involved in a request.
* Resolves the Profile nucleus component
* and adds the Profile id as a request
* attribute.
*/
public void doFilter(ServletRequest request,
42
4 - Web Applications
ServletResponse response,
FilterChain chain)
throws IOException, ServletException
{
// Get the Dynamo Request/Response Pair
DynamoHttpServletRequest dRequest =
ServletUtil.getDynamoRequest(request);
DynamoHttpServletResponse = dRequest.getResponse();
// Resolve the Profile object
Profile profile =
(Profile)dRequest.resolveName("/atg/userprofiling/Profile");
// Add the Profile id as a request attribute
request.setAttribute("PROFILE_ID",
profile.getRepositoryId());
// Pass control on to the next filter
chain.doFilter(request,response);
return;
}
}
<web-app>
...
<session-config>
<session-timeout>60</session-timeout>
</session-config>
...
</web-app>
Note that each web application session is the child of a Dynamo session. By default, the Dynamo session
manager ignores web application timeouts, and just uses the session timeout of the parent Dynamo
session. To enable web application timeouts, create a SessionManager.properties file in
<ATG6dir>/home/localconfig/atg/dynamo/servlet/sessiontracking that contains this line:
observeWebAppTimeouts=true
A Dynamo session can have multiple child sessions, each representing a different web application that
the same user is accessing. The Dynamo session has its own timeout value, set (in milliseconds) by the
sessionInvalidationTime property of the SessionManager component. However, if
observeWebAppTimeouts is set to true, the Dynamo session will not time out before any of the web
43
4 - Web Applications
<web-app>
<display-name>DynamoMeetingManager</display-name>
<description>A sample Dynamo J2EE Application</description>
<distributable/>
...
</web-app>
Note that including the distributable element makes it possible for a Web application to use session
backup and failover if they are enabled, but does not itself enable these features. For information about
enabling session backup and failover in Dynamo, see the ATG 6 Installation and Configuration Guide for
Dynamo Application Server.
scheme - The protocol of the URL, which can be http or https. If the scheme tag is
omitted, the protocol is not considered when dispatching URLs.
host-pattern - The hostname, which can be a specific name or can contain wildcard
characters. The host-pattern tag is particularly useful if a server has more than one
virtual hostname, and you want to direct requests for different virtual hosts to
44
4 - Web Applications
different Web applications. If the host-pattern tag is omitted, the hostname is not
considered when dispatching URLs.
uri-prefix The beginning of the pathname portion of the URL. This parameter is
required for all web-application-mapping tags.
For example, the following tags specify that any requests arriving over HTTPS, using any hostname
ending with .atg.com, with a URI starting with /purchase should be directed to this Web application:
<dynamo-j2ee-specifier>
...
<war>
<module-uri>
web-app
</module-uri>
<web-application-mapping>
<scheme>
https
</scheme>
<host-pattern>
*.atg.com
</host-pattern>
<uri-prefix>
/purchase
</uri-prefix>
</web-application-mapping>
...
</war>
...
</dynamo-j2ee-specifier>
There can be only one instance of each of these tags within a web-application-mapping tag; you
cannot, for example, specify multiple host-pattern values in a single mapping tag. However, you can
have multiple web-application-mapping entries for a single web application, and use them to specify
mappings for different schemes, hostnames, and URI prefixes.
Note: If you are using a third-party Web server, you must configure your Connection Module to recognize
context root mappings and web application mappings, so that the Connection Module can route requests
with these values to Dynamo. By default, Connection Modules are configured to route requests with the
.jsp MIME type extension to Dynamo. You can use the DynamoPath feature in the Connection Module to
specify the context root mappings and web application mappings that indicate J2EE requests should be
routed to Dynamo. See the ATG 6 Installation and Configuration Guide for Dynamo Application Server for
information about configuring Apache, IIS, and Sun ONE Connection Modules.
45
4 - Web Applications
(e.g., index.jsp) will return a listing of the files in the directory. Listing of directories is generally not used
in production applications, so list-directories is False by default. You can override this setting:
<dynamo-j2ee-specifier>
...
<war>
<module-uri>
web-app
</module-uri>
...
<list-directories>
True
</list-directories>
...
</war>
...
</dynamo-j2ee-specifier>
<dynamo-j2ee-specifier>
...
<war>
...
<servlet>
46
4 - Web Applications
<servlet-name>
SomeServlet
</servlet-name>
<max-pool-size>
40
</max-pool-size>
<min-pool-size>
10
</min-pool-size>
</servlet>
...
</war>
...
</dynamo-j2ee-specifier>
<web-app>
...
<filter>
<filter-name>Filter1</filter-name>
<filter-class>Filter1</filter-class>
</filter>
<filter>
<filter-name>Filter2</filter-name>
<filter-class>Filter2</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter1</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
47
4 - Web Applications
<filter-name>Filter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
By default, the Dynamo web container executes Filter2 first, then Filter1, because the URI mapping
for Filter2 has higher precedence. If you set ignorePrecedenceForFilterMatching to true,
however, Filter1 is executed first, because it is declared first in the web.xml file.
48
4 - Web Applications
The previous chapters illustrated the process of developing and deploying a J2EE application in Dynamo
using Darina from the command line. Its important to understand this process and be familiar with the
files that you must create and fill in.
For a complex application, though, this can be a very tedious process. A large J2EE application may
require hundreds of tags in its deployment descriptor files.
To simplify the development and deployment process, the ATG Control Center includes a J2EE
Deployment Editor. This editor guides you through the task of filling in the fields through a series of
dialogs. You enter values in these dialogs, and the editor handles the saving of these values to the
appropriate deployment descriptor files. It also provides options that call the same underlying code used
by Darina for validating the application, identifying errors, and building and running the application.
This chapter includes the following sections:
Overview of the Deployment Editor
Deploying an Application
Deploying a Standalone Module
Resolving Resource References
Resolving Security Roles
creating the necessary manifest files, deployment descriptor files, and properties files
49
5 - Using the Dynamo Deployment Editor
Note that using the deployment editor does not preclude performing some of these functions manually
as well. For example, you can still edit the dynamoJ2EESpecifier.xml directly, manually create
directories for new J2EE modules, or build the application by calling Darina from the command line. The
deployment editor works by calling the same code as Darina for building, validating, and deploying
applications, so changes you make outside the editor will be reflected in the editor the next time you
open the application in it.
If you have an existing J2EE application in a J2EE project, you can open the application in the deployment
editor. The application can be in a DAR file, EAR file, or staging directory, and must be part of a J2EE
project. If the application is structured properly, it will appear in the deployment editors list of J2EE
applications installed on the server. (See the J2EE Project section of the Creating a Sample J2EE
Application chapter for information about the structure of a J2EE project.) If the application is in an EAR or
DAR file, the application appears with the name of the file, minus the extension.
When ATG 6 is first installed, it includes several J2EE projects. To see the list of projects, start up the ACC,
and select the Utilities > J2EE Deployment screen. Your screen should look something like this:
The screen contains a browser that lists all of the J2EE projects installed on the server, and the
applications each project contains. You can open any application in the list by double-clicking on the
name of the application, which is the name of the staging directory or archive file (minus the extension). If
the application is in a staging directory, it will open in the editor. If the application is in an EAR or DAR file,
the editor will unpack the application before opening it. (You can determine whether an application is in
an archive file or a staging directory by placing your cursor over the name of the application and viewing
the resulting tool tip.) Note that if the project contains a staging directory and an EAR or DAR file with the
same name (not including the extension), the editor will open the version in the staging directory, not the
archive file.
Double-click on the j2eeDefault application and it will open in the editor. The screen should now look
similar to this:
50
5 - Using the Dynamo Deployment Editor
The editor screen consists of three panes. The left pane is a browser that displays the application as a treelike structure of nodes. When you select a node in this pane, the top right pane displays a dialog box for
editing the data associated with that node. The lower right pane is used to display validation errors
associated with the selected node.
Now choose View > Expand All, and the browser shows an expanded view that includes all of the nodes.
Then select the web-app node in the left pane. A tabbed dialog box displays in the data pane (the upper
right). The screen should now look similar to this:
51
5 - Using the Dynamo Deployment Editor
The browser in the left pane uses three icons to differentiate the nodes. The following table explains these
icons:
Icon
Description
Can have any number of children (including zero). Node itself has no data associated with it.
Has data associated with it but cannot have children.
Has a predefined set of children. Node itself has data associated with it.
The content of the data pane differs depending on the type of icon selected. If you select a folder icon, the
data pane displays a dialog for creating a new child node. If you select an icon that has data associated
with it, the data pane displays a dialog box for editing the data.
52
5 - Using the Dynamo Deployment Editor
Deploying an Application
The deployment editor provides all of the tools necessary for deploying an existing J2EE application in
Dynamo. Using the editor, you can install an application stored in a EAR or DAR file, create a J2EE project,
fill in the deployment descriptors, and validate and start up the application.
In addition, the deployment editor is flexible enough to support Dynamos incremental development and
deployment mode. Using the deployment editor, you can create a new application from scratch, or by
starting with an existing application as a template. In this mode, you may need to add various elements to
the application (such as a tag library or an EJB), and iteratively modify and build the application.
This section describes the complete process of using the deployment editor to create and deploy a J2EE
application, including:
2.
From the File menu, select Install J2EE Application from Local Archive.
3.
In the dialog box, fill in the name for the J2EE project and the J2EE application.
If a J2EE project with the name you specify already exists, Dynamo adds the new
application to that project. If a J2EE project by that name does not exist, Dynamo
creates a new project by that name and places the application in it.
4.
Click the ... button, and use the file browser to select the EAR file or DAR file.
53
5 - Using the Dynamo Deployment Editor
5.
Click OK.
Dynamo creates the application and, if it doesnt already exist, the J2EE project (including the top-level
directory structure and the manifest file for the project). The archive file is unpacked into a staging
directory. For example, if the project is called MyProject and the application is called myApp, the staging
directory will be <ATG6dir>/MyProject/j2ee-apps/myApp. This directory will have subdirectories for
each of the J2EE modules in the application. Dynamo also creates a dynamoJ2EESpecifier.xml file that
you can fill out by using the fields in the editor.
2.
3.
In the dialog box, fill in the name for the J2EE project and for the J2EE application.
If a J2EE project with the name you specify already exists, Dynamo adds the new
application to that project. If a J2EE project by that name does not exist, Dynamo
creates a new project by that name and places the application in it.
4.
Click OK.
Dynamo creates the application and, if it doesnt already exist, the J2EE project (including the top-level
directory structure and the manifest file for the project). It also creates the application staging directory
and its META-INF subdirectory. It does not create directories for any J2EE modules unless you
subsequently create these modules through the editor.
2.
From the File menu, select Create New J2EE Project from Template.
3.
In the dialog box, fill in the name for the J2EE project.
4.
From the drop-down menus, select the template group and the template to use.
5.
Click OK.
54
5 - Using the Dynamo Deployment Editor
Dynamo creates the new J2EE project by copying the project template you selected. The new project
contains the same applications that are in the template.
2.
Move the J2EE projects that you want to use as templates into the directory.
3.
4.
5.
Edit the templateModuleRoots property, adding the template group directory to the
list of directories.
6.
You must shut down and restart the ACC before the new template group and the templates in it are
available.
55
5 - Using the Dynamo Deployment Editor
In the data pane, enter the name of the new servlet, and click Add. The servlet appears in the editor:
56
5 - Using the Dynamo Deployment Editor
57
5 - Using the Dynamo Deployment Editor
The file transfer tool displays your local file system on the left and the directories of the application you
are editing on the right. To copy files into the application:
1.
In the file browser on the left side of the dialog box, navigate to the directory
containing the files to transfer, and select the files.
You can select any number of files and directories by holding down the Control key
and clicking. If you select a directory, Dynamo will copy the directory and all of its
contents, including any files or directories it contains.
2.
In the file browser on the right side of the dialog box, navigate to the application
directory you want to copy the files into.
3.
Dynamo copies the selected files into the application. Note that the transfer works in either direction; you
can copy files from a J2EE application to your local file system by selecting them in the right pane and
then clicking Transfer Files.
After you transfer any .java or .class files, save your configuration and then select either Tools > Build
Application or File > Reload Configuration. This will ensure that the deployment editor has up-to-date
information about these classes.
Select View > Module Components, and then select the Tag Libraries node in the
browser.
58
5 - Using the Dynamo Deployment Editor
2.
From the New Standard Tag Library drop-down list, select the tag library you want
copied into your Web application.
Note: For the DSPEL tag libraries, choose the DSP option even though it will
automatically use the dspTaglib URI. The appropriate URI is defined in the tag librarys
TLD, which is included in the DSP tag library JAR file.
3.
Note that the files are not actually copied until you build the application.
The resultant XML for the DSP tag libraries looks like the following:
<taglib>
<taglib-uri>/dspTaglib</taglib-uri>
<atg-taglib-src-dir>/DAS/taglib/dspjspTaglib/1.0</atg-taglib-src-dir>
</taglib>
When copying JSTL in this manner, a URI will not be specified in dynamoJ2EESpecifier.xml.
To include any other tag library in an application:
1.
Copy the TLD file into the web application module, placing it in the directory WEB-INF.
2.
3.
Select View > Module Components, and then select the Tag Libraries node in the
browser.
4.
In the data pane, enter the URI for the tag library, and click the first Add button.
The URI you specify is the URI used in the page directive in your JSPs and the URI
defined in the tag librarys TLD file.
5.
Click the ... button next to the TLD File Location field, and use the file browser to select
the TLD file.
Note that the files are not actually copied until you build the application.
59
5 - Using the Dynamo Deployment Editor
When you select a node in the browser, the labels for the fields that produced errors
appear in red in the data pane, and validation error messages are displayed in the
validation pane.
For example, if you add a servlet to the application, but no .java or .class file for the servlet exists, the
screen might look like this after running the validation tool:
It is a good idea to select View > Expand All before or immediately after running the validation tool. When
the browser is fully expanded, the actual nodes that produced the errors appear in red. When the browser
60
5 - Using the Dynamo Deployment Editor
is collapsed, if a node that produced an error is not visible, its parent node will appear in red until you
expand it. Note that if you select a validation error message in the lower right pane, the cursor will
automatically be placed in the field in the data pane that produced the error.
Even if all of the deployment descriptors are filled in properly, you may see class not found validation
errors if any Java source files have not been compiled. If this happens, choose Tools > Build Application
(described in the next section). When Dynamo builds the application, it will compile each .java file
whose corresponding .class file is either older than it or does not exist.
61
5 - Using the Dynamo Deployment Editor
2.
From the File menu, select Install J2EE Application from Local Archive.
3.
In the dialog box, fill in the name for the J2EE project and the J2EE module.
If a J2EE project with the name you specify already exists, Dynamo adds the new
application to that project. If a J2EE project by that name does not exist, Dynamo
creates a new project by that name and places the module in it.
4.
Click the ... button, and use the file browser to select the file.
5.
Click OK.
Dynamo creates the module and, if it doesnt already exist, the J2EE project (including the top-level
directory structure and the manifest file for the project). The archive file is unpacked into a staging
directory. Dynamo also creates a dynamoJ2EESpecifier.xml file that you can fill out by using the fields
in the editor.
2.
3.
In the dialog box, fill in the name for the J2EE project and for the J2EE module.
If a J2EE project with the name you specify already exists, Dynamo adds the new
application to that project. If a J2EE project by that name does not exist, Dynamo
creates a new project by that name and places the application in it.
4.
5.
Click OK.
Dynamo creates the module and, if it doesnt already exist, the J2EE project (including the top-level
directory structure and the manifest file for the project). It also creates the module staging directory and
its META-INF subdirectory.
62
5 - Using the Dynamo Deployment Editor
the chief advantage of an application resource is that it can be started up without restarting Dynamo. This
section describes how to resolve resource references using either approach.
Note: Application clients cannot use global resources, because they dont have access to Nucleus
components. This is explained more fully in the Application Clients chapter.
Multiple resource references can be resolved to the same application or global resource. For an
application resource, all the references to it must be in the same application. For a global resource,
multiple applications can use the same resource. If multiple references require different configurations,
the deployer must either configure separate application resources, or create multiple Nucleus
components to use as global resources.
Mapping a resource reference to a global resource can be done in two ways. You can either map the
resource reference directly to the JNDI name of a Nucleus component, or you can create a separate
resource definition and then resolve the resource reference through a resource link that maps the name
used in the code to the name of the service definition. For application resources, you must create a
separate resource definition and then link to it. Even for global resources, this approach is often
preferable, because it allows you to define the resource only once and then link to it as many times as
necessary. In addition, it enables you to link to resources in the same way regardless of whether they are
global or application-specific.
For example, suppose you create one or more JDBC connection pools as either global or application
services (or a combination of each). You can then link to these services from multiple places in your
application. For example, to specify the JDBC service used by an EJB:
1.
2.
3.
Specify a new resource reference by clicking Add, filling in the Name field in the dialog
box, and then clicking OK.
4.
5.
6.
From the Resource Type drop-down, select JDBC Resource Factory Service Definitions.
7.
In the Link field, select the resource to link the reference to.
JDBC Service
Creating a Global Resource
To create a global resource, you create one or more Nucleus components and configure them through
properties files. For example, a commonly used resource is a DataSource, which is a factory for
producing JDBC connections. A DataSource resource reference should be satisfied by a Nucleus
component of class atg.service.jdbc.MonitoredDataSource. Dynamo comes preconfigured with
such a component, /atg/dynamo/service/jdbc/JTDataSource. You can override the components
default configuration by creating the appropriate .properties file in the applications config/
directory. For example, configurations to the JTDataSource object would appear in
<ProjectDir>/config/atg/dynamo/service/jdbc/JTDataSource.properties.
63
5 - Using the Dynamo Deployment Editor
DataSource components are a bit more complex than other resources since they are actually made up of
multiple components. The JTDataSource component handles pooling and monitoring of connections,
but the actual connections are supplied by another DataSource. This DataSource may be a JDBC 2
DataSource supplied by a JDBC driver vendor, or it may be a JDBC 1 driver. Dynamos default
configuration (using the SOLID database included with Dynamo for evaluation purposes) has the
JTDataSource pointing to /atg/dynamo/service/jdbc/FakeXADataSource, a DataSource which
The JTDataSource configures the pooling and monitoring behavior of the underlying connections. For
example, the JTDataSource might have these properties:
min=10
max=20
maxFree=15
This defines the minimum and maximum number of connections to keep in the pool, and also specifies
the maximum number of free connections at any time.
Once you have configured the Nucleus components, you can create a resource definition in the
deployment editor:
1.
In the browser, select the JDBC Resource Factory Service Definitions folder.
2.
In the data pane, enter a name for the new resource, and click Add.
The new resource appears in the browser, under the folder.
3.
4.
5.
In the Resource Name field, enter the JNDI form of the Nucleus component name (e.g.,
dynamo:/atg/dynamo/service/jdbc/JTDataSource).
In the browser, select the JDBC Resource Factory Service Definitions folder.
2.
In the data pane, enter a name for the new resource, and click Add.
The new resource appears in the browser, under the folder.
64
5 - Using the Dynamo Deployment Editor
3.
4.
5.
Fill in the class name and URL for the driver, the minimum and maximum pool sizes,
and so on.
You can optionally specify values for properties of the resource by adding rows to the Properties table
and filling in the properties and their values.
2.
In the data pane, enter a name for the new resource, and click Add.
The new resource appears in the browser, under the folder.
3.
4.
5.
In the Name field, enter the JNDI form of the Nucleus component name (e.g.,
dynamo:/atg/dynamo/service/jdbc/SQLRepository).
Follow the steps for creating a GSA repository service as a global resource, but in the
Service Type radio buttons, select Immediate.
2.
3.
Specify one or more initialization files for the repository by clicking the Add button
and using the Open dialog box to select the files.
4.
Specify the JDBC resource for the repository to use. If a JDBC resource has already
been defined, you can select Link as the JDBC Resource Type, and then select the link
from the drop-down. Otherwise, you can select Name and fill in the JNDI name of a
JDBC data source.
You can optionally specify values for properties of the resource by adding rows to the Properties table
and filling in the properties and their values.
Note that if you are using container-managed persistence (CMP) for EJBs, the initialization file list must
include the file that defines the repository views used by the EJBs. If you are using CMP automatic
mapping, the file may not have been created yet when you create the GSA service. However, you can still
specify this file by typing its name (_cmpRepository.xml) in the File Name field of the Open dialog box.
See the Container-Managed Persistence section of the Enterprise JavaBeans chapter for more
information.
65
5 - Using the Dynamo Deployment Editor
2.
In the data pane, enter a name for the new resource, and click Add.
The new resource appears in the browser, under the folder.
3.
4.
In the JMS Connection Type radio buttons, select either Queue or Topic.
5.
In the name field, enter the JNDI form of the Nucleus name. For SQL JMS, this
component is dynamo:/atg/dynamo/messaging/SqlJmsProvider. For Local JMS,
this component is dynamo:/atg/dynamo/messaging/MessagingManager.
For information about the Sun JMS Reference Implementation, see Appendix B: Sun JMS Reference
Implementation. For information about SQL JMS and Local JMS, see the ATG 6 Dynamo Programming
Guide.
JavaMail Service
If a J2EE component needs to send or receive e-mail, it should do so using JavaMail facilities. You can
create a global JavaMail service by mapping the service name to the JNDI name
dynamo:/atg/dynamo/service/j2ee/MailSessionContext/DefaultSession. Application
resources that use this service can be resolved by linking to this service.
The actual Nucleus component that configures the mail system is found at
/atg/dynamo/service/j2ee/MailSessionContext. You can configure this component by setting the
URL Service
The URL resource provides a mechanism for gaining access to resources not covered by the various other
resource types. In its code, the component obtains a pointer to a java.net.URL object. From the URL
object, the component may call methods that give the component access to content or objects
represented by the URL. Thus, a URL resource can be used as a way to pass arbitrary content or objects to
a J2EE component.
You can resolve a URL resource reference directly like this:
<resource-ref>
<res-ref-name>
atgIndex
</res-ref-name>
<resource-name>
66
5 - Using the Dynamo Deployment Editor
http://www.atg.com/index.html
</resource-name>
</resource-ref>
To create a URL service in the deployment editor, just supply the name of the service and the URL it maps
to. You can then link to this service to resolve references in web modules, EJBs, etc.
<resource-ref>
<res-ref-name>erp/myErp</res-ref-name>
<res-type>com.mycompany.erp.erpResource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
The res-type is the name of the main class of the connector. The res-auth must be Container or
Application, depending on how authentication is managed for the connector.
You then resolve the resource-ref in the dynamoJ2EESpecifier.xml file. For example, to look up the
connector from a web application:
<war>
<module-uri>my-web-app</module-uri>
...
<resource-ref>
<res-ref-name>erp/myErp</res-ref-name>
<connector-link>erp.rar</connector-link>
<default-resource-user>admin</default-resource-user>
<default-resource-password>rsxqz445</default-resource-password>
</resource-ref>
...
</war>
67
5 - Using the Dynamo Deployment Editor
If you are running the connector from a staging directory, the connector-link is the name of the
subdirectory containing the unpacked RAR file; if the connector is running from a DAR file, it is the name
of the nested RAR archive. The default-resource-user is the name of the principal to use for
authentication, and the default-resource-password is the password for that principal.
68
5 - Using the Dynamo Deployment Editor
<dynamo-j2ee-specifier>
...
<war>
<module-uri>
web-app
</module-uri>
<env-entry>
<env-entry-name>
someOtherValue
</env-entry-name>
<env-entry-value>
2242
</env-entry-value>
</env-entry>
</war>
...
</dynamo-j2ee-specifier>
2.
3.
Click the Add button, and in the dialog box, specify a name for the entry, and click OK.
4.
From the Type drop-down, select the data type for the environment entry.
5.
If you specify an Application Value, this value is stored in the web.xml file. If you specify a Dynamo Value,
this value is stored in the dynamoJ2EESpecifier.xml file.
69
5 - Using the Dynamo Deployment Editor
70
5 - Using the Dynamo Deployment Editor
6 Enterprise JavaBeans
It is possible to write an application in which the user interface communicates directly with back-end
databases and resources. In the Web-based J2EE world, you implement this strategy by having Servlets,
JSPs, and JSP Tags communicate directly with a database through JDBC.
This architecture allows you to build applications quickly, but it has several drawbacks. It makes
applications sensitive to changes in the database schema, which in turn makes it more difficult to add or
change functionality. It also spreads out the knowledge of the systems functions, since that knowledge is
strewn throughout the interface code instead of being encapsulated in a controlled manner. Finally, its
harder to add new interfaces that perform similar functions. Such an operation usually requires you to cut
and paste code from one interface to the other, which leads to a management nightmare.
Because of these problems, most non-trivial applications introduce a layer of business logic into the
architecture, implemented as a set of business objects. These business objects define an API for the
back-end services of the application. These APIs are defined in terms that are not specific to any one
application or interface. For example, the business objects might define the calls that you should use to
create a new customer account or place an order. In the end, these calls make the same database calls
that the interface would have made on its own. However, because the business logic is in its own layer,
you can build multiple applications on the same functionality without cutting and pasting code. Also, the
applications are not as sensitive to changes in the database. You can confine those changes to the
business objects without requiring changes to all of the connected applications.
An application server can improve matters further by hosting business objects and providing additional
services. For example, the application server can expose those objects to the network, so that remote
clients can gain access to the back-end functionality without having to link their code directly to the
business objects. The application server can also enforce security constraints, so that applications cannot
invoke certain functions unless a user with the proper credentials directs them to do so.
Enterprise JavaBeans (EJBs) are the mechanism for encapsulating business logic and data in the J2EE
platform. EJBs are Java components that you create according to a strict form. Any EJB container (a
required part of the J2EE platform) can host EJBs that you create in this manner. Once you have installed
an EJB into an EJB container, that container must allow applications to gain access to the EJB, which will,
in turn, gain access to resources (such as databases) to carry out its functionality. At the same time, the
EJB container provides several services to EJBs, such as remote access, security, and automatic
persistence.
One of the main goals of the EJB architecture is to allow developers to concentrate on writing business
logic without being bothered by the other concerns that come up in enterprise computing (remote
access, security, persistence, etc.). To do this, EJB developers must follow a specific form in creating their
components. Developers must define certain interfaces for each EJB, with naming conventions for
methods and other restrictions on arguments and return values. In many cases, the amount of code
71
6 - Enterprise JavaBeans
required to adhere to the form will be greater than the actual business logic enclosed in the EJB. This is
natural, and should not be alarming to developers.
EJB Examples
Dynamo includes a sample application that illustrates the various types of EJBs. The example is in the
<DAS6dir>/J2EE-Examples/SimpleEJB directory. Before you can run this application, you must use
Darina to deploy it. Change to the <DAS6dir>/home directory, then run Darina like this (using forward or
backward slashes as appropriate):
bin/runDarina ../J2EE-Examples/SimpleEJB/j2ee-apps/simpleEJB -build
Darina will compile all of the applications source files, produce ejb-client-jar files, and create the
various RMI classes. When its finished, Darina will have produced a deployed DAR file at ../J2EEExamples/SimpleEJB/j2ee-apps/simpleEJB.dar.
Once the application has been deployed, you may run it by using the modules flag:
bin/startDynamo -m J2EE-Examples.SimpleEJB
This command starts Dynamo, installing the demonstration so that it starts up the same time Dynamo
does.
This demo includes eight different EJBs:
CMPPerson is an entity bean that uses container-managed persistence (EJB 1.1 style).
CPKPerson is an entity bean that uses container-managed persistence (EJB 1.1 style)
CMP2Person is an entity bean that uses container-managed persistence (EJB 2.0 style).
CPK2Person is an entity bean that uses container-managed persistence (EJB 2.0 style)
We assume that the demo will be running on SOLID, the evaluation database included with Dynamo. This
database comes pre-initialized with the schema you need to run the demo. If you use a different
database, or if the schema does not yet exist, you can use the schema by entering these commands:
72
6 - Enterprise JavaBeans
AGE INTEGER
);
CREATE TABLE EJB_CPK_PERSON (
ID INTEGER,
FIRSTNAME VARCHAR (128) NOT NULL,
LASTNAME VARCHAR (128) NOT NULL,
AGE INTEGER,
PRIMARY KEY (FIRSTNAME, LASTNAME)
);
Once you deploy and run the application, you can gain access to it by entering this URL:
http://{hostname}:8840/simpleEJB/
The URL displays links to demonstrations for different EJB types. Each demonstration is driven by its own
servlet that performs the appropriate client-side calls to gain access to the EJB and output the results. This
is not a recommended way to build an application; you should use JSPs and Tags to build interfaces. We
use servlets in this example for the purpose of simplicity.
73
6 - Enterprise JavaBeans
<web-app>
...
<ejb-ref>
<ejb-ref-name>
ejb/AddNumbers
</ejb-ref-name>
<ejb-ref-type>
Session
</ejb-ref-type>
<home>
atg.simpleJ2EE.AddNumbersHome
</home>
<remote>
atg.simpleJ2EE.AddNumbers
</remote>
<ejb-link>
AddNumbers
</ejb-link>
</ejb-ref>
...
</web-app>
The reference must be resolved by pointing it at an EJB Home that is either in the same application, or an
external EJB Home supplied by another application. Internal references may be resolved within the
deployment descriptor using ejb-link tags, as is done in the SimpleJ2EE example. However, if the
reference were not resolved there, it would have to be resolved in the dynamoJ2EESpecifier.xml file,
something like this:
<dynamo-j2ee-specifier>
...
<war>
<module-uri>
web-app
</module-uri>
<ejb-ref>
<ejb-ref-name>
ejb/AddNumbers
</ejb-ref-name>
<ejb-link>
AddNumbers
</ejb-link>
</ejb-ref>
</war>
...
</dynamo-j2ee-specifier>
74
6 - Enterprise JavaBeans
An ejb-ref may be resolved to point to an external EJB, supplied by another application, possibly hosted
by a different J2EE container provider. In this case, the deployer must know the JNDI name that should be
used to access that EJB Home. The JNDI name will depend on the vendor. The JNDI name should be
supplied using ejb-home-name, in place of ejb-link:
<dynamo-j2ee-specifier>
...
<war>
<module-uri>
web-app
</module-uri>
<ejb-ref>
<ejb-ref-name>
ejb/AddNumbers
</ejb-ref-name>
<ejb-home-name>
vendorprotocol:/somePrefix/AddNumbers
</ejb-home-name>
</ejb-ref>
</war>
...
</dynamo-j2ee-specifier>
Note that application clients may communicate remotely with EJBs in the same application, but because
they are in the same application they can use the EJBs name in an ejb-link.
As with env-entry references, ejb-ref references must be resolved on a per-EJB basis, or on a per-Web
application basis.
<session>
<ejb-name>
AddNumbers
</ejb-name>
...
<env-entry>
<env-entry-name>
defaultValue
</env-entry-name>
<env-entry-type>
java.lang.Integer
</env-entry-type>
75
6 - Enterprise JavaBeans
</env-entry>
...
</session>
The AddNumbers EJB could access the value of this entry with the following code:
InitialContext ctx = new InitialContext ();
int defaultValue = ((Integer)
ctx.lookup ("java:comp/env/defaultValue")).
intValue ();
However, the env-entry must be given a value. This could be done in the ejb-jar.xml file using an
env-entry-value. Or, it can be supplied in the dynamoJ2EESpecifier.xml file. To do this, use an enventry declaration in the dynamoJ2EESpecifier.xml file:
<dynamo-j2ee-specifier>
...
<ejb-jar>
<module-uri>
ejbs
</module-uri>
<enterprise-beans>
<session>
<ejb-name>
AddNumbers
</ejb-name>
<env-entry>
<env-entry-name>
defaultValue
</env-entry-name>
<env-entry-value>
25
</env-entry-value>
</env-entry>
</session>
</enterprise-beans>
</ejb-jar>
...
</dynamo-j2ee-specifier>
2.
3.
Click the Add button, and in the dialog box, specify a name for the entry, and click OK.
4.
From the Type drop-down, select the data type for the environment entry.
76
6 - Enterprise JavaBeans
5.
If you specify an Application Value, this value is stored in the ejb-jar.xml file. If you specify a Dynamo
Value, this value is stored in the dynamoJ2EESpecifier.xml file. For example, suppose you set the
application value to 25, and the Dynamo value to 30. When you save the configuration, defaultValue is
set to 25 in the ejb-jar.xml file, and is set to 30 in the dynamoJ2EESpecifier.xml.
When you run the application in Dynamo, the value in the dynamoJ2EESpecifier.xml file overrides the
value in the ejb-jar.xml file, so defaultValue is set to 30. However, if you were to deploy the
application on another J2EE application server, defaultValue would be set to 25 (using the value in
ejb-jar.xml), because the settings in dynamoJ2EESpecifier.xml are used only by Dynamo.
Communications Protocols
EJBs can use a variety of communications protocols for remote method calls. By default, Dynamo uses
iiop, but you can specify standard RMI instead by setting the ejb-protocol tag in the
dynamoJ2EESpecifier.xml file to rmi. For example:
<dynamo-j2ee-specifier>
<application-name>
simpleJ2EE
</application-name>
<ejb-protocol>
rmi
</ejb-protocol>
...
</dynamo-j2ee-specifier>
When you run Darina (either from command-line or through the Build option in the deployment editor), it
determines what stubs and ties to build based on the value of this setting. If you want to override the
setting, Darina accepts the command-line flags -iiop and rmi.
For example, to build the simpleJ2EE application and use standard RMI as the EJB protocol:
bin/runDarina ../J2EE-Examples/SimpleJ2EE/j2ee-apps/simpleJ2EE
build -rmi
When you use the rmi or iiop flag, Darina sets the value of ejb-protocol to match the flag, so
Dynamo can recognize which protocol is supported by the generated stubs.
IOR Security
IIOP uses Interoperable Object References (IORs) to control access to EJBs. An IOR is a reference to an
object that uses a string of digits to encode identity and security requirements for calls to that object. For
each EJB, you specify a transport configuration definition (which defines certain IIOP parameters), the
authentication service context (which specifies how callers are authenticated), and the secure attribute
service context (which specifies whether the callers identity is propagated between objects).
For example, the IOR security definition in the dynamoJ2EESpecifier.xml file might look like this:
77
6 - Enterprise JavaBeans
<enterprise-beans>
<session>
<ejb-name>
AddNumbers
</ejb-name>
<ior-security-config>
<transport-config>
<integrity>
supported
</integrity>
<confidentiality>
required
</confidentiality>
<establish-trust-in-target>
supported
</establish-trust-in-target>
<establish-trust-in-client>
supported
</establish-trust-in-client>
</transport-config>
<as-context>
<auth-method>
username_password
</auth-method>
<realm>
default
</realm>
<required>
True
</required>
</as-context>
<sas-context>
<caller-propagation>
required
</caller-propagation>
</sas-context>
</ior-security-config>
</session>
</enterprise-beans>
78
6 - Enterprise JavaBeans
demarcated area, which in the case of an EJB is a single method call. We explain the transaction attributes
in the section on transaction demarcation. By using declarative transactions, you can control and change
transactional behavior without touching any of the EJBs code.
If an EJB uses programmatic transactions, then it can start and end transactions within code. It does so
through the javax.transaction.UserTransaction interface, which it can obtain by calling
getUserTransaction() on the EJBContext. If an EJB declares that it uses programmatic transactions,
then any existing transaction is suspended before you enter the EJBs method, and is resumed after the
EJBs method ends. The EJB is responsible for ending any transactions it creates within its method call.
An EJB must use either programmatic or declarative transactions, also known as bean-managed and
container-managed transactions. It cannot use both. Furthermore, only session beans can use beanmanaged transactions. Entity beans can use only declarative transactions.
You must specify declarative transactions in the EJB deployment descriptor. Declare the transactions in a
separate section called the assembly descriptor. You can declare them to apply to all methods in an EJB or
to individual methods. For example:
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>
AddNumbers
</ejb-name>
<method-name>
*
</method-name>
</method>
<trans-attribute>
Required
</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>
AddNumbers
</ejb-name>
<method-name>
addNumbers
</method-name>
</method>
<trans-attribute>
Supports
</trans-attribute>
</container-transaction>
</assembly-descriptor>
79
6 - Enterprise JavaBeans
This example indicates that all methods of the AddNumbers EJB should have a transaction attribute of
Required, except for the addNumbers method, whose declaration of Supports overrides the *
declaration. The EJB specification describes how even more specific declarations can be made to
differentiate between methods with the same name but different arguments, or even methods with the
same name and arguments in the home and remote interfaces.
<assembly-descriptor>
<method-permission>
<role-name>
admin
</role-name>
<method>
<ejb-name>
AddNumbers
</ejb-name>
<method-name>
addNumbers
</method-name>
</method>
</method-permission>
</assembly-descriptor>
This declaration indicates that only users belonging to the admin role can call the addNumbers method.
This admin role is only an internal name. It must be declared in the assembly-descriptor:
<assembly-descriptor>
<security-role>
<role-name>
admin
</role-name>
</security-role>
<method-permission>
<role-name>
admin
</role-name>
<method>
80
6 - Enterprise JavaBeans
<ejb-name>
AddNumbers
</ejb-name>
<method-name>
addNumbers
</method-name>
</method>
</method-permission>
</assembly-descriptor>
The deployer must then map the internal admin role to an actual role name in the Dynamo security
system. This is done in the dynamoJ2EESpecifier.xml file by resolving the role name to a security
group. See the J2EE Security chapter.
EJBs can also use programmatic security, in which the EJB code uses EJBContext APIs to determine the
identity of the current caller, or determine if the caller is in a particular role. You can use programmatic
security in conjunction with declarative security (unlike transactions, in which declarative and
programmatic transactions are mutually exclusive). When using programmatic security, the EJB can call
getCallerPrincipal() on the EJBContext to obtain the name of the current caller, and can call
isCallerInRole(String roleName) on the EJBContext to see if the current caller is in a particular
role.
If the EJB uses isCallerInRole, then the EJBs deployment descriptor must declare security-roleref tags for each roleName tested. In the deployment descriptor, those security-role-refs must be
resolved through role links to security roles declared in the assembly descriptor.
81
6 - Enterprise JavaBeans
T1. Because that instance has not yet been loaded from the database, ejbLoad is called on the instance.
The method call is then executed on the instance.
The client might then make more calls in the same transaction to that same instance. Each call is routed
back to the same instance. However, ejbLoad is not called before any of those method calls since it was
already called the first time the EJB was used. Neither is ejbStore called after each of those method calls.
At some point transaction T1 ends. At that time, any EJBs associated with T1 call ejbStore, including the
EJB associated with ID 4. Because those EJBs have been synchronized with the database, those EJBs can
be dissociated from their entity instances and returned to the instance pool. This means that if the client
gains access to ID 4 again in a different transaction, the client could end up communicating with a
different EJB instance.
So that is the default behavior that Dynamo uses - it only calls ejbLoad once per instance per transaction,
and ejbStore once per instance at the end of the transaction. There are, however a couple of situations
where this behavior can create problems:
If a client makes a change to an entity instance, then executes a finder method in the
same transaction, the results from the finder might be incorrect with respect to the
entity instances state. For example, a client might change an instances age field from
20 to 21. The client might then execute a finder method to find all instances with age
greater than 20, then be surprised to find that the instance just changed is not in that
result set.
The reason for this is that even though the instances age field has been changed, that
change has not been stored to the database because the transaction has not yet
ended and ejbStore has not been called. So a finder method that executes a query
against the database will not see the change because it hasnt yet been written to the
database.
The EJB specification describes a situation called a transaction diamond, which can
occur with distributed transactions. If a client gains access to two different VMs in the
same transaction, and each of those VMs gains access to the same EJB, each VM will
have its own copy of the EJBs state in its memory. This opens the possibility of the two
EJBs getting out of sync - the EJB on one VM might change its state, but the change is
not seen by the EJB on the other VM since the transaction has not yet ended and the
new state has not yet been written to the database.
If an application runs into one of these situations, then it can change the default behavior back to the
more conservative approach of calling ejbLoad and ejbStore around every single method call. This can
be set on an EJB-by-EJB basis using the ejb-load-every-method and ejb-store-every-method tags:
<entity>
<ejb-name>
CMPPerson
</ejb-name>
<ejb-load-every-method>
True
</ejb-load-every-method>
82
6 - Enterprise JavaBeans
<ejb-store-every-method>
True
</ejb-store-every-method>
...
<cmp-mapping>
<repository-name>
...
83
6 - Enterprise JavaBeans
min-pool-size - By default, a pool starts with no instances. The deployer may wish to
change a particular EJB to create a set of instances when the application starts, rather
than waiting for the EJB to be requested. This might be used if each instance takes a
while to be created. This value can be set on an EJB-by-EJB basis in the
dynamoJ2EESpecifier.xml file:
<session>
<ejb-name>
AddNumbers
</ejb-name>
...
<min-pool-size>
10
</min-pool-size>
</session>
Dynamo will make sure that periodic sweeps that remove instances from the pool will
not drop the pool below the minimum size.
84
6 - Enterprise JavaBeans
sweep. If set to .25, then one quarter of the instances are removed, etc. This is also set
on a global basis in the EJBContainer:
poolReductionFactor=.25
Entity EJBs, using both bean- and container-managed persistence, are treated in a similar manner by
Dynamo. A particular EJB implementation instance can be directed to represent many different entity
instances over its lifetime. Dynamo manages these instances by letting a particular instance represent a
single entity instance over the lifetime of a transaction.
For example, if a client requests the entity with ID 4 in transaction T1, Dynamo will select an
implementation instance from the pool, initialize it to point to ID 4, and remember that for transaction T1,
ID 4 is handled by that instance. If the client makes subsequent calls in the same transaction for the same
entity ID, it will use the same instance. But when the transaction ends, that instance will be dissociated
from the transaction and entity ID, and returned to the pool.
So even though entity implementation instances may be used over several method calls before being
returned to the pool, the basic pooling mechanism remains the same as that used by stateless session
beans. This means that the same operation parameters described above can be applied to entity instance
pools as well as stateless session pools.
85
6 - Enterprise JavaBeans
So what should happen over time is that new files get filled up, become older, get drained out, and
eventually get removed.
Session expiration is closely related to passivation. Dynamo can be configured to expire session beans
that have gone unused for a period of time. At the same time that Dynamo sweeps through session
instances looking for instances to passivate, it also looks for instances to expire. Any that have gone
unused for too long are removed, after being notified through the ejbRemove call. If an instance was
passivated, then it is also marked as expired in the file holding the instances passivated state, which
might cause that file to be removed if there are no further instances in that file.
You can configure how Dynamo expires or passivates session beans. These properties must be set in the
/atg/dynamo/service/j2ee/EJBContainer component:
Property
Description
sessionInstanceTimeout
maxTotalActiveSessionInstanceSize
sessionExpirationSchedule
instanceStoreDirectory
instanceStoreMaxEntryCount
instanceStoreFileExpansionSize
86
6 - Enterprise JavaBeans
For example, a Nucleus component can gain access to the AddNumbers EJB in the same VM by using this
code:
Note that for an EJB in an EJB 1.1 module, the JNDI name omits the module URI. In this case, the JNDI
name would be dynamoejb:/simpleJ2EE/AddNumbers.
This approach should yield better performance since it bypasses the remote call mechanisms and gives
the application a direct link to the underlying EJB objects.
You do not have to specify properties. The username and password are inherited from the current thread,
which may have set them through a variety of mechanisms, such as an HTML login.
Container-Managed Persistence
Container-managed persistence (CMP) is one of the most attractive features of the EJB system. It allows
developers to gain access to persistent data without any of the usual JDBC or network coding. The EJB
CMP model is fairly simple: The EJB declares which of its public member variables or properties it wants to
be persistent, and the EJB container loads those variables from the database before an instance is used
and saves their values back to the database after the instance has been used.
The J2EE 1.3 specification requires the application server to support both EJB 2.0 and EJB 1.1 CMP.
Conceptually the two CMP versions are similar, but there are some significant differences in the
implementation. This section provides an overview of features that are general to both versions of CMP,
and then discusses the simpleEJB demo, which includes examples of both EJB 2.0 and EJB 1.1 style CMP.
87
6 - Enterprise JavaBeans
primitives - boolean, byte, char, int, long, float, double. Map these values to
repository properties of similar type. For example, int should map to a property of
type Integer. If a property value is of type null, then the value assigned to the
primitive field value is undefined.
Serializable - Any other serializable object that doesnt fit the above descriptions will
be stored in its serialized byte form. This means that it must map to a repository
property of type binary. Fields of this type cannot be queried meaningfully.
88
6 - Enterprise JavaBeans
This process will not detect all changes. Dynamo can reliably detect changes for immutable objects, such
as Strings and primitives, but is less reliable for more complex objects, such as arrays or collections.
As a result, Dynamo takes a conservative approach to detecting changes. If Dynamo can reliably
determine whether a value has changed or not, then it writes the value if it has changed. But if Dynamo
cannot be sure that a value has changed, then Dynamo writes the value anyway. Dynamo may appear to
be rewriting values that arent changing, but, in fact, Dynamo is only doing that because it cannot detect
that the value has not changed.
Configuring CMP
As described near the beginning of this chapter, the simpleEJB demo includes several entity beans that
use CMP. This section discusses two of those EJBs, CMPPerson and CMP2Person. These EJBs are
functionally equivalent, and differ primarily in that CMPPerson uses EJB 1.1 CMP, and CMP2Person uses
EJB 2.0 CMP.
Dynamo uses a SQL repository as its persistence mechanism for both versions of CMP. Mapping a CMP EJB
to an underlying data store involves two parts. The repository definition file (typically named
sqlRepository.xml) creates the repository views (item descriptors) and maps their properties to tables
and columns in a SQL database. The Dynamo J2EE specifier file then maps the EJBs member variables or
properties to repository views and their properties. Note that all EJBs in an application that use EJB 2.0
CMP must use the same repository.
89
6 - Enterprise JavaBeans
<property name="id"
column-name="ID"
data-type="int"/>
<property name="name"
column-name="NAME"
data-type="string"/>
<property name="age"
column-name="AGE"
data-type="int"/>
</table>
</item-descriptor>
...
<item-descriptor name="ejbCmp2Person">
<table name="EJB_PERSON2"
type="primary"
id-column-name="ID">
<property name="id"
column-name="ID"
data-type="int"/>
<property name="name"
column-name="NAME"
data-type="string"/>
<property name="age"
column-name="AGE"
data-type="int"/>
</table>
</item-descriptor>
...
</gsa-template>
The repository views defined above are very simple. In a more sophisticated application, you may need to
define complex relationships in your data. For example, an EJB representing a person might have a
spouse property that points to another EJB.
The SQL repository is sophisticated enough to model a wide variety of relationships. However, the
mapping can be complex, especially if you are not used to the semantics of defining repository views. You
can avoid this step entirely by using CMP Automatic Mapping, described below.
For more information about configuring SQL repositories, see the ATG 6 Repository Guide.
90
6 - Enterprise JavaBeans
The configuration begins by specifying which repository will handle the persistence. You can specify the
repository as either a global or application resource. The SimpleEJB demo creates a repository as an
application resource named gsa1, and the CMPPerson and CMP2Person EJBs both link to this resource:
<cmp-mapping>
<repository-link>
gsa1
</repository-link>
...
</cmp-mapping>
Each EJB must specify which repository view (item descriptor) in the repository will represent the EJB
instances:
<entity>
<ejb-name>
CMPPerson
</ejbname>
...
<repository-view-name>
ejbPerson
</repository-view-name>
...
</entity>
...
<entity>
<ejb-name>
CMP2Person
</ejbname>
...
<repository-view-name>
ejbCmp2Person
</repository-view-name>
...
</entity>
The next step is to map the each persistent field in the EJB to a property in the repository view. The EJB
container handles the datatype conversions between the values in the repository and the values of the
fields. For EJB 1.1 CMP, the EJB member variables are mapped to the properties of the corresponding
repository view. For example, the mapping for the mAge member variable of CMPPerson looks like this:
<field-mapping>
<field-name>
mAge
</field-name>
<property-name>
91
6 - Enterprise JavaBeans
age
</property-name>
</field-mapping>
...
For EJB 2.0 CMP, the properties of the EJB (not the member variables) are mapped to the properties of the
corresponding repository view, so the equivalent mapping for CMP2Person looks like this:
<field-mapping>
<field-name>
age
</field-name>
<property-name>
age
</property-name>
</field-mapping>
...
Finally, each EJB 1.1 finder method or EJB 2.0 query method must have a corresponding query that the
container uses to query the repository. For EJB 1.1 CMP, the query is defined in the
dynamoJ2EESpecifier.xml file, and is written using Dynamos repository query language (RQL). Note
that the finder query is defined in terms of the property names (e.g., age), not the names of the member
variables (e.g., mAge). For example, the finder query for the findBetweenAges method of CMPPerson is
defined like this:
<finder-method>
<method-name>
findBetweenAges
</method-name>
<finder-query>
<![CDATA[ age >= ?0 AND age <= ?1 ]]>
</finder-query>
</finder-method>
The ?x expressions refer to arguments of the method. For example, the findBetweenAges method has
two arguments, pLowAge and pHighAge. When the method is called, pLowAge will be substituted in place
of ?0, and pHighAge will be substituted in place of ?1. The query is enclosed in a CDATA section so the <
and > characters do not affect the parsing of the XML file.
For EJB 2.0 CMP, the query is defined in the ejb-jar.xml file, and is written using EJB-QL, the standard
query language defined in the EJB 2.0 specification. The query for the findBetweenAges method of
CMP2Person is defined like this:
<query>
<description>
92
6 - Enterprise JavaBeans
</description>
<query-method>
<method-name>
findBetweenAges
</method-name>
<method-params>
<method-param>
int
</method-param>
<method-param>
int
</method-param>
</method-params>
</query-method>
<ejb-ql>
<![CDATA[SELECT DISTINCT OBJECT(o) FROM CMP2Person o WHERE o.age >= ?1
AND o.age <= ?2]]>
</ejb-ql>
</query>
93
6 - Enterprise JavaBeans
The names of the item descriptors and database tables are automatically generated. You can modify the
SQL script to change the database table and column names, and you will probably need to change the
data types in the script to optimize them for your database and application.
If you modify the SQL script, you must also modify the repository definition file so the two files remain in
synch. For example, if you change the name of a database table in the
create_repository_tables.sql file, you must be sure to change it in the item descriptor definitions
in the _cmpRepository.xml file.
Its also a good idea to rename the files if you modify them, so your changes arent overwritten if you
build the application again. If you rename the _cmpRepository.xml file, you must also change the GSA
service definition in the dynamoJ2EESpecifier.xml file to reflect the new name.
Note that you cannot change the names of the item descriptors. When automatic mapping is specified
for an EJB, Dynamos J2EE container maps EJBs to the generated names of the item descriptors; if the
names have been changed, the mapping will not work. If you do change the names of the item
descriptors, you must remove the auto-mapping tags from the dynamoJ2EESpecifier.xml file and
manually map the fields. For example, you need to do this if you want your EJBs to use an existing
repository.
Darina also has a -cmp-repository-generate-all option that generates a repository definition file
and a SQL script for creating repository views and database tables for all CMP EJBs, regardless of whether
automatic mapping is specified.
94
6 - Enterprise JavaBeans
Notice that there is a Mapping checkbox for each field, so you can turn mapping on and off on a field-byfield basis. This is useful if you are using CMP for an EJB that has one or more nonpersistent fields (e.g., a
field that is computed from the value of other fields, or a field whose data is not serializable).
EJB Clustering
For applications that involve many application clients, Dynamo provides an EJB clustering system that
allows you to scale these applications over many servers. Dynamos EJB clustering system was designed
to meet the following goals:
Limit the additional latency required to use a cluster rather than pointing directly at a
single server
Limit the overhead on the network of managing and maintaining information about
the cluster
95
6 - Enterprise JavaBeans
Dynamos EJB clustering system is intended to be lightweight. Other EJB clustering systems impose a
great deal of network latency and overhead as they do things like multicast JNDI information to all nodes
in the cluster. Dynamos EJB clustering system avoids this overhead and focuses on providing lightweight
and reliable EJB clustering support.
Note: Dynamos EJB clustering system is intended for use with application clients only. It is not intended
to be used with other J2EE modules, such as web applications.
96
6 - Enterprise JavaBeans
Interface
Home Interface
97
6 - Enterprise JavaBeans
There are other types of applications for which the default load balancing strategy is not appropriate. In
those types of applications, a large number of inter-connected beans are being manipulated in many
threads. A visual user interface is an example of such an application. To support these kinds of
applications, you can change the default load balancing strategy to one where each application client
chooses a single server from the cluster. See the Lightweight Application Clients and EJB Clustering
section of the Application Clients chapter for information about how to specify this strategy.
Dynamo currently does not support transaction-based load balancing. The existing load balancing
strategies should be sufficient for many applications.
98
6 - Enterprise JavaBeans
Cluster Management
The Dynamo cluster management system is built on top of Suns JMX (Java Management Extensions)
technology. A JMX server runs on both cluster managers and cluster nodes. For more information about
JMX, visit http://java.sun.com/products/JavaManagement/.
Currently, the cluster management system uses SOAP-based services to handle communication between
managers and nodes. This strategy may change in the future. Several other Java Specification Requests
designed to fill this node are in development, and we may plug these requests into the cluster
management system at a later date. We do not currently support the use of third-party tools to invoke
these JMX interfaces.
For more information about SOAP, visit http://www.w3c.org/.
JMX
Cluster Manager
JMX
Application Client
Cluster Node
Session Backup
Application Client
Cluster Node
Session Backup
RMI
Cluster Manager
The Cluster Manager is a Dynamo instance that manages information about the EJB cluster. The Cluster
Manager maintains information about the J2EE applications available in that server and the availability of
that server.
The Cluster Manager polls each server at a configurable interval and uses the collected information, in
conjunction with the cluster policy, to summarize the state of the cluster. The Cluster Manager serves this
information to application clients or servers that intend to use the cluster.
99
6 - Enterprise JavaBeans
Cluster Node
A Cluster Node is an individual Dynamo Server. It must be running every J2EE application at the version
required by the cluster policy. Cluster Nodes are added to the cluster either explicitly via the
ClusterManager, or they can dynamically register themselves with the cluster.
Application Client
An application client is either a J2EE application client module or a standalone application. The
application client is configured with a list of cluster managers. When the application client first creates a
JNDI InitialContext, a thread is started in the application client. This thread polls the Cluster Manager at
configurable intervals to retrieve information about the cluster.
Property
Description
enabled
initialClusterNodes
Example:
initialClusterNodes+=http://machinea.atg.com:8830/
ejbClusterManagement,
http://machineb.atg.com:8830/ejbClusterManagement
100
6 - Enterprise JavaBeans
availabilityTolerance
Example:
availabilityTolerance=2
Property
Description
requiredApplicationNames
The version number of the .dar file is updated and printed to the console whenever you use the
runDarina command to build or update your .dar file, unless you have also specified one of the quiet
options, (-q or Q). The version number changes each time runDarina processes it, even if you have
made no changes to the application. To check the version of an existing .dar file without updating it, use:
runDarina dar-version dar-file
An application run from a stage directory will report a version number of zero to the cluster manager. You
may still use clustering in this case. Set the relevant element of the requiredDarVersions property to 0,
but keep all the stage directories in perfect synchronization to avoid subtle versioning problems.
The ClusterManager also uses the /atg/dynamo/service/management/DynamoInfoCollector
service to collect information about each cluster node. You can configure the following properties on this
service to control how this information is collected:
101
6 - Enterprise JavaBeans
Property
Description
basicAuthenticationUsername
basicAuthenticationPassword
socketConnectTimeout
socketSoTimeout
Action
Description
102
6 - Enterprise JavaBeans
If a cluster node becomes unavailable that is, the cluster manager cannot poll the node successfully
within the required period, perhaps due to network problems or heavy load on the node the cluster
manager uses the entry for this node from the previous frame and notes that the node was missing. The
availabilityTolerance property controls the number of consecutive attempts that the cluster
manager makes before removing the node from the cluster. The cluster manager continues to poll the
node even after it has been removed from the cluster. If the node begins to respond again, the cluster
manager adds it back to the cluster and resets its availability count.
If a cluster node can be polled successfully but does not meet the requirements of the cluster definition,
then the cluster lists the node, but the nodes isAvailable flag is set to false.
Removing a node from the cluster manager does not guarantee that nodes or app clients will stop using
the node. An app client that already has a reference to an EJB from the removed node may continue to
use the node. The effect is to remove the node from the list of nodes the cluster manager advertises as
available.
Adding a node with this interface does not immediately make it available. The node becomes available
only when the manager polls it successfully and determines that it meets the requirements of the cluster
definition.
Set the property initialClusterNodes to point to the ejbClusterManagement service on each of the
Dynamos that are in the cluster. For example, if you plan to run two cluster nodes on machines
machinea.atg.com and machineb.atg.com, then set the following:
initialClusterNodes=http://machinea.atg.com:8830/
ejbClusterManagement,
http://machineb.atg.com:8830/ejbClusterManagement
To launch a Dynamo server with a Cluster Manager, run the following command from your
<DAS6dir>/home directory.
bin/startDynamo -m J2EE-Examples.ClusterEJB.ClusterManager
103
6 - Enterprise JavaBeans
Property
Description
enabled
Example:
enabled=true
providerURL
Example:
providerURL=http://cluster-managerhostname:8830/ejbClusterManagement
clientProviderURL
Example:
clientProviderURL=http://cluster-nodelocalhost:8830/ejbClusterManagement
104
6 - Enterprise JavaBeans
joinClusterOnStartup
Example:
joinClusterOnStartup=true
departClusterOnShutdown
Example:
departClusterOnShutdown=true
departOnlyAutoJoinedClusterManagers
Boolean. Set
departOnlyAutoJoinedClusterManagers to true
105
6 - Enterprise JavaBeans
intervalBetweenRetriesOnJoin
clusterPollingInterval
clusterSecurityCredentials
clusterSecurityPrincipal
securityCredentials
securityPrincipal
106
6 - Enterprise JavaBeans
Set the property providerURL to point the Cluster Manager. For example:
providerURL=http://localhost:8830/ejbClusterManagement
To run a cluster node that includes the ClusterEJB J2EE application, run the following command from
the <DAS6dir>/home directory:
bin/startDynamo -m J2EE-Examples.ClusterEJB.ClusterNode
Note: When you first start a cluster, the cluster manager will try to communicate with each node in the
cluster and each node will in turn try to communicate with the cluster manager. If some of the services
with which they are trying to communicate are not yet running, you may receive warning messages on
the console. The ClusterClientService component may tell you that a retryable error occurred while
trying to receive ClusterInfo from the cluster manager, and the Cluster Manager may tell you that it
could not retrieve DynamoInfo from a particular cluster node. These messages should disappear once all
the members of the cluster are running. If, after five to ten minutes (depending on the size of the cluster),
these warnings persist, then you should check the Dynamo instances identified in the message to make
sure they are running and are configured correctly.
Property
Description
backingUpSessions
useSessionBackupServerHostName
useSessionBackupServerPort
107
6 - Enterprise JavaBeans
allowedRestorationAddresses
When general session backup is switched on in Dynamo, EJB session backup is switched on as well. Only
stateful session beans that have been labeled for session backup are backed up when session backup is
enabled in Dynamo.
The SessionBackupClient also has the following properties, which are not inherited from the general
Dynamo configuration:
Property
Description
dictionaryClientAddress
Use this property to specify a different address for the local end
of the socket if you have more than one network card.
socketFactory
clientPoolSize
waitForConfirmation
This property indicates whether the backup client will wait for
confirmation from the dictionary server when the client is
backing up a stateful session bean. The default is true.
108
6 - Enterprise JavaBeans
7 Application Clients
Application clients are complete Java applications that are packaged into a J2EE application. An
application client runs within an application client container, in a VM that is separate from the main
Dynamo server processes, and typically interacts remotely with Enterprise JavaBeans on the server. An
application client can be a graphical interface to the business logic on the server, or a command-line
maintenance utility for use by system operators, or a batch utility run by a separate scheduler, etc.
Even without the use of application clients, Java applications can be written to interact with EJBs on other
servers (see Lightweight Application Clients at the end of this chapter). However, developing and
packaging an application as a J2EE application client has some advantages:
The application can link to EJBs back on the server using the same ejb-ref and ejblink tags that other J2EE elements use. The container takes care of establishing the
right RMI connections, JNDI factories, etc.
The application can use the containers resource factories, such as JDBC data sources,
without having to create and manage those resources in its own code.
The application can be developed, verified, and packaged the same way as all other
elements of the J2EE application.
This chapter does not discuss the details of writing an application client. The basic mechanics of writing,
packaging, deploying, and running an application client are discussed in the Creating a Sample J2EE
Application chapter of this manual. This chapter concentrates on configuring and deploying application
clients.
109
7 - Application Clients
At deployment time, any unresolved references must be filled in using the dynamoJ2EESpecifier.xml
file. As with other J2EE components, environment entries may be filled in at this point, as can EJB
references.
Resource references, such as JDBC Data Sources and JavaMail Sessions, must also be resolved. Unlike
other J2EE components, these references cannot be resolved by pointing them at Nucleus components.
This is because these Nucleus components reside on the server and are inaccessible to an application
client in a different VM. Instead, these resource references must be resolved as application resources.
Once the J2EE application has been deployed successfully, both the server and application client can be
run. The server must be started first. Once the server is running, multiple instances of the application
client can be started and stopped.
The application client is run using a script called <DAS6dir>/home/bin/runAppClient. This script must
be passed several arguments, including:
the name of the application client in the J2EE application (a J2EE application may
contain several application clients)
Note that the runAppClient script requires that the Dynamo server is installed and running on the same
machine as the application client. To run an application client on a different machine from the server, see
Running an Application Client Remotely.
<jdbc-service>
<resource-service-name>
110
7 - Application Clients
jdbc1
</resource-service-name>
<jdbc-lookup>
DriverManager
</jdbc-lookup>
<jdbc-url>
jdbc:solid://localhost:1313
</jdbc-url>
<jdbc-driver-class>
solid.jdbc.SolidDriver
</jdbc-driver-class>
<min-pool-size>
10
</min-pool-size>
<max-pool-size>
10
</max-pool-size>
<max-pool-free>
10
</max-pool-free>
<resource-username>
admin
</resource-username>
<resource-password>
admin
</resource-password>
</jdbc-service>
See Mapping Resource References in the Dynamo and J2EE chapter for more details.
Another approach is to resolve the JDBC reference using the resource-name and jdbc-res-conf tags:
<app-client>
<module-uri>
appclient
</module-uri>
...
<resource-ref>
<res-ref-name>
jdbc/db1
</res-ref-name>
<resource-name>
jdbc:solid://localhost:1313
</resource-name>
<jdbc-res-conf>
<jdbc-lookup>
DriverManager
111
7 - Application Clients
</jdbc-lookup>
<jdbc-driver-class>
solid.jdbc.SolidDriver
</jdbc-driver-class>
<res-ref-username>
bob
</res-ref-username>
<res-ref-password>
secret
</res-ref-password>
</jdbc-res-conf>
</resource-ref>
</app-client>
JDBC 1.0-style uses a driver class and a JDBC URL. This is the style used by all preJDBC 2.0 drivers and many JDBC 2.0 drivers that depend on the DriverManager to
create JDBC connections.
JDBC 2.0-style, on the other hand, uses a vendor-specific JNDI name to gain access to
the driver. Not all JDBC 2.0 drivers automatically use this style - in fact, many still use
the DriverManager approach, or offer both styles. The JDBC drivers documentation
should indicate which style of access should be used.
resource-name
If JDBC 1.0-style driver access is being used, then this is the JDBC URL string that is used to gain access to
the driver. This string varies from database to database and driver to driver. If JDBC 2.0-style driver access
is being used, this field should contain the JNDI name used to gain access to the driver.
jdbc-lookup
If JDBC 1.0-style driver access is being used, then the value of this field should be DriverManager. If JDBC
2.0-style driver access is being used, then the value of this field should be JNDI.
jdbc-driver-class
This field is only specified if JDBC 1.0-style driver access is being used. If so, then the full class name of the
driver should be specified.
res-ref-username
If the application clients deployment descriptor specifies a res-auth of Container, then this field must
be filled in with the username to be used when connecting to the database. If res-auth is not
Container, then this field should not be supplied, since the client is expected to supply the username
and password in code.
112
7 - Application Clients
res-ref-password
If the application clients deployment descriptor specifies a res-auth of Container, then this field must
be filled in with the password to be used when connecting to the database. If res-auth is not
Container, then this field should not be supplied, since the client is expected to supply the username
and password in code.
<app-client>
<module-uri>
appclient
</module-uri>
...
<resource-ref>
<res-ref-name>
mail/mailer1
</res-ref-name>
<mail-transport-protocol>
smtp
</mail-transport-protocol>
<mail-store-protocol>
pop
</mail-store-protocol>
<mail-host>
mail.mycompany.com
</mail-host>
</resource-ref>
</app-client>
The mail-transport-protocol field is optional, and presently can only be set to smtp. The mailstore-protocol field is also optional and presently can only be set to pop. The mail-host field
contains the address of the mail server to be contacted by the session.
113
7 - Application Clients
Argument
Description
dar-file
options
For example, the command to run the default application client in the simpleJ2EE application using IIOP:
bin/runAppClient ../J2EE-Examples/SimpleJ2EE/j2ee-apps/simpleJ2EE.dar
-module-name default orb-host localhost orb-port 8820
114
7 - Application Clients
Option
Description
-cluster-managers
cluster-managers
http://localhost:8830/ejbClusterManagement
-connect-timeout
The ClusterEJB demo that accompanies Dynamo comes with a J2EE application client module that
communicates with each of the beans in the cluster.
To run the application client module, use the runAppClient script from the <DAS6dir>/home directory:
bin/runAppClient ../J2EE-Examples/ClusterEJB/
j2ee-apps/clusterEJB.dar module-name default cluster-managers
http://cluster-manager-host:8830/ejbClusterManagement
-connect-timeout 50000 -read-timeout 25000
The next time you try to look up a bean in the cluster, the collector thread will be restarted.
115
7 - Application Clients
contents depending on your applications needs. These files are in the <DAS6dir>/J2EE-AppClients
directory.
import java.rmi.*;
import javax.naming.*;
import javax.rmi.*;
import javax.ejb.*;
import atg.simpleJ2EE.*;
public class SimpleJ2EETestClient
{
public static void main (String [] pArgs)
throws NamingException,
RemoteException,
CreateException,
RemoveException
{
// Find the AddNumbersHome
InitialContext ctx = new InitialContext ();
AddNumbersHome addNumbersHome =
(AddNumbersHome)
PortableRemoteObject.narrow
(ctx.lookup ("simpleJ2EE/ejbs/AddNumbers"),
AddNumbersHome.class);
// Get an AddNumbers instance
AddNumbers addNumbers = addNumbersHome.create ();
// Determine the result
int result = addNumbers.addNumbers (18, 95);
116
7 - Application Clients
Dont place standalone clients in the J2EE application module or create them without a package. For
simplicitys sake, this source code appears in the module and has no package. We recommend, however,
that you place application clients in whatever package and source control structure the developer uses.
The code here is similar to any other code that gains access to an EJB. The biggest difference is the JNDI
name used for the EJB. Because standalone clients do not belong to the same J2EE application as the EJB,
they cannot use the java:comp/env namespace. Instead, they must use this convention to name the EJB:
{app name}/{module URI}/{ejb name}
The name of the application is specified in the applications dynamoJ2EESpecifier.xml file under the
application-name tag. In this case, the name of the application is simpleJ2EE.
The name of the EJB is specified in the EJBs ejb-jar.xml file, under the tag ejb-name. In this case, the
name of the EJB is AddNumbers, so the full JNDI name remote clients should use is
simpleJ2EE/ejbs/AddNumbers.
Note that for an EJB in an EJB 1.1 module, the JNDI name omits the module URI. In this case, the JNDI
name would be simpleJ2EE/AddNumbers.
You can override this naming convention by specifying an external-uri element in the
dynamoJ2EESpecifier.xml file for the EJB. For example:
<session>
<ejb-name>
AddNumbers
</ejb-name>
<external-uri>
adder
</external-uri>
</session>
This external-uri then becomes the JNDI name that you should specify:
AddNumbersHome addNumbersHome =
(AddNumbersHome)
PortableRemoteObject.narrow
(ctx.lookup ("adder"),
AddNumbersHome.class);
117
7 - Application Clients
Use this feature with care, since Dynamo does not enforce uniqueness of these names. In other words, it is
possible for two EJBs to have the same external-uri name, which would cause one of the EJBs to hide
the other.
The code does not specify the hostname and port of the remote server, but you can supply this
information in a number of ways.
Once you have written the code, you then compile the class. Compilation requires access to two
additional libraries. The class requires the standard J2EE library to supply classes such as javax.ejb.*,
javax.naming.*, and javax.rmi.*. The easiest way to find this library is to use the
<DAS6dir>/J2EEAPI/lib/classes.jar file, which contains the J2EE classes. You can also use any
compliant J2EE distribution library.
The second required library is the set of interfaces representing the EJB, such as AddNumbersHome and
AddNumbers. This library is called the EJB client JAR, and is formed by using Darina to extract the
appropriate classes from the SimpleJ2EE application. To do this, change to the <DAS6dir>/home
directory, then run Darina:
bin/runDarina ../J2EE-Examples/SimpleJ2EE/j2ee-apps/simpleJ2EE
-build -output-client-jar
../J2EE-Examples/SimpleJ2EE/j2ee-apps/simpleJ2EE-client-jar.jar
In most command line shells, you must enter the entire command on a single line. The command is
broken up here for clarity.
This example and others in this section use the UNIX forward slash (/) and colon (:) separator characters;
use the backslash (\) or semicolon (;) instead on Windows.
This is no different from running Darina normally, except that Darina will generate a second file,
simpleJ2EE-client-jar.jar, at the specified directory. This file contains all of the additional classes
needed to compile and run the client program (with the exception of the standard J2EE classes). This
includes the AddNumbersHome and AddNumbers classes, as well as a few required Dynamo-specific
classes. If there are multiple EJB modules in the J2EE application, all of the classes from all of those
modules will be collapsed into this single JAR file.
Once both libraries are ready, you can compile the class:
javac -classpath
../J2EEAPI/lib/classes.jar:../J2EE-Examples/SimpleJ2EE/j2ee-apps/
simpleJ2EE-client-jar.jar -d ../J2EE-Examples/SimpleJ2EE/j2ee-apps
../J2EE-Examples/SimpleJ2EE/j2ee-apps/SimpleJ2EETestClient.java
Once you compile the class, you can run it. First, make sure that Dynamo is running and hosting the EJB:
bin/startDynamo -m J2EE-Examples.SimpleJ2EE
118
7 - Application Clients
simpleJ2EE-client-jar.jar:../J2EE-Examples/SimpleJ2EE/j2ee-apps
-Djava.naming.factory.initial="atg.jndi.url.dynamoejb.RemoteEJBContext"
-Djava.naming.provider.url="rmi://localhost:8860/"
SimpleJ2EETestClient
This command should invoke the remote EJB and return the sum of 18 and 95.
The command line specifies a classpath with three elements. The first element is the classes.jar file
containing the standard J2EE classes. The second element is the client JAR file containing the interfaces
specific to Dynamo and the AddNumbers EJB. The third element is the directory containing the
SimpleJ2EETestClient itself.
The next portion of the command line defines a couple of system properties that use -D flags. The first
system property, java.naming.factory.initial, defines the name of the class that you should use to
produce a JNDI InitialContext. Do not change this value. The second system property,
java.naming.provider.url, specifies the server and port hosting the EJB. This allows you to point the
client at different servers without modifying the code.
The SimpleJ2EE application does not have any security declarations, so any EJB client can connect and
invoke methods. If the SimpleJ2EE application did specify security constraints, then the client program
must log in with a username and password. It can do this using the system property
java.naming.security.principal for the username and java.naming.security.credentials for
the password:
java classpath
../J2EEAPI/lib/classes.jar:../J2EE-Examples/SimpleJ2EE/j2ee-apps/
simpleJ2EE-client-jar.jar:../J2EE-Examples/SimpleJ2EE/j2ee-apps
-Djava.naming.factory.initial="atg.jndi.url.dynamoejb.RemoteEJBContext"
-Djava.naming.provider.url="rmi://localhost:8860/"
-Djava.naming.security.principal="admin"
-Djava.naming.security.credentials="adminpass"
SimpleJ2EETestClient
If these are specified, then when the client obtains a home interface, it will attempt to authenticate itself.
If it succeeds, then subsequent calls will be associated with the specified principal.
If you enter the system properties on the command line, then they will apply to the entire application.
This may not always be desirable since other parts of the application may wish to gain access to other
EJBs on other servers, or with different usernames and passwords. If this is the case, then you can set
these properties in the code:
119
7 - Application Clients
The difference here is that a Properties structure is created and passed to the InitialContext. You
then can invoke the client without using any -D arguments:
java -classpath
../J2EEAPI/lib/classes.jar:../J2EE-Examples/SimpleJ2EE/j2ee-apps/
simpleJ2EE-client-jar.jar:../J2EE-Examples/SimpleJ2EE/j2ee-apps
SimpleJ2EETestClient
This need not be an all or nothing choice. You can use D to set some properties and use the
Properties structure for others. Any properties you specify using the Properties structure will
override -D properties of the same name.
Description
java.naming.provider.url
java.naming.factory.initial
java.naming.security.principal
java.naming.security.credentials
atg.jndi.url.clusterejb.
cluster_security_principal
120
7 - Application Clients
atg.jndi.url.clusterejb.
cluster_security_credentials
atg.jndi.url.clusterejb.
cluster_polling_interval
atg.jndi.url.clusterejb.
cluster_client_strategy_class
For example, the ClusterEJB application includes a lightweight application client class,
atg.clusterEJB.StandaloneAppClient. You can run the client using this command:
java -Djava.naming.provider.url=
http://localhost:8830/ejbClusterManagement
-Djava.naming.factory.initial=
atg.jndi.url.clusterejb.ClusterEJBContext
classpath "../J2EE-Examples/ClusterEJB/j2ee-apps/clusterEJB
/clusterAppclient:../J2EE-Examples/ClusterEJB/j2ee-apps
/clusterEJB/ejbclient_clusterEJBs.jar:..
/J2EEAPI/lib/classes.jar:../DAS/lib/resources.jar"
atg.clusterEJB.StandaloneAppClient
import atg.jndi.url.clusterejb.ClusterSocketFactory;
..
121
7 - Application Clients
122
7 - Application Clients
8 J2EE Security
It allows Dynamo to deny access to certain pages or method calls unless the calling
user fits one of the roles declared by the application.
Getting these two functions to operate correctly in Dynamo requires the cooperation of several Dynamo
subsystems. The list of users must be kept in some data storage facility, which is accessed through a
repository. For example, the user list might be maintained in a database accessed by a SQL repository. The
repository must then be mapped to Dynamos security API through the use of a UserAuthority
implementation. Finally, the UserAuthority API must be mapped to a specified J2EE application
through declarations in the J2EE applications dynamoJ2EESpecifier.xml file.
123
8 - J2EE Security
J2EE Application
UserAuthority
Repository
SQL
LDAP
Where the security system is involved, the entire chain of data operates in a read-only mode. Data is
stored in the repository, which is queried by the UserAuthority, which is queried by the J2EE
application. However, reading security data is only half the story. An application must also be able to
manage the user database - create and remove users, add roles to users, remove roles from users, etc.
Managing the user database is a much more complex problem than simple authentication and access
control. Applications have widely varying needs in their storage and management of users, and there is
no generic solution that meets all needs. For example, one application might be used by only a few
people with a very simple management tool, while another application might serve thousands of internet
users, giving them the ability to manage their own application. It turns out that most developers would
much rather write the interfaces and code to manage an application-specific user database than rely on a
single management tool.
For this reason, Dynamos security system does not include a generic user management tool (although
there is one available for managing administrative users, described later). Instead, Dynamo strives to
make it easy for applications to write their own user management code.
There are several approaches an application can take to manage the user database. The first is to
manipulate the underlying data source directly:
J2EE Application
User Authority
Repository
SQL
In this case, the J2EE application might issue SQL commands directly to the database to perform any user
account manipulation. These changes would then be picked up by the repository and user authority,
which will act on those changes when new login or role requests arrive.
This approach is usually discouraged since it can get the application mired deep in SQL code - something
most developers want to avoid. In addition, changes made to the SQL database will not be picked up by
the repositorys caches, so the repository will have to run in a cacheless mode, thereby hurting
performance.
A second approach involves having the J2EE application communicate directly with the underlying
repository, issuing Repository API commands to manipulate the user database:
124
8 - J2EE Security
J2EE Application
User Authority
Repository
SQL
This approach has several advantages - it allows the component to use an abstract API to manipulate the
data, so that it doesnt have to be rewritten if the underlying data source changes. It also cooperates with
the repositorys caches, thereby improving performance.
The disadvantage to this approach is that it requires the J2EE application to call non-standard APIs (the
repository API is not a part of J2EE). This makes it more difficult to port the application to another
application server.
The final approach takes advantage of Dynamos entity EJB architecture. Dynamo implements containermanaged persistence for entity beans by storing EJB instances in a repository. Each EJB maps to an item
descriptor, and each instance field maps to a property of that item descriptor.
Using this approach, a J2EE application can manipulate the user database through entity EJBs. Then, by
configuring the EJBs to point at the same repository as the user authority does, these entity EJBs can
directly affect the security mechanism used by Dynamos J2EE infrastructure:
J2EE Application
User Authority
Entity EJB
Repository
SQL
CMP
The advantage to this approach is that it uses entity EJBs to manage users, so the application does not
need to call any nonstandard APIs. However, this approach may still make porting the application difficult,
because other application servers may use separate data stores for security and CMP.
125
8 - J2EE Security
<user-manager>
dynamo:/atg/dynamo/service/j2ee/J2EEUserAuthority
</user-manager>
<user-manager-link>myUserAuthority</user-manager-link>
...
<user-authority-service>
<resource-service-name>myUserAuthority</resource-service-name>
<gsa-service-link>myGSA</gsa-service-link>
<user-view>applicationUser</user-view>
<user-view-login-property>login</user-view-login-property>
<user-view-password-property>password</user-view-password-property>
<user-view-roles-property>groups</user-view-roles-property>
<role-view-role-name-property>name</role-view-role-name-property>
<password-hasher-name>
/atg/dynamo/security/DigestPasswordHasher
</password-hasher-name>
</user-authority-service>
userView - the name of the item descriptor representing a user. This property is
required.
descriptor that holds the users login name. This property is required.
descriptor that holds the users password. This property is not strictly required - if it
isnt specified, then users wont require a password in order to log in. However, it is
strongly recommended that sites require passwords.
that holds the users roles. The value of the property may be an array or collection of
126
8 - J2EE Security
Strings, representing the role names. The property might also be an array or collection
of repository items, where each item represents a role, and one property of that item
contains the roles name.
This property is optional. If it is omitted, then users will still be able to log in, but users
will appear to have no roles.
set of Strings, or as a set of repository items. If the latter, then this property will define
which property in the repository item represents the role name.
passwordHasher - the name of a Nucleus component that will hash passwords before
storing them in the repository. This prevents passwords from being stored in plain text
in the database, so that unauthorized access to the database will not result in access to
every users password. If plain text passwords are desired, this should be set to
NullPasswordHasher. If hashing through some digest algorithm (e.g., MD5) is
desired, this should be set to DigestPasswordHasher. This is described in the
Hashing Passwords section.
A UserAuthority defined as an application resource needs a reference to a SQLRepository. This
repository, too, can be defined as either a global resource or an application resource. To define a global
resource, use the pre-configured SQLRepository component in Nucleus:
<user-authority-service>
...
<gsa-service-link>myGSA</gsa-service-link>
...
</user-authority-service>
...
<gsa-service-instance>
<resource-service-name>myGSA</resource-service-name>
<resource-name>
dynamo:/atg/dynamo/service/jdbc/SQLRepository
</resource-name>
</gsa-service-instance>
<user-authority-service>
...
<gsa-service-link>myGSA</gsa-service-link>
...
</user-authority-service>
...
<gsa-service-instance>
<resource-service-name>myGSA</resource-service-name>
<repository-name>my.repository</repository-name>
<definition-file>sqlRepository.xml</definition-file>
127
8 - J2EE Security
<jdbc-resource-link>myJDBCDataSource</jdbc-resource-link>
</gsa-service-instance>
The details of configuration are described in the ATG 6 Repository Guide; however, an example will be
discussed later in the SQL Repository Configuration Example topic of this chapter.
The SQLRepository application resource definition also has a reference to a JDBC resource. Once again,
this JDBC resource can be defined as either a global resource or an application resource. To define a
global resource, use the pre-configured JTDataSource component in Nucleus:
<jdbc-service>
...
<resource-service-name>myJDBCDataSource</resource-name>
<resource-name>
dynamo:/atg/dynamo/service/jdbc/JTDataSource
</resource-name>
...
</jdbc-service>
<gsa-service-instance>
...
<jdbc-resource-link>myJDBCDataSource</jdbc-resource-link>
...
</gsa-service-instance>
...
<jdbc-service>
<resource-service-name>myJDBCDataSource</resource-service-name>
<jdbc-lookup>DriverManager</jdbc-lookup>
<jdbc-url>jdbc:solid://localhost:1313</jdbc-url>
<jdbc-driver-class>solid.jdbc.SolidDriver</jdbc-driver-class>
<min-pool-size>10</min-pool-size>
<max-pool-size>10</max-pool-size>
<max-pool-free>10</max-pool-free>
<resource-username>admin</resource-username>
<resource-password>admin</resource-password>
</jdbc-service>
In either case, the SQLRepository service will use a DataSource that pools and monitors connections
from another DataSource. The JTDataSource Nucleus component has properties like
loggingSQLWarning, loggingSQLInfo, and loggingSQLDebug which if set to true, will display
communication between Dynamo and the database.
By default, the JTDataSource is configured to point to
/atg/dynamo/service/jdbc/FakeXADataSource. This is a DataSource that uses a JDBC 1.1 driver to
point at a database. By default, the FakeXADataSource points at the Solid database that comes with
128
8 - J2EE Security
Dynamo for evaluation purposes. The DataSource can be changed by setting the driver, URL, user, and
password properties.
Note that this setup illustrates just one possibility for configuring the security system. This setup can be
changed to point to another type of repository, such as an LDAP data source. Or different applications
might be configured to point at different sets of users (often called domains in security parlance).
Setting up these alternate configurations requires a little more work, since new components must be
configured, but all of the previously-discussed principles remain the same.
Single Login
The J2EE specification states that once a user has been authenticated to one application, that users
identity is made known to all applications in the same container. For example, if Dynamo is running three
applications, and user bob logs in to one of those applications, then that application will associate the
principal bob with all requests from that user. But if the user moves to another application on the same
Dynamo, that Dynamo will also recognize the user as bob. This means that the user does not have to log
in separately to each application running on the Dynamo. Logging in to one application is as good as
logging into all applications.
However, this works only if all of those applications are using the same UserAuthority. If one of the
applications is using a different UserAuthority, then the user must log in separately to that application.
However, the user still remains logged in to the other applications.
So a user may log in to several applications at once, and if the user logs into an application driven by one
UserAuthority, then the user is automatically logged into any other applications that use the same
UserAuthority.
Logging Out
Most secure applications require the ability to let the user log out, which has the effect of dissociating any
security identity from the users session. This prevents someone else from using the users terminal and
gaining access to the users privileged information.
J2EE does not really have a logout mechanism that mirrors its login mechanisms. The best way to log a
user out programmatically is to invalidate the users session. This can be done by calling
HttpServletRequest.getSession().invalidate(). This has the effect of logging the user out of all
Web applications on that server, not just the application the user is currently accessing.
Note that this works best for form-based logins. If the user is logged in through information that is kept
on the browser, such as HTTP basic authentication information, then invalidating the server-side session
will not necessarily prevent the browser from automatically logging the user in again on the next request.
129
8 - J2EE Security
ApplicationUserAuthority. In addition, the application uses entity EJBs to add new users and roles to
the database. Note that because the same repository is used for user information and for EJB CMP, the
example must use an SQL repository and not an LDAP or other repository implementation.
This section does not explain the entire application in complete detail. Developers can glean the major
concepts from the explanation in this section, but should go through the example code themselves to get
the full detailed picture.
This example is meant to serve as a template for other applications that perform similar functions.
However, the Web interface is built in a quick-and-dirty fashion using servlets and tags that generate
HTML, and should not be considered exemplary. Developers should not use these interface techniques as
a model for good programming.
Darina will compile all of the applications source files, produce ejb-client-jar files, and create the
various RMI classes. When its finished, Darina will have produced a deployed file at ../J2EEExamples/Security/j2ee-apps/security.dar.
Once the application has been deployed, you can start it using the -m flag:
bin/startDynamo -m J2EE-Examples.Security
130
8 - J2EE Security
SECURITY_USER Table
ID
LOGIN_NAME
PASSWORD
admin
admin
SECURITY_ROLE Table
ID
ROLE_NAME
DESCRIPTION
admin
subscriber
SECURITY_USER_ROLE Table
USER_ID
ROLE_ID
Go back to the main page, then attempt to View content as a paid subscriber. A login form page should
appear, asking for a login name and password. Enter admin for the login name and admin for the
password, since that is the only account known to the system.
131
8 - J2EE Security
Unfortunately, the content page can only be viewed by a user with the subscriber role, which the
admin user does not have. So an error page will appear, refusing access to the page.
To get to the content page, a new user must be created with the subscriber role. To do this, go back to the
main page, then go to the Administration Page.
Notice that no login page is required to get to the administration page, even though that page is only
accessible to users with the admin role. Even though the previous login attempt failed to get into the
subscriber page, the system still remembers that the current user successfully logged in as admin, and so
has access to any pages requiring the admin role.
The administration page shows the users and roles currently in the system. Each user displays the roles
associated with that user, and each role displays the users associated with that role. Notice that users and
roles use an integer ID as their primary keys, rather than the login name or role name. In theory, because
login names and role names must be unique, they could also serve as primary keys. However, it is often a
good idea to use a separate field to represent a user or role ID to avoid complications if a login name or
role name has to change in the future.
Underneath the list of users and roles are two forms - one is used to create a new user, and the other is
used to create a new role. To create a new user, choose a unique ID number, a unique login name, and a
password. For example, 2, joe, and D6rules. The form also presents a set of checkboxes representing the
various roles that have been created in the system. If more roles are created using the Add New Role
form, those roles will appear in this list of checkboxes. The new user will be associated with any roles that
are checked. For the new joe user, check off both admin and subscriber, then click on Create New
User.
After creating the new user, return to the main page and attempt again to View content as a paid
subscriber. The login form will once again pop up. The system hasnt forgotten that the current user is
admin. However, since admin doesnt have access to the page, the system is giving a chance to login in as
a different user. So login as joe, with password D6rules. The system will now treat the current user as
joe, who does have the subscriber role, and can access the content page.
single user in the SECURITY_USER table. It has fields representing the ID,
LOGIN_NAME, and PASSWORD columns. It defines a finder method that finds a User
by primary key (ID, not LOGIN_NAME), and a finder method that finds all Users.
The UserAccountEJB also has a container-managed field of type Role[], which
represents the set of roles with which a user is associated. This association is kept in
the SECURITY_USER_ROLE table, which maintains the many-to-many mappings
132
8 - J2EE Security
between users and roles. This means that the data in a single UserAccount instance
might come from two tables - one row in the SECURITY_USER table, and possibly
many rows in the SECURITY_USER_ROLE table. Dynamos EJB facilities allow this sort of
configuration.
Role - Similar to the UserAccount EJB, this EJB represents a role from the
SECURITY_ROLE table, along with any associated UserAccounts as read from the
SECURITY_USER_ROLE table.
admin user. It uses JDBC directly, wired through the Dynamo J2EE Specifier to get
connections from the JTDataSource and remove all rows from the SECURITY_...
tables. It then uses the above entity EJBs to create the admin and security roles, and
the admin user.
AddNewUserServlet - This servlet reads the form inputs from the Add New User form
on the administration page, and creates a new UserAccount EJB. This also associates
the new user with any Roles that have been entered through the checkboxes.
AddNewRoleServlet - This servlet reads the form inputs from the Add New Role form
The JSPs use the ATG Core tag library, plus an additional tag library containing the following special tags.
Note that these tag implementations are not meant to be taken as a good Web programming technique
(they generates HTML directly and violate several other good JSP guidelines), but are provided in this
quick and dirty format to simplify the example:
administration page.
administration page.
form.
<security-constraint>
<web-resource-collection>
<web-resource-name>
adminPages
</web-resource-name>
<url-pattern>
/admin.jsp
</url-pattern>
133
8 - J2EE Security
<url-pattern>
/AddNewRole
</url-pattern>
<url-pattern>
/AddNewUser
</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>
Administrator
</role-name>
</auth-constraint>
</security-constraint>
...
<security-role>
<role-name>
Administrator
</role-name>
</security-role>
Note that protected pages can be specified individually (/index.jsp), or as a URL pattern (/content/*).
Developers should be careful when protecting a large area to make sure that guest users or other
necessary users are not somehow locked out of a common area.
The web.xml file also declares how users will log in. In this case, login is performed through a form:
<login-config>
<auth-method>
FORM
</auth-method>
<form-login-config>
<form-login-page>
/security/login.jsp
</form-login-page>
<form-error-page>
/security/loginFailed.jsp
</form-error-page>
</form-login-config>
</login-config>
<resource-ref>
<res-ref-name>
134
8 - J2EE Security
jdbc/db
</res-ref-name>
<resource-link>
securityDataSource
</resource-link>
</resource-ref>
...
<jdbc-service>
<resource-service-name>
securityDataSource
</resource-service-name>
<jdbc-lookup>
DriverManager
</jdbc-lookup>
<jdbc-url>
jdbc:solid://localhost:1313
</jdbc-url>
<jdbc-driver-class>
solid.jdbc.SolidDriver
</jdbc-driver-class>
<min-pool-size>
10
</min-pool-size>
<max-pool-size>
10
</max-pool-size>
<max-pool-free>
10
</max-pool-free>
<resource-username>
admin
</resource-username>
<resource-password>
admin
</resource-password>
</jdbc-service>
The Dynamo J2EE Specifier also maps the role names used in the application (Administrator and
ContentSubscriber), to the role names stored in the database (admin and subscriber):
<security-role>
<role-name>
Administrator
</role-name>
<security-group>
admin
</security-group>
</security-role>
135
8 - J2EE Security
<security-role>
<role-name>
ContentSubscriber
</role-name>
<security-group>
subscriber
</security-group>
</security-role>
Next, the application must be told which UserAuthority it will use. This configuration indicates which
item descriptors and properties contain the information required to handle login and role membership
requirements. Users are declared to be stored in the userAccount item descriptor, with properties
loginName, password, and roles. The roles property is expected to point to a collection of repository
items, each of which contains a property called roleName:
<user-manager-link>
securityUserAuth
</user-manager-link>
...
<user-authority-service>
<resource-service-name>securityUserAuth</resource-service-name>
<gsa-service-link>securityRepository</gsa-service-link>
<user-view>userAccount</user-view>
<user-view-login-property>loginName</user-view-login-property>
<user-view-password-property>password</user-view-password-property>
<user-view-roles-property>roles</user-view-roles-property>
<role-view-role-name-property>roleName</role-view-role-name-property>
</user-authority-service>
Finally, the EJB configuration specifies that the EJBs use the securityRepository for CMP, and maps
each EJB to an Item descriptor (repository view), each field to a repository property, and each finder
method to an RQL or EJB-QL query. For example:
<entity>
<ejb-name>
UserAccount
</ejb-name>
<cmp-mapping>
<repository-link>
securityRepository
</repository-link>
<repository-view-name>
userAccount
</repository-view-name>
136
8 - J2EE Security
<read-only>
False
</read-only>
<field-mapping>
<field-name>
mId
</field-name>
<property-name>
id
</property-name>
</field-mapping>
...
</cmp-mapping>
<finder-method>
<method-name>
findByPrimaryKey
</method-name>
<finder-query>
<![CDATA[ id = ?0 ]]>
</finder-query>
</finder-method>
...
</entity>
For more information about configuring CMP, see the Container-Managed Persistence section of the
Enterprise JavaBeans chapter.
<item-descriptor name="userAccount">
<table name="SECURITY_USER"
type="primary"
id-column-name="ID">
<property name="id"
column-name="ID"
data-type="int"/>
<property name="loginName"
137
8 - J2EE Security
column-name="LOGIN_NAME"
data-type="string"/>
<property name="password"
column-name="PASSWORD"
data-type="string"/>
</table>
...
Recall that the UserAccount EJB requires another property called roles, which points to the Roles
associated with a user. In the repository, this is expressed as a multi property whose type is another item
descriptor, and is configured like this:
<table name="SECURITY_USER_ROLE"
type="multi"
id-column-name="USER_ID">
<property name="roles"
column-name="ROLE_ID"
component-item-type="role"
data-type="set"/>
</table>
It should be clear now that configuring an application to work with the Dynamo security system is not a
trivial process. It is also not a forgiving process - if something is configured wrong, its very possible that
the application will simply not allow logins, and will not say why. Deployers should be very careful when
configuring the security system, consulting the above example to make sure that all of the proper links
are made in all the required files.
Hashing Passwords
In the above example, passwords are stored in plain text in the database. While this works fine, it does
represent a security risk since someone who somehow gains unauthorized access to the database can
retrieve the passwords of every user in the system.
One solution to this problem is to hash passwords before putting them into the database. Hashing is a
way to perform a one-way transformation on a password, turning the password into another String,
called the hashed password. One-way means that it is practically impossible to go the other way - to
turn the hashed password back into the original password. There are several mathematically complex
hashing algorithms that fulfill these needs - MD5 is one of those algorithms, and is the one that is used
by default in Dynamo.
So by hashing passwords before they go into the database, the passwords are protected even if the
database is compromised. The passwords are stored in a form that does not allow the actual password to
be retrieved. When a user enters a password while attempting to log in, the password is run through the
same hashing function before being compared against the hashed password in the database. This allows
138
8 - J2EE Security
the system to check an entered password against the hashed version in the database, even though the
actual password cannot be retrieved from the database.
Dynamos architecture allows password hashing to be enabled with a few minor configuration changes,
and with no changes to code. An example of password hashing can be found in the module
HashedSecurity, which is identical to the Security module except that hashing is enabled. The
hashing can be demonstrated by deploying the HashedSecurity module, then running Dynamo with -m
J2EE-Examples.HashedSecurity.
To use password hashing, set the passwordHasher property of the user authority to point to a password
hashing component. If the UserAuthority is defined as a global resource, you set this property in the
properties file of the UserAuthority component. If the user authority is defined as an application
resource, you set the property as part of creating the resource definition for the UserAuthority in the
dynamoJ2EESpecifier.xml file. For example:
<user-authority-service>
...
<password-hasher-name>
/atg/dynamo/security/DigestPasswordHasher
</password-hasher-name>
...
</user-authority-service>
The DigestPasswordHasher will hash passwords using the MD5 algorithm, followed by converting the
digest to a hexadecimal form. The details of this can be configured in the DigestPasswordHasher. See
the ATG 6 Personalization Programming Guide for more information about password hashing.
The SQL repository allows an application to specify properties that are filters for other properties. These
filtering properties are not connected with a database column. They are instead connected with an
underlying property, which itself may be connected with a database column. When an application writes
a value to a filtering property, the property is transformed by a Java object, then submitted to the
underlying property. The reverse happens when the application reads a value - the value is read from the
database into the underlying property, then transformed through the Java object and appears in its
transformed state to the application.
abc
Application
cba
filtering property
cba
underlying property
database
In the case of hashed passwords, the filtering Java object will hash a password written to it before sending
it to the underlying property. However, the object performs no transformation when reading the value
from the underlying property (since it is practically impossible to undo the hashing transformation).
So when a password value is written through an entity EJB to the password property, it is hashed by the
Java object. For example, a password of admin will be hashed into
21232f297a57a5a743894a0e4a801fc3. This hashed value is then written to the hashedPassword
property, which in turn is written to the PASSWORD column in the database:
139
8 - J2EE Security
admin
21232f
Entity EJB
password
21232f
hashedpassword
PASSWORD
On the other hand, when the security system reads the password property, it will actually get back the
hashed version of the password since the property is not transformed on reading:
21232f
Security System
21232f
password
21232f
hashedpassword
PASSWORD
Fortunately, the security system needs to see the hashed version of the password, since the security
system will be comparing that value against a hashed version of whatever password the user entered to
log in.
In the sqlRepsitory.xml file, this is configured by first changing the name of the password property to
hashedPassword. Then a new password property is created, which uses the Java object
PasswordPropertyDescriptor to do its transformations, directing the results to the hashedPassword
<item-descriptor name="userAccount">
<table name="SECURITY_USER"
type="primary"
id-column-name="ID">
...
<property name="hashedPassword"
column-name="PASSWORD"
data-type="string"/>
</table>
...
<property name="password"
property-type="atg.repository.PasswordPropertyDescriptor">
<attribute name="hashedProperty"
value="hashedPassword"/>
<attribute name="passwordHasher"
bean="/atg/dynamo/security/DigestPasswordHasher"/>
</property>
</item-descriptor>
One word of caution regarding password hashing - once a decision has been made to hash passwords
using a particular hashing algorithm (or with the default MD5 algorithm), it is very difficult to change that
decision. If hashing is later turned off or a new algorithm chosen, then all of the passwords currently in the
database will suddenly become invalid because they were hashed with the wrong algorithm. Worse yet,
because of the one-way nature of the hashing algorithms, it is impossible to extract the original
140
8 - J2EE Security
passwords so that they can be re-hashed under the new scheme. So the best advice is to choose whether
to hash or not very early on, and not change that decision.
Finally, the hashing algorithm is not a secret. In fact, it is possible that systems outside of Dynamo may
wish to insert users into the same database used by Dynamo, in which case, those external systems will
need to know how to hash passwords as well. The following is a Java code snipped that illustrates how to
produce hashed passwords the same way that the default system does:
import java.security.*;
...
MessageDigest md = MessageDigest.getInstance (messageDigestAlgorithmName);
byte [] source = new byte [originalPassword.length ()];
originalPassword.getBytes (0, source.length, source, 0);
byte [] digest = md.digest (source);
char [] digestChars = new char [digest.length];
char [] hexChars =
{ '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
for (int i = 0; i < digest.length; i++) {
digestChars [i * 2] = hexChars [(int) ((digest [i] 4) & 0xf)];
digestChars [(i * 2) + 1] = hexChars [(int) (digest [i] & 0xf)];
}
String hashedPassword = new String (digestChars);
The algorithm does little more than invoke the standard MD5 algorithm, then convert the resulting byte
array to hexadecimal.
Administrative Users
Earlier it was mentioned that applications are responsible for storing and maintaining their own users,
and that the security system would interface with whatever schema is used by the application.
Dynamo is itself an application with its own security needs. For example, the HTML Component Browser
requires a security system in order to restrict access to those who have the proper username/login
configuration. Dynamos development and deployment tool, the ATG Control Center, has even richer
security requirements. ACC users are able to change applications, change system configurations, manage
marketing campaigns (if Dynamo Scenario Server is installed), affect store catalogs, change site content,
etc. Because all of these functions are performed by the same tool, the security mechanism must have a
notion of roles or privileges to allow users to only access those functions to which they are entitled.
Dynamo defines the schema by which it maintains these administrative users. Dynamo also includes,
through the Admin window of the ATG Control Center, an interface that allows an administrator to
maintain this list of users, creating and removing users, and adding or removing roles and privileges.
A J2EE application may elect to base its security on this list of users instead of requiring its own schema
and user manipulation tools. If so, the J2EE application should point its user-manager (in the
141
8 - J2EE Security
system may have been configured to use a repository-based administrative user authority, found at
/atg/dynamo/security/RepositoryAccountManager. The details of these user authorities are
142
8 - J2EE Security
The following is a list of the command-line options that may be passed to the runDarina command:
Option
Description
-dar-version {dar-file-name}
Print DAR version number of DAR file to the screen and exit.
-no-dar
-debug
-o {output-dar-file-name}
-compiler,javac {command}
-no-java-src
Filter out all Java source files (files ending in .java) from the
module JARs when creating the final DAR file.
-stage-dir {stage-dir-name}
-server {server-name}
-q
-Q
-build
Recompile any source files that are out of date with respect to
their corresponding class files.
143
Appendix A: Darina Command Options
-buildall
-m {modules}
-jsp-compile
-jsp-compile-config-path
{config-path}
-cmp-repository-generate-all
Generate a SQL repository definition file for all EJBs that use
container-managed persistence, regardless of whether
automatic mapping is specified.
-max-table-name-length
{number-of-chars}
-regen
-output-client-jar
{client-jar-name}
-iiop
-rmi
-merge-ejb-class-loaders
-separate-ejb-class-loaders
Dont allow EJB modules to share classes. EJB client JARs must
be self-contained to be built.
-unpack-rar-subjars
{jar-path-names}
144
Appendix A: Darina Command Options
Dynamo includes several different JMS providers. The Dynamo Message System, discussed in the ATG 6
Dynamo Programming Guide, has two JMS providers, SQL JMS and Local JMS. However, these providers do
not support the complete JMS API, so in addition, Dynamo includes the Sun JMS Reference
Implementation. You should use the JMS Reference Implementation, for example, if your J2EE
applications include any message-driven beans.
This appendix discusses some aspects of using the JMS Reference Implementation. For more information,
see http://java.sun.com/products/jms/.
145
Appendix B: Sun JMS Reference Implementation
Database Tables
This section describes the database tables used by the Sun JMS Reference Implementation. These tables
must be installed in your database if you are using the Reference Implementation. See the ATG 6
Installation and Configuration Guide for Dynamo Application Server for information about installing these
tables:
sun_jms_message
sun_jms_dest
sun_jms_dur_sub
sun_jms_unack_msg
sun_jms_message
The table used to persist JMS messages.
Column
Data Type
Constraint
msg_id
VARCHAR(256)
NOT NULL
VARCHAR(256)
NOT NULL
VARCHAR(256)
NULL
LONG VARBINARY
NULL
sun_jms_dest
The destination table used to persist the list of destinations.
Column
Data Type
Constraint
dest_name
VARCHAR(256)
NOT NULL
INT
NOT NULL
146
Appendix B: Sun JMS Reference Implementation
max_messages
INT
NULL
INT
NULL
sun_jms_dur_sub
The table used to contain the list of durable subscribers.
Column
Data Type
Constraint
client_id
VARCHAR(256)
NOT NULL
VARCHAR(256)
NOT NULL
VARCHAR(256)
NULL
VARCHAR(256)
NOT NULL
CHAR
NULL
sun_jms_unack_msg
The table used to hold the unacknowledged messages.
Column
Data Type
Constraint
msg_id
VARCHAR(256)
NOT NULL
VARCHAR(256)
NOT NULL
147
Appendix B: Sun JMS Reference Implementation
subscription_name
VARCHAR(256)
NOT NULL
INTEGER
NOT NULL
VARCHAR(256)
NULL
148
Appendix B: Sun JMS Reference Implementation
Index
A
administrative users, 141
application clients
configuring timeouts, 121
developing, 109
J2EE modules, 114
resource references, 110, 113
running, 27, 114
standalone, 116
application resources, 6, 62
applications
building, 22, 27
debugging, 13
developing, 14, 19
J2EE modules, 21
monitoring, 13, 27
reloading, 28
running, 13, 22, 26
runtime directory, 30
structure, 21
B
building applications, 22, 27
deployment editor, 61
running Darina, 22
C
clients. See application clients
cluster manager, 99
administration, 102
configuration, 100
cluster nodes, 100
configuration, 104
clustering EJBs, 95
command options for Darina, 143
communications protocols
IIOP, 77
RMI, 77
compiler
Java, 36
connectors, 67
container-managed persistence (CMP), 9, 87
automatic mapping, 93
configuring, 89
mapping EJB fields to properties, 88
D
DAR files
creating, 12
Darina, 22
command options, 143
running, 10
staging directory, 10
data source. See JDBC data source
database tables
JMS, 146
debugging applications, 13
demo applications
security example, 130
deploying applications
assembling EAR files, 9
deployment editor, 49, 53
running Darina, 10, 22
staging directory, 10
deployment descriptors
deployment editor, 44
EJB references, 73
deployment editor, 49
adding elements to applications, 55
building applications, 61
deployment descriptors, 44
developing applications, 54
file transfer, 57
installing applications, 53
overview, 49
resource references, 62
running applications, 61
standalone modules, 61
template applications, 55
text editor, 59
validating applications, 60
developing applications, 14, 19
adding new elements, 55
standalone modules, 62
DSP tag library, 40
DSPEL tag library, 40
Dynamo and J2EE, 3
Dynamo Archive files. See DAR files
Dynamo J2EE Specifier file
creating, 10
filling in, 11
149
Index
Dynamo request, 38
Dynamo services
Nucleus components, 3
repositories, 4
E
EAR files
assembling, 9
EJBs
accessing from Nucleus components, 87
cluster management, 99
cluster manager administration, 102
cluster manager configuration, 100
cluster nodes, 100, 104
clustering, 95
communications protocols, 77
container-managed persistence, 9
EJB references, 73
environment entries, 75
failover, 98
field types for CMP, 88
finder methods, 9
IOR Security, 77
JNDI and clustering, 96
load balancing, 97
loading and storing data, 81
overview, 71
passivating, 83, 85
pooling, 83
security, 80
session backup server, 100
stubs and clustering, 97
transaction management, 78
Enterprise Archive files. See EAR files
environment entries, 68
Web applications, 68
external build tree, 33
external source tree, 31
F
failover
configuration, 107
session backup, 107
failover of EJBs, 98
file transfer
deployment editor, 57
filters, 41
example, 42
processing, 38
finder methods, 9
RQL statements, 92
G
global resources, 6, 62
GSA repositories. See repositories
H
hashing passwords, 138
I
IIOP, 77
IOR Security, 77
installing applications
DAR files, 53
EAR files, 53
standalone modules, 62
internal source tree, 35
IOR Security, 77
J
J2EE modules, 21
J2EE projects, 20
J2EE security. See security
Java compiler
specifying, 36
Java Connector Architecture, 67
JavaMail
resource references, 66, 113
JDBC
connection pools, 63
data sources, 64, 128
resource references, 110
JMS, 145
database tables, 146
L
logging in to Web applications, 129
logging out of Web applications, 129
M
mapping resource references, 6, 62
monitoring applications, 13, 27
N
Nucleus components
overview, 3
P
passivating EJBs, 83, 85
password hashing, 138
pooling EJBs, 83
R
RAR files, 67
reloading applications, 28
command-line tools, 30
repositories
150
Index
configuration, 8
configuring for security, 137
mapping resource references, 7
overview, 4
repository items, 5
resource references, 65
RQL, 9, 92
security architecture, 127
SQL repositories, 8
repository query language. See RQL
resource adapters, 67
resource references
application resources, 6, 62
connectors, 67
deployment editor, 62
global resources, 6, 62
JavaMail, 66
JDBC connection pools, 63
mapping to Dynamo services, 6
mapping to repositories, 7
repositories, 65
URL service, 66
RMI, 77
roles (security)
role references, 68
RQL (repository query language). See repositories
running applications, 13, 22, 26
application clients, 114
deployment editor, 61
runtime directory, 30
passivating, 85
session failover, 44
specifying a Java compiler, 36
SQL repositories. See repositories
staging directory, 10
standalone modules, 61
Sun JMS Reference Implementation, 145
T
tag libraries, 40
template applications, 55
text editor
deployment editor, 59
timeouts
configuring for application clients, 121
transaction management
EJBs, 78
transferring files
deployment editor, 57
U
URL service, 66
UserAuthority, 123, 125
V
validating applications
deployment editor, 60
S
security
administrative users, 141
architecture, 123
configuration, 125
configuring repositories, 137
demo applications, 130
EJBs, 80
JDBC data source, 128
password hashing, 138
repositories, 124, 127
role references, 68
UserAuthority, 123, 125
servlets, 41
processing, 38
Web applications, 46
session backup
configuration, 107
session beans (EJBs)
W
Web application deployment descriptor. See web.xml
Web applications, 40
EJB references, 73
environment entries, 68
logging in, 129
logging out, 129
mappings, 44
servlets, 46
session failover, 44
session timeouts, 43
Web services, 41
web.xml
adding new resources, 41
optional resources, 40
required resources, 40
151
Index