CHAPTER 11

image

EJB Packaging and Deployment

Until now, we have focused on how to build EJBs, Java Persistence API (JPA) entities, and their clients, for exploiting the surrounding enterprise services offered by the EJB container. In Java EE parlance, these tasks fall under the role of Application Component Provider, which is simply referred to as the Provider. In this chapter, we explore the topics that surround the process of packaging your components into modules and library components, binding external references declared in your Java EE components to actual resources in your server environment, and sending it all off to an application server so that the components can be executed at run time by an application. These responsibilities are handled by the Java EE roles of the Application Assembler (the Assembler) and the Application Deployer (the Deployer). While in practice it is common for a single individual to perform one or more of these roles, or for many people to perform any single role, for the purpose of explaining these topics, we will partition the deployment tasks into stages that correspond to these designated roles.

We will emphasize EJB and JPA entity components and also touch upon deployment of the other Java EE module types: Web application modules, application clients, and resource adapters. We will also look at the relationship between the Java EE server and the four Java EE containers that it supports, and we will explore some of the services that are provided by a Java EE server.

Following a brief overview of the deployment tasks in which we introduce much of the deployment terminology, we offer a look at the Java EE infrastructure components—the Java EE server and containers—that support deployment. We will explore the different types of Java EE modules and how they fit together and how you specify the deployment descriptors—metadata files—that define each module. A section on library components is offered, which explains how to declare class-path dependencies between Java EE modules and library components. We then provide a more detailed examination of the Assembler and Deployer roles, and we conclude with the deployment requirements that are specific to EJB modules and JPA persistence units.

After reading this chapter, you should understand how to do the following:

  • Group your EJB, JPA, and other application components into Java EE modules and library components.
  • Resolve naming collisions and redundancies found in external references.
  • Package a Java EE application consisting of one or more Java EE modules and library components.
  • Declare class-path dependencies between modules and libraries.
  • Bind external references to physical resources in the application server environment.

A Note on Deployment Tools

This chapter provides some examples of how to structure your application archives. It assumes that you have access to software tools, typically offered through an integrated development environment (IDE), to assist you in the assembly and deployment of your Java EE applications. There have been efforts in the Java Community Process (JCP) to standardize in this area (see JSR 88, the Java EE Application Deployment API), but deployment inevitably requires application server–specific configuration tasks. Fortunately, application servers generally provide Ant tasks to invoke their own deployment utilities, and you may also use Ant to create the deployable archives. The use of Ant is prevalent in many development environments and is nearly ubiquitous in production environments in which automated scripts are required to deploy the same Java EE applications to multiple Java EE server instances. Many of the customization steps that are described in this chapter require the use of interactive editors, mainly for updating Java EE generic and platform-specific XML deployment descriptors. For these tasks, an IDE can prove invaluable, and many IDEs provide platform-specific deployment support that guides you in packaging, configuring, and deploying your Java EE applications.

Overview of the Packaging and Deployment Processes

Packaging is the process of assembling (or grouping) various Java EE modules into Java EE JAR, WAR, or EAR files. Once packaged in a Java Archive (JAR) file, a Web Archive (WAR) file, or an Enterprise Archive (EAR) file, the Java EE application is ready to be delivered to the application server. Deployment is the process of installing Java EE components in an application server so that they can be found and executed when you run your application. This process involves multiple tasks that must be performed, roughly, in sequence. These tasks are summarized in the following sections, and each is described in greater detail and applied specifically to EJB and JPA deployment later in this chapter. Some steps will only need to be performed under special circumstances, so actual deployment may involve only a subset of these tasks.

The Provider

Generally speaking, the Provider (there may be many for a given project) produces the Java EE application components as a precursor to deployment. The tasks associated with the Provider, along with the files delivered by this role, are shown in Figure 11-1.

9781430246923_Fig11-01.jpg

Figure 11-1.  Tasks and deliverables of the Application Component Provider

The deliverables from the Provider are application components and possibly module descriptors, provided either as files on disk or packaged into Java Archive (JAR) files.

The Assembler

The Assembler takes the output from the Provider, and with it performs the tasks and produces the deliverables illustrated in Figure 11-2.

9781430246923_Fig11-02.jpg

Figure 11-2.  Deployment tasks and deliverables of the Application Assembler

Grouping Components by Container Type to Produce Java EE Modules

The output of the Provider is a set of Java EE components, such as EJBs, JPA entities, JSF (JavaServer Faces) pages, application client classes, and possibly others. The Provider may also produce non-Java EE components, like ordinary Java classes. The Assembler groups the Java EE components together such that each group contains components of only one Java EE component type. Whenever the Provider has defined a module-level deployment descriptor (XML) file, the Assembler may follow any directives in that file to compose the groups, or the Assembler may choose either to merge or split descriptors to increase or decrease the number of Java EE components in each group. At the end of this process, each resulting group will become a Java EE module. The non-Java EE classes and resources that are left over may be bundled into the Java EE modules or isolated into their own groups to become sharable library components.

Defining Module-Level Deployment Descriptors (Optional)

