Beyond standard packaging, there are three distinct tasks before we can make a successful deployment:
We need to prepare the app server by setting up server-wide resources such as connection pools, which our apps rely on.
Let's look at each task in turn.
Let's look at some of the most important server-wide configuration issues we're likely to encounter. These involve creating the services the app will rely on at runtime, and ensuring that any dependencies are satisfied.
In most J2EE apps, we'll need to perform RDBMS access. This means that we must configure a javax.sql.DataSource and ensure that it is bound in the server's global JNDI naming context. This usually involves creating a connection pool, the details of which will be server-specific, and defining a server-specific DataSource that exposes it. DataSource objects can be used by code running in either the EJB or web container. Typical configuration parameters we will need to set when defining a connection pool are:
The JDBC driver class. This is normally a class supplied by the RDBMS vendor, such as oracle.jdbc.driver.OracleDriver.
We'll also need to ensure that the necessary database driver is available at app server (rather than app) level, as connection pools are independent of apps.
JMS destinations are another example of server-wide resources. These are not limited to any single app. In fact, they can be used for inter-app communication.
In JBoss 3.0, the $JBOSS_HOME/deploy/jbossmq-destinations-service.xml file defines the default JMS topics and queues, setting their JNDI names. In Orion the same role is performed by the /config/jms.xml file.
Different app servers have different approaches to authentication, but we will need to provide the app server some way of checking user credentials against a persistent store. This usually involves specifying a class, which may be provided by the app server or may be custom, which checks users and role information. Most app servers define a fairly simple interface such classes must implement. User information is usually held in an RDBMS.
In Orion, authentication can be configured at an app level, but in WebLogic and JBoss, it's server-wide.
We may wish to install binaries used by multiple apps at server level, rather than distribute them as part of each app. We can do this if necessary by modifying the command that invokes the app server by adding additional classpath elements, although it's more elegant to follow server conventions. In JBoss, we can simply copy the necessary .jar or .zip files to the /lib directory of the relevant server. Note that when we install libraries at a server-wide level, it will be impossible to modify them without restarting the app server; the app server will be unable to load them in a dynamic classloader such as it may use for app code. In general, it's better to keep apps self-sufficient, by shipping all required binaries within J2EE deployment units. However, the following are typical cases when we might choose a server-wide approach:
When the binaries in question relate to the server, rather than a specific app. Database drivers are in this category. They cannot usually be included in apps, as servers typically start connection pools before starting apps, and therefore need the drivers before loading apps.
ImportantĀ |
Don't update or patch libraries used by an app server unless it's essential, as it risks affecting the behavior of the app server. |
Occasionally it may be necessary to deploy some classes at server-wide level to avoid class loading problems between WAR and EJB deployments. However, as we've seen, this often reflects poor design of the classes in question, and is a last resort, rather than a positive choice.
In additional to server configuration, we will need to add proprietary information for inclusion in deployment units. Proprietary deployment descriptors are required to provide additional information that fills gaps left by the standard deployment descriptors and to configure implementation-specific parameters. For example, proprietary deployment descriptors must be used to:
Tell the server where to find resources the standard deployment descriptors identify. For example, the standard deployment descriptors require declaration of the JNDI names used in app code to access resources such as DataSources, but don't specify how these should be mapped onto server-wide data sources created during server configuration.
The structure of proprietary descriptors varies, but there's much commonality between their content. The settings I'll discuss below are common to all servers I've worked with.
NoteĀ |
Entity beans with CMP often require complex proprietary deployment descriptors, the format of which varies between app servers. As I don't advocate use of entity beans, I won't attempt to cover this here. If using CMP entity beans, please refer to documentation about proprietary descriptors for your app server. Plan to use tools to manage the complexity of such deployment descriptors; manual editing is not a viable option for the necessary ejb-jar.xml elements and proprietary descriptors. |
Usually the most complex parameters relate to EJBs. We'll always need to provide mappings for the JNDI names declared in ejb-jar.xml. However, other settings may include:
Stateless session bean pooling options.
Note that we don't always need to override the defaults, which may ensure appropriate behavior for most apps.
Web-tier configuration is usually simpler than EJB-tier configuration, because the relevant container infrastructure is simpler, because there are fewer gaps in web.xml, and because using an MVC framework (such as Struts or the framework we discussed in ) tends to move much of the configuration of web-tier components into framework-specific deployment descriptors. Typically we'll need only to provide mappings for the JNDI names declared in resource references in web.xml. However, we may be able to set options such as the following (configurable in weblogic.xml):
JSP compilation options, such as which compiler to use, special command-line arguments, and whether all JSP pages should be precompiled when the app starts up
The steps in deploying an app will vary between servers. Web apps don't generally require any special steps besides making the WAR available to the server, as a web container merely needs to load the relevant servlet classes and make the necessary resources available through JNDI. EJB deployments, however, may be more complex, as the EJB classes implemented as part of the app don't implement the bean's EJBObject and home interfaces. The server must provide implementations of these interfaces, invoking app classes to perform business logic. Some servers use dynamic proxies to implement EJB component and home interfaces, wrapping app classes. However, many servers, such as WebLogic, require a compilation step, in which the container generates and compiles the necessary classes. The use of container-generated classes may produce marginally better performance by minimizing the need for reflection, although it's unlikely that any such gain will be significant in most apps. Until J2SE 1.3 introduced dynamic proxies, container-generated classes were the only available deployment strategy. In WebLogic's case, the proprietary ejbc tool is used to generate container-specific classes and add them to the EJB JAR file before deployment to the server. WebLogic can automatically perform this step on deployment of a standard EJB JAR file, but it unnecessarily wastes server resources and may make it harder to track down deployment errors, by combining the operations of building the WebLogic-specific EJB JAR file and deploying it on a running server.
ImportantĀ |
If a server-specific "compilation" step is required, use an Ant target to invoke it and ensure that it occurs before deployment. |
Now we know enough to list the essential tasks required to configure any server to run our sample app and add the necessary deployment descriptors to our app. Only how we accomplish these tasks will differ between servers:
Create a server-wide DataSource for our Oracle database.