For each Java EE module that is formed, the Assembler may locate and assign a deployment descriptor to represent that module. Starting with Java EE 5, this step is optional, since annotations now make it possible to identify the module type by analyzing its file contents. For example, you (in the role of either the Provider or the Assembler) are free to define an ejb-jar.xml deployment descriptor; but unless you are overriding information that is captured in Java annotations, or you have chosen to not use annotations, it is no longer necessary. In Java EE 5, an EJB module is defined simply by the presence of a class in a file group that is annotated @Stateless, @Stateful, or @MessageDriven.

Packaging Components (with Optional Descriptors) into JAR Files

In this stage, the component groups identified in the first stage are packaged together with their module-level deployment descriptors, if defined, into files using the JAR format. EJB modules are archived into EJB JAR files with a .jar extension, Web application modules are archived into Web Archive (WAR) files with a .war extension, application clients are archived into JAR files with a .jar extension, and so on. JPA persistence units may be archived into their own JAR files (with .jar extensions) or archived directly into EJB JAR or WAR files. Well cover this detail in the “Assembling a Persistence Unit” section later in the chapter.

In addition, non-Java EE components, such as ordinary Java classes, may be added to these Java EE module archives; or the Assembler may archive them into their own JAR files to be deployed as library components.

Creating an Enterprise Archive (EAR) File (Optional)

If you (as the Assembler) have created multiple archives that you want to deploy together as a logical group, you will need to bundle these archives together inside a wrapper JAR file known as an EAR file, which uses the suffix .ear. This EAR file is referred to as a Java EE application. If you have created only a single EJB JAR or WAR archive, no further packaging is required. You can skip the step of creating a wrapper EAR file, and deploy the EJB JAR or WAR file as a stand-alone module.

An application acts as a packaging boundary, ensuring that the Java EE components in all modules are able to communicate with each other within a single naming context. A Java EE application does not necessarily correspond to an actual end-user application as it may be used by many different client applications, but it allows client applications to connect to the Java EE application once and access the Java EE components in that application from a single context.

An EAR file may contain an application-level deployment descriptor, application.xml, in its META-INF directory. This file is optional in Java EE 5, since it is now possible to rely on default rules to provide default names and properties for each module. By default, each module name defaults to the short name of its archive file, minus the file suffix (.jar, .war, and so on). Defining an application.xml descriptor allows you to refine the default names and properties and to choose selectively which modules in the EAR file to include in the application for a particular deployment.

image Note   A WAR file and an EAR file are standard JAR files with a .war or .ear extension respectively.

Assembler-Specific Tasks

Depending on the completeness and the complexity of the deployment descriptors for each module, the Assembler may be required to complete or refine some of the external references declared by the Provider. In many cases, the modules are sufficiently self-contained and complete so that there is no further work for the Assembler to perform, even when a deployment descriptor is not supplied by the Provider. In more complex deployment scenarios, when Provider-supplied documentation is used (possibly communicated through description properties on either the annotations or in the deployment descriptor), the Assembler may need to consolidate semantically equivalent but disparately named resources into a minimal, distinct set. Conversely, the Assembler may need to avoid resource name collisions by renaming resource references that share the same name but hold different semantics.

For example, if the Assembler is bundling two Java EE modules produced by different providers into a single Java EE application, both providers may reference the same logical EJB but use different names, or they may reference them with the names not yet bound. It is the responsibility of the Assembler to detect cases such as this, using the documentation provided by the Provider(s), and update the EJB references to bind to a single name. This name may be chosen by the Assembler and assigned to the EJB in that application context.

Any changes made by the Assembler are applied only to the module and application deployment descriptor files, and not to the Java source. This process works because of the rules of precedence dictated by Java EE, which in the case where conflicting metadata properties are defined both in the Java annotation source and the XML deployment descriptors, the deployment descriptors will prevail. The Assembler is able to resolve inconsistencies in the Java source by working only with the deployment descriptor files.

The Deployer

The tasks and deliverables of the Deployer are depicted in Figure 11-3.

9781430246923_Fig11-03.jpg

Figure 11-3.  Tasks and deliverables of the Application Deployer

Deployer-Specific Tasks

Again using instructions from the Assembler (and Provider)—typically communicated through description properties in the deployment descriptors or source annotations, the Deployer is required to bind all external references onto concrete resources (EJB references, resource references, persistence unit references, and so on) in the target application server environment. Only the Deployer can presume to know about the target server environment, and Java EE has deliberately added a layer of indirection to all resource usage to allow this binding to occur without affecting the work of either the Provider or the Assembler. This is why all resources used by the Java EE components are referred to via indirect references.

As was the case with the Assembler, Java EE policy dictates that the Deployer is allowed to make changes only to the XML deployment descriptor files and not to annotations in the Java source.

Invoking the Application Server-Specific Deployment Tool

Finally, your Java EE module or your Java EE application is ready to be submitted to the application server. Your application server will provide a deployment tool that lets you complete the deployment and install the Java EE components in the application server, ready to be executed by the end-user applications. During this stage, the deployment tool will validate the module(s) being submitted for internal integrity and ensure that all resources can be bound to actual objects that reside in the application server environment. The deployment will fail if any required resources cannot be located at deploy time, or if referenced library components are not found.

Summary of Overview

Java EE deployment lets you deploy individual modules, library components, or complete applications. In many cases, deployment may simply involve packaging the compiled source, together with the descriptors (a persistence.xml file is mandatory for persistence units, but ejb-jar.xml, web.xml, and application.xml files are optional for an EJB JAR, WAR and EAR modules respectively) and submitting them to a deployment tool. When assembling applications from multiple modules that may have been built by different component providers and may be of differing versions, the Assembler role takes on greater importance.

Java EE Deployment Infrastructure

Now that we have summarized the deployment process, let us explore some areas of the Java EE infrastructure that are central to deployment. An understanding of this topic is useful when it is time to make your own decisions about how to package your code into modules and to resolve and bind external references.

The Java EE Server

The Java EE server is the program running inside your application server that provides enterprise services to your Java EE components when they are executed. The Java EE server is also responsible for handling deployment requests and redirecting them to the Java EE containers that it hosts.

The Java EE specification defines the list of core services that must be supported by a Java EE server. These include messaging, database, security, transaction, persistence, and many other services. The Java EE server may also be extended to provide additional services, or alternative implementations of existing services, which are beyond those mandated by the specification. Java EE specification defines how a server may be extended to provide its containers with access to remote and external services by adapting them into the Java EE environment using resource adapters through the Java EE Connector API.

The Java EE Containers

The primary purpose of the Java EE server is to support Java EE containers, which provide various environments in which Java EE components are run. The Java EE specification stipulates support for four Java EE containers: EJB, Web, application client, and applet. While the EJB and Web containers execute in the application server running in the middle tier, the application client container typically executes in a Java SE environment on the client tier, and the applet container typically runs inside a Web browser. Nonetheless, they all rely on their underlying Java EE server for the many enterprise services that they in turn provide—through APIs—to the components that execute inside their container environment. For example, a Java EE server provides native messaging services to a Java EE container, and the container exposes messaging services to its components through the JMS (Java Message Service) API. Similarly, the container exposes database services through Java Database Connectivity (JDBC), transaction services through Java Transaction API (JTA), and so on. The Java EE containers also interpose on all communication between Java EE application components executing in Java EE containers, to provide component and resource injection. This is illustrated in Figure 11-4.

9781430246923_Fig11-04.jpg

Figure 11-4.  A JAVA EE Server

In addition to the many built-in services offered to Java EE components by the Java EE containers, Java EE allows for the integration of third-party services—through resource adapters and the Connector API—that are exposed to Java EE components through their containers using the Java EE Service Provider Interface (SPI).

Java EE Deployment Components

The principal building block components of a Java EE deployment are the Java EE application and the Java EE modules. Let’s take a look at what defines these components.

The Java EE Application

Java EE lets you deploy both individual Java EE modules and entire Java EE applications to the server. As mentioned in the preceding “Overview of the Packaging and Deployment Processes” section, when deploying an application, you package the individual Java EE modules, together with any associated deployment descriptors and dependent library components, into a wrapper archive JAR file known as an EAR file, which has the suffix .ear. Deploying an individual Java EE module is essentially a shortcut to avoid wrapping one JAR file around another single JAR file.

Apart from its packaging structure, a Java EE application operates, at run time, as a context in which one or more associated Java EE components, such as EJBs, servlets, and application clients, can operate and communicate with one another using a shared class loader and namespace. It may be useful to think of a Java EE application as a loosely coupled group of Java EE modules that are able to see each other and to share resources.

Java EE Module Types

Java EE defines the following Java EE module types: EJB, Web application, application client, and resource adapter. The first three correspond to their eponymous containers, and their deployment is delegated to these containers. Deploying a resource adapter module installs the resources in the Java EE server and registers these resources for use by Java EE components. Ordinary Java classes and other resources referenced by your Java EE modules may also be included as library components within an EAR file, either packaged as JAR files or stored as directories, and deployed with your Java EE application.

Note that a JPA persistence unit, comprising a set of JPA entities, is not a Java EE module but a library component. We describe some of the reasons for this in the “Persistence Unit” section that follows.

Let’s take a closer look at each of the Java EE module types.

EJB Module

An EJB module is comprised of one or more session and/or message-driven beans (MDBs). It is packaged into an EJB JAR file, and if it includes an ejb-jar.xml deployment descriptor (this is optional starting with Java EE 5), it must be located in the META-INF directory in the JAR file. Platform-specific descriptors may also be added to this META-INF directory. If the EJB JAR file doesn’t contain an ejb-jar.xml file, the EJB bean classes must identify themselves as EJBs using @Stateless, @Stateful, @Singleton, or @MessageDriven annotations.

In many cases, it is desirable to isolate the client’s view of an EJB module into its own archive. When the client communicates only with a session bean’s interfaces, it does not need access to the session bean class. In this case, it is good practice to package only the interfaces of the session bean(s), along with any other dependent classes, into a separate EJB client JAR library. This JAR file can be handed to the client, but it can also be referenced from the EJB JAR file so that these interfaces do not need to be duplicated inside the EJB JAR file. To reference the EJB client JAR file, or any other JAR file or directory in the EAR file, the Assembler adds a Class-Path entry to the META-INF/MANIFEST.MF file in the JAR file that points to these locations:

Class-Path: MyEjb-Client.jar

image Note   For further information on the MANIFEST.MF file, including usage of the Class-Path and Extension-List entries referred to in this chapter, please see: http://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html.

More than one JAR file or directory can be referenced in this way by separating the .jar and directory entries with a space character. The path of the referenced JAR files is relative to the EJB JAR file itself, which must be located in the root directory of the EAR file. In the preceding example, the MyEjb-Client.jar file is also located in the root directory of the EAR file.

An EJB module may also include a persistence unit, which is described in the following section. A persistence unit may only exist in the EJB JAR in expanded form; JAR files may not be nested inside the EJB JAR file. A persistence unit is defined by the presence of a META-INF/persistence.xml file in the contents of the EJB JAR file.

An EJB module may be assigned a name using a module declaration inside a META-INF/application.xml file. When no META-INF/application.xml file is present during deployment, as when the EJB JAR file is deployed stand-alone or within an EAR file that does not include this descriptor, it is assigned a default name. This name is derived from the name of the EJB JAR archive, minus any directory information or the .jar suffix. For example, an EJB JAR file may be bundled in an EAR file in the following location:

./OrderManagerEJBModule.jar

In this case, its default module name would be OrderManagerEJBModule.

EJBs in a WAR File

The EJB 3.0 specification simplified the packaging of EJBs by making the packaging of XML descriptors like ejb-jar.xml optional. The EJB 3.1 specification has taken this simplification even further by allowing the packaging of EJBs (POJOs annotated with @Stateless, @Stateful, @Singleton, or @MessageDriven annotations) directly in the WEB-INF/classes directory of the WAR file. Similarly, the ejb-jar.xml descriptor, if present, can be packaged directly into the WEB-INF directory along with web.xml. With this change, users no longer need to create a separate EJB JAR module for packaging the EJBs. Figure 11-5 depicts this new packaging option.

9781430246923_Fig11-05.jpg

Figure 11-5.  Packaging EJB directly under WEB-INFclasses directory of WAR file

Persistence Unit

A group of JPA entities, known as a persistence unit, is neither strictly a module type nor does it have its own dedicated container. Instead, the Java EE server supports persistence directly as one of the core services it offers to the Java EE containers. This allows JPA entities to behave as persistent objects and interact with Java EE components while executing in the other Java EE container environments. By not being constrained to their own container, JPA entities are also free to execute and demonstrate persistent behavior outside the Java EE environment.

image Note   In a deployment context, the term persistence unit refers to a group of collocated JPA entities and a ­corresponding (and mandatory) META-INF/persistence.xml file. This group of files may be packaged into its own JAR file, or the files may be bundled directly inside an EJB JAR or WAR file. In turn, the persistence.xml file defines one or more <persistence-unit> entries that may further partition the entities in the persistence unit packaging structure. In this chapter, we differentiate these two concepts that share similar names by always using the hyphen (persistence-unit) when describing the <persistence-unit> XML element. Thus, any reference to a persistent unit can be assumed to refer to the group of entities collocated with a persistence.xml file.

As mentioned in the preceding note, the packaging of persistence units is different from the packaging of other module types. When packaged in a Java EE application EAR file, a persistence unit is treated as a library component (see the “Library Components” section below). It can be packaged into a JAR file, or its classes can be packaged directly inside an EJB JAR or WAR file. Either way, a META-INF/persistence.xml file serves to identify the entities contained in the persistence unit. We will discuss the packaging details in the “Assembling a Persistence Unit” section later in this chapter.

Web Application Module

A Web application module is comprised of servlets, HTML pages, JSF, JSP documents, and any other Web-based files. Its deployment descriptor is the WEB-INF/web.xml file and, as with the EJB module, the presence of this file is now optional starting with Java EE 5 since its contents can be derived using default rules. When archived, the contents of a Web application module are packaged into a JAR file with the suffix .war. This is commonly referred to as a WAR file.

The contents of a WAR file follow a special structure to suit application partitioning in Web browsers better. Of particular relevance when bundling persistence units into a WAR file, Java .class files are placed in the WEB-INF/classes directory, and dependent JAR files may be added directly to the WEB-INF/lib directory.

Similar to an EJB module, a Web module may be assigned a name using a module declaration inside a META-INF/application.xml file. When no META-INF/application.xml file is present during deployment, as when the WAR file is deployed stand-alone or within an EAR file that does not include this descriptor, it is assigned a default name. This name is derived from the name of the WAR archive, minus any directory information or the .war suffix. For example, a WAR file may be bundled in an EAR file in the following location:

./OrderManagerWebApp.war

In this case, its default module name would be OrderManagerWebApp.

Resource Adapter Module

Resource adapters offer a mechanism for extending a Java EE server. They allow resources and services managed by external systems to be integrated into the Java EE server for use by components executing in the Java EE containers. A resource adapter module contains a set of resource adapters and an optional META-INF/ra.xml deployment descriptor.

During deployment, a resource adapter is packaged into a Resource Archive (RAR) file, which is a JAR file with the suffix .rar.

Application Client Module

An application client module contains Java classes that can be executed in a Java SE environment on the client tier. The application client container is a lightweight Java EE container that supports injection and provides persistence, security, and messaging services, among others. It does not provide many of the services that are available from the middle-tier Java EE containers.

The deployment descriptor for an application client module resides in META-INF/application-client.xml and, like the other Java EE module deployment descriptors, is optional starting with Java EE 5.

Library Components

Shared classes or other resources that your modules require at run time can be packaged into library components. Libraries may either be installed in the application server (the process of installing a library is not described here) or bundled inside your EAR or WAR file. Any JAR-format file embedded inside an EAR, whether a Java EE module or a bundled library archive, may reference a bundled library component using the Class-Path property in the META-INF/MANIFEST.MF file.

image Note   Whenever a JAR file is referenced through a Class-Path entry, only the classes in the referenced JAR file are recognized by the deployment tool. Any descriptor files found in the referenced JAR file will be ignored.

Bundled Libraries

Listing 11-1 shows the file contents of a sample EAR file to demonstrate how the Class-Path property references a bundled library. Here we use a shorthand notation to show the Class-Path: myEjb-Client.jar entries that reside in the META-INF/MANIFEST.MF files for their associated JAR and WAR files.

Listing 11-1.  Example EAR File Contents Showing Explicit Module Dependencies on a Bundled Library Component

myApp.ear:
 META-INF/application.xml
 myEjb.jar Class-Path: myEjb-Client.jar
 myWebApp.war Class-Path: myEjb-Client.jar
 myEjb-Client.jar

In this example, the client-side interfaces (remote, local, and Web service endpoint interfaces) have been deliberately stripped from the myEjb.jar EJB module and packaged into the bundled myEjb-Client.jar library component. The META-INF/ejb-jar.xml descriptor in myEjb.jar contains the following entry:

<ejb-client-jar>myEjb-Client.jar</ejb-client-jar>

This identifies myEjb-Client.jar as the JAR file holding its client-side interfaces. The myEjb.jar EJB module depends on these EJB interfaces, and it declares its dependence through its Class-Path entry referencing the myEjb-Client.jar library. The myWebApp.war Web module references these EJB interfaces, and it declares its dependence on myEjb-Client.jar in the same way. The myEjb-Client.jar library is an ordinary JAR file, and it sits alongside the EJB and WAR files in the EAR file.

An alternative to explicitly declaring dependence on a bundled library component is to use the EAR file’s built-in library directory, lib, as shown in Listing 11-2. All JAR files found in the lib directory are automatically added to the class-path of the Java EE modules in the EAR file.

Listing 11-2.  Example EAR File Contents Showing Implicit Module Dependencies on a Shared, Bundled Library Component

myApp.ear:
 META-INF/application.xml
 myEjb.jar
 myWebApp.war
 lib/myEjb-Client.jar

This achieves the same result as Listing 11-1. Assuming application.xml does not specify a <library-directory> element that overrides the default lib directory, the Java EE server will automatically add the myEjb-Client.jar file to the class-paths of the myEjb.jar and myWebApp.war modules.

Libraries may also be bundled in the WEB-INF/lib directory for the JAR files of a WAR file, and in the WEB-INF/classes directory for the unpackaged classes of a WAR file.

Installed Libraries

It is also possible to install libraries in your application server environment and then reference them from the JAR-format files in your EAR file using the Extension-List property in the JAR file’s META-INF/MANIFEST.MF file. This is an efficient means of sharing libraries across Java EE applications since it avoids having to bundle the libraries redundantly in multiple EAR files. The installed libraries are stored on disk by the application server instance, and typically a shared library entry in one of the application server’s configuration files links the name of the installed library with its JAR file or files. Java EE applications may then refer to this installed library by name without having to know about the JAR file contents of the library.

An example of using an installed library is shown in Listing 11-3.

Listing 11-3.  Example EAR File Contents Showing Usage of an Installed Library

myApp.ear:
 META-INF/MANIFEST.MF:
  Extension-List: commonUtils
  commonUtils-Extension-Name: com/apress/ejb/ch11/commonUtils
  commonUtils-Extension-Specification-Version: 1.4
 META-INF/application.xml
 myEjb.jar

In this example, the EAR file’s META-INF/MANIFEST.MF file is used to declare a reference to an installed library named commonUtils, version 1.4. This gives all the JAR files inside the EAR file access to the contents of the commonUtils library, satisfying the myEjb.jar module’s dependence on the contents of this library. The reference could have been defined on myEjb.jar instead, in which case only myEjb.jar would be given access to this library. Either way, the installed library must have been installed prior to deployment of myEjb.jar.

The META-INF/MANIFEST.MF file for the JAR file contained in our commonUtils library is shown in Listing 11-4.

Listing 11-4.  Contents of an Installed Library’s JAR File

commonUtils.jar:
 META-INF/MANIFEST.MF:
  Extension-Name: com/apress/ejb/ch11/commonUtils
  Specification-Title: Utils for implementing common patterns
  Specification-Version: 1.4

Versioning of Libraries

Although it is not mandated by the Java EE specification, many application servers support Java EE application isolation levels that allow each Java EE application to have its own class loader. This allows multiple applications running simultaneously in the same Java EE server to reference different versions of the same bundled or installed library component. An example where this is useful is when you wish to migrate a subset of your applications to use a new library version. You can install the new library version in the server and then selectively update the Specification-Version property for any applications that you wish to use the new library version.

Alternatively, Java EE servers with this level of isolation support will allow you to deploy a Java EE application that bundles its own version of a dependent library. The rules of precedence in the Java EE specification dictate that, in the case of a conflict between a bundled library and an installed library with the same Extension-Name, the bundled library will be used. This guarantees that the application will always use its bundled library, regardless of which versions of that library are available in the server’s installed library base.

Application Servers and Platform Independence

Java EE has always held a keen eye to portability, although in practice this has often been difficult to achieve. Ideally, all Java EE servers implement the specification as far as it goes and then differentiate themselves both on performance and features, like support for configurable isolation levels and advanced object/relational (O/R) mapping options that are recommended (or hinted at, but not mandated) by the specification.

Application servers are expected to define their own platform-specific descriptors to be used to augment the core requirements of the Java EE specification, and indeed virtually all application server implementations offer such descriptors. Over time (and we have seen this most notably in the area of JPA mapping metadata), features that are found to be lacking in the specification and are solved by vendor implementations, get rolled into the specification and are made generic. For example, EJB 2.1 offered no support or regulations on how to define O/R mappings for entity beans, nor on how to implement an entity inheritance hierarchy. Starting with EJB 3, the JPA has taken many of the best ideas coming out of TopLink, Hibernate, and Java Data Objects (JDO), and rolled them straight into the orm.xml file to offer these features, as well as others.

Deployment Tools

Application server vendors have virtually all standardized on JSR 88, which specifies the use of managed JavaBeans, called MBeans, to manage the deployment process. MBeans are self-describing and follow design patterns defined by the Java Management Extensions (JMX) specification to provide an interface between the Java EE server and the application server’s deployment tool. The actual interfaces exposed by the Java EE-deployment MBeans vary from one application server to another; but the fact that all deployment tools now use them, to one degree or another, offers some consistency between vendor deployment tools.

Typically, a vendor’s deployment tools will guide the Assembler not only through the process of packaging the Java EE modules, libraries, and application archives, but also through specifying some amount of metadata for populating both the Java EE generic and platform-specific deployment descriptors. The tools will also accept EJB, WAR, or EAR files, and they actually perform the installation and validation deployment tasks in the server itself.

image Note   Cargo is a thin wrapper that allows you to manipulate Java EE containers in a standard way. Cargo aims to provide an abstraction API to many of the popular Java EE containers, through the medium of Ant tasks, Maven, and IDE plug-ins. For more information on Cargo, see http://cargo.codehaus.org.

The Deployment Plan

Some vendors’ application server tools record the Deployer’s choices in a document called a deployment plan. Since deployment is often an iterative process, especially during the development and testing stages, it is convenient to capture the Deployer’s choices so that the Deployer does not have to specify the same information repeatedly.

Currently, there is no standard format for a deployment plan specified in JSR 88 or elsewhere, so it is not a document that can be reused across application server implementations. If you find this inconvenient, get involved in the JCP and form or join a JSR to promote a standard in this area.

Deployment Roles

Any encompassing enterprise service platform is, by its very nature, complex. Recognizing this reality, the architects of Java EE have partitioned the Java EE services into well-defined APIs. Similarly, they have partitioned the tasks associated with the various stages of developing and configuring Java EE applications into well-defined roles. We mentioned that the tasks associated with building the various application components, such as EJBs, entities, servlets, JSF JSPs, and many others, fall under the Java EE role of Application Component Provider. There are also other roles, such as the System Component Provider, which is responsible for installing resources in the application server that are required by the application components. Among these are database resources, authorization policies, security roles, and many others, including services brought in through resource adapters.

We had previously introduced the roles of Application Assembler and Application Deployer. In this section, however, we will explore these roles in greater depth.

The Application Assembler

Here is what you need to know as an application assembler.

Defining and Describing External Dependencies

The Provider identifies the external requirements held by its components, either in annotations, deployment descriptors, or both. These dependencies may be on other EJBs, persistence units, environment property values, database connections, or any other object external to that application component. It is the responsibility of the Assembler to describe these external dependencies further such that the Deployer can figure out how to map them to concrete resources in a specific application server environment. External dependencies are defined through <ejb-ref>, <ejb-local-ref>, <resource-ref>, <resource-env-ref>, <security-role-ref>, and <message-destination-ref> entries in annotations or deployment descriptors. The Assembler’s job is to analyze these external references and patch them up. This process involves the following steps.

Ensuring That All References Are Complete

It is legal, and common, for the Provider to complete the definition of external references only partially. The Provider may not know, or may attempt to guess, the actual names of the resources being referenced. In such cases, the Provider will spell out the details of the reference—its object type, its internally used name, and a description of the logical behavior of the referenced object. The Assembler takes this information and then links it to a name of a resource that is internally consistent within the application. An example of this is an EJB reference. A web.xml, ejb-jar.xml, or application-client.xml descriptor is allowed to declare EJB references using an <ejb-ref> element. An <ejb-ref> has an ejb-ref-name property that is used by the referencing component (whether a Web form, another EJB, or an application client), and links it to the actual name assigned to the EJB during deployment by assigning a value to the <ejb-ref>’s ejb-link property. Listing 11-5 illustrates an <ejb-ref> that has been fully defined by the Assembler.

Listing 11-5.  An ejb-ref Descriptor Element that Has Been Properly Linked to a Named EJB

<ejb-ref>
 <description>
  Some description that defines this EJB to the Assembler
 </description>
 <ejb-ref-name>ejb/MyAccountManager</ejb-ref-name>
 <ejb-ref-type>Session</ejb-ref-type>
 <remote>com.apress.ejb.ch11.MyAccountManager</remote>
 <ejb-link>SalesAccountManager</ejb-link>
</ejb-ref>

image Note   The <home> and <local-home> properties are optional starting with EJB 3.

It is also possible to resolve a reference to an EJB that is packaged in a different EJB JAR file in the same application. Listing 11-6 illustrates how you would use a special path notation in the ejb-link value to do this. The ejb-link property value may refer to any EJB found in an EJB JAR file in the application EAR file.

Listing 11-6.  An ejb-ref Descriptor Element that Links to an EJB Residing in a Different EJB JAR in the Application

<ejb-ref>
 <description>
  Some description that defines this EJB to the Assembler
 </description>
 <ejb-ref-name>ejb/MyAccountManager</ejb-ref-name>
 <ejb-ref-type>Session</ejb-ref-type>
 <remote>com.apress.ejb.ch11.MyAccountManager</remote>
 <ejb-link>../salesEjbModule.jar#SalesAccountManager</ejb-link>
</ejb-ref>

This example shows how the link would appear if the SalesAccountManager EJB was moved into a peer EJB module named salesEjbModule.jar. Finally, the Assembler may need to resolve EJB references that have been partially declared using @EJB annotations in the Java source, as shown in Listing 11-7.

Listing 11-7.  A Partial @EJB Annotation in a Java Source File

@EJB(name="AccountManager",
   beanInterface=AccountManager.class,
   description="The Department Account Manager")
private AccountManager acctMgr;

The Assembler would add an <ejb-ref> element to complete this reference but would leave the properties that have already been defined intact, as shown in Listing 11-8.

Listing 11-8.  An ejb-ref Descriptor Element that Fills in the Missing Properties of an @EJB Annotation

<ejb-ref>
 <ejb-ref-name>ejb/MyAccountManager</ejb-ref-name>
 <ejb-link>SalesAccountManager</ejb-link>
</ejb-ref>

image Note   While it is possible to use JNDI (Java Naming and Directory Interface) to look up EJBs deployed outside the context application, <ejb-ref>, <ejb-local-ref>, and the corresponding @EJB annotation may only be used to access EJBs deployed in the context application.

This process continues until the Assembler has linked all the EJB, resource, resource environment, and any other references that were found dangling.

Resolving Conflicting and Redundant References

The modules presented to the Assembler for assembly into an application may have been built by different Providers, or at different times. In such cases, it is common to find references to the same logical resources, but using different names. It is the responsibility of the Assembler to scan both the source annotations and any XML deployment descriptors and rename any redundant references to a common name.

Similarly, the same internal name may be used by application components to refer to logically distinct resources. Using the description properties of these references, found both on annotations and in deployment descriptors, along with any other documentation supplied by the Provider, the Assembler must detect such conflicts and rename these references appropriately.

The Assembler may choose to populate each module descriptor fully by merging Java annotations found in the module source files into the descriptor, whenever it is not in conflict. If the Assembler chooses to perform this task, the descriptor’s metadata-complete property may be set to true. This signals to the Deployer that this descriptor and the Java annotations need not be further analyzed, leading to a speedier deployment.

Packaging

The Assembler performs the packaging stage to bundle application components into container-specific JAR files and component libraries. This packaging process was outlined in the preceding “Overview of the Packaging and Deployment Processes” section. You can use Ant or ZIP utilities to perform these steps of grouping the Java EE components into modules and packaging them into JAR files. However, this is an area that benefits from the use of a visual packaging tool, typically available through an IDE. The Assembler packages EJB and application client modules into JAR files, Web application modules into WAR files, and resource adapters into RAR files.

When assembling a stand-alone Java EE module with no bundled libraries, no further packaging is needed. The module’s JAR file is ready to be deployed.

If multiple modules are involved, or if libraries need to be bundled as well, the Assembler creates an EAR file and adds the modules and libraries to this archive. The Assembler may add the modules using an internal directory structure, provided that the lib directory, or the directory specified by <library-directory> in the application.xml file, is honored as the location for implicitly shared libraries.

An optional application.xml file in the EAR file’s META-INF directory may be used to identify the modules explicitly, which are included in the application. This is the way of telling the deployment tool to ignore the modules that are not meant of be part of the application, but for some reason are included as part of the application.

The Application Deployer

The module or package produced by the Assembler is then handed off to the Deployer. The Deployer has intimate knowledge of the target application server environment, including information about all the resources that are currently deployed in that environment.

The Deployer’s actual experience differs due to the varying tool sets offered by vendors to accompany their application servers. The logical processes of the deployment state are outlined in the following sections.

Unpackaging the Archive

The EAR file, or stand-alone module JAR file, is unpackaged and its contents are analyzed.

Deriving the Module Descriptors

The Deployer processes the descriptor for each Java EE module. If a descriptor was provided, and if its metadata-complete property is set to true, then the Deployer can send the module off to the appropriate container. If the descriptor is not supplied, or if metadata-complete is not set to true, then the Java source contents of that module must be scanned to detect annotations. All metadata properties found by scanning the annotations are coalesced with properties found in the descriptor. During this reconciliation step, Java EE precedence rules dictate that whenever both an annotation and the descriptor provide a value for a given property, the value in the descriptor prevails. The result of this reconciliation state is a completed descriptor for that module.

Binding External References

All external references found are checked for completeness, ensuring that the work of the Assembler was performed. These references are then matched to actual resources in the application server environment. If any resources cannot be bound, an error is reported back to the Deployer so that it can be resolved. As you can imagine, this process greatly benefits from a robust deployment tool set provided by the application server.

Deploying to the Containers

Each completed module can be sent to its corresponding container to be installed and registered. Once complete, the Java EE components in these modules are ready to be accessed by clients.

Assembling an EJB JAR Module

An EJB JAR file is a pretty straightforward archive. The .class files are laid out in the JAR file in directories corresponding to their packages, rooted at the top-level directory of the JAR. The ejb-jar.xml deployment descriptor, if present, goes in the META-INF directory, typically accompanied by any other platform-specific descriptors.

Arbitrary classes may be included alongside the EJB classes and interfaces. It is a common practice to package the shared library JARs in the same EAR file as the EJB JAR file. Libraries bundled in the surrounding EAR file may be referenced using the Class-Path property of the EJB JAR file’s META-INF/MANIFEST.MF file, as described in the preceding “Library Components” section. Similarly, you may reference installed libraries previously deployed but outside the context application by listing them in the Extension-List property in the META-INF/ MANIFEST.MF file.

When it comes to specifying the metadata for an EJB, the ejb-jar.xml descriptor and the Java source annotations are mutually redundant. The decision to use one approach over another is largely a matter of Provider preference, though this decision is also affected by how the application will be edited, assembled, and deployed. However, the top-level settings, (such as <ejb-client-jar>) have no corresponding annotations and must be assigned through this descriptor.

image Note   Starting with Java EE 5, we have the ability to deploy EJB and WAR modules directly, without packaging them as a Java EE application. This is only appropriate if these modules hold no external dependencies on classes in other JAR files that are not already deployed to the target application server environment.

Naming Scope

Within a Java EE application, no two EJBs may have the same name. It is the Assembler’s responsibility to detect this case and rename EJBs appropriately to resolve the conflict.

Assembling a Persistence Unit

A persistence unit is a set of JPA entity, mapped superclass, and embeddable classes coupled with a mandatory META-INF/persistence.xml file. Java EE offers a fixed set of ways to bundle a persistence unit during deployment. You can package a persistence unit in any of the following ways:

  • Into one or more JAR files which in turn may be packaged within a WAR or an EAR file
  • As a set of classes within an EJB-JAR file
  • In the classes directory of a WAR file
  • Or as a combination of the above-mentioned ways

The JAR file or directory where its META-INF/persistence.xml file is located is called the root of the persistence unit, and it defines the root directory for the classes that comprise the persistence unit. The root of the persistence unit must be one of the following:

  • An EJB-JAR file
  • The WEB-INF/classes directory of a WAR file
  • A JAR file in the WEB-INF/lib directory of a WAR file
  • A JAR file in the library directory of an EAR file
  • An application client JAR file

The decision of where you bundle your persistence unit determines which modules will have visibility to it. For instance, adding it to the EAR file’s library directory gives access to all other modules in the application. Placing it in the EJB, Web application, or application client JAR limits its scope to that module.

In addition to the persistence.xml file, one or more O/R mapping files may be added to the META-INF directory to augment or override any annotations that may have been specified in the managed JPA classes. The JPA specifies the default file name to be META-INF/orm.xml, but each <persistence-unit> defined in the persistence.xml file may specify its own mapping files, using <mapping-file> elements.

Naming Scope

Within a Java EE application, it is possible for two JPA entities to have the same name, but only if they are in separate contexts. For instance, two Web application modules may bundle separate persistence units inside their WEB-INF/lib or WEB-INF/classes directories. In this case, the persistence units are private to each Web application module, and duplicate names between these persistence units will not cause a conflict.

It is the Assembler’s responsibility to detect conflicts within the same naming scope and rename entity-name properties appropriately to resolve the conflict.

Conclusion

This chapter introduced the topic of Java EE deployment, and it covered both general deployment issues and areas of deployment that are specific to EJBs and JPA entities. We began the discussion with an overview of the tasks that are performed during deployment, noting that, depending on the complexity of the Java EE modules being deployed, some steps may not be required. This overview section also explained the roles of the Assembler and Deployer, and it explained the deployment tasks in the context of these two roles.

To provide some background into the deployment infrastructure (knowledge that will assist you when choosing how to partition your applications and resolve external references), we explored the Java EE server and the four Java EE containers: EJB, Web, application client, and applet. This led to a discussion of the corresponding Java EE module types, and the definition of a Java EE application. We also explained how to use library components to package your JPA persistence units and non-Java EE components.

The remainder of the chapter provided a more in-depth look at the roles of the Assembler and Deployer, and it concluded with further specifics on how to deploy EJB modules and JPA persistence units.

In the next chapter, we explore how to build clients that are capable of interacting with EJB components in a multiuser, distributed environment.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.109.93