Follow along with the steps for deploying simple J2EE applications on computers running Apache Geronimo, and find out how similar the steps are to those for any other J2EE-compliant application server. While this article focuses mainly on how to deploy EJBs on Apache Geronimo, you'll also learn about JSPs and servlets. This article assumes that you know how to write and deploy EJBs in another J2EE container, such as IBM WebSphere® Application Server, JBoss, or WebLogic.
Note: Use the current release of Apache Geronimo (at the time of this writing, V1.0 M5) to work with the code samples in this article.
I want to thank Neal Sanche for granting me permission to use the code from his article, "Dive into EJB Web applications with Geronimo," as the basis for explaining the deployment process. Please download the code, and refer to it as you read this article (see the Download section).
JSPs and servlets are two basic J2EE technologies that drive the user interface (UI) layers of a J2EE application. You use JSPs primarily for presentation logic and the HTML code. Servlets form the controller layer of a typical Model-View-Controller (MVC) architecture and serve as an interface between the presentation and the model layers.
The simple application in the example code is written using Apache Struts. The code contains a few Struts action classes and a couple of JSPs. Figure 1 shows the structure of the source code.
Figure 1. Structure of source code for the example
The Struts action classes are in the Phonebook/src/java/org/acme/phonebook/struts directory. The JSPs are in the Phonebook/src/webapp/pages directory.
The only real servlet in this example is the Struts Action Servlet, which controls the invocation of the action classes. Find servlet-mappings.xml and servlets.xml in the code tree, and see how the Struts Action Servlet is declared. The code for these files is shown in Listing 1 and Listing 2, respectively.
Listing 1. Servlet-mappings.xml
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- Session Config -->
<session-config>
<!-- Make sessions last two hours -->
<session-timeout>120</session-timeout>
</session-config>
|
Listing 2. Servlets.xml
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>
/WEB-INF/conf/struts-config.xml
</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>0</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
|
For J2EE Web programmers, this code is familiar. The servlet-mappings.xml and servlets.xml files are merged into the web.xml file of the J2EE Web Archive (WAR) file during the Maven build process. Consider going through the build process and viewing the generated web.xml file.
Apache Geronimo uses OpenEJB as the EJB container system. The example contains two EJBs:
- Container-managed entity EJB
- Stateless session EJB
In his article, Neal explains that he has leveraged XDoclet quite heavily in his EJBs. XDoclet, like EJBGen, generates most of the EJB code for you, including the deployment descriptors. The concept of XDoclet is similar to Java annotations. Javadoc-style comments are used as triggers for the XDoclet compiler and generate a lot of the code that's needed. Browse through PhoneBookEntryBean.java, shown in Listing 3, to see the annotation style that XDoclet uses.
Listing 3. PhoneBookEntryBean.java
package org.acme.phonebook.ejb;
/**
*
* @ejb.bean
* type="CMP"
* cmp-version="2.x"
* name="PhoneBookEntry"
* local-jndi-name=
* "org.acme.phonebook.ejb/PhoneBookEntryLocalHome"
* view-type="local"
* primkey-field="name"
*
* @ejb.finder
* signature="java.util.Collection findAll()"
* query="SELECT OBJECT(o) from PhoneBookEntry AS o"
*
* @xx-ejb.data-object
* container="true"
* setdata="true"
* generate="true"
*
* @ejb.value-object
*
* @ejb.transaction type="Required"
* @ejb.permission unchecked="true"
* @struts.form include-all="true"
*
* @web.ejb-local-ref
* name="ejb/PhoneBookEntryLocal"
* type="Entity"
* home="org.acme.phonebook.ejb.PhoneBookEntryLocalHome"
* local="org.acme.phonebook.ejb.PhoneBookEntryLocal"
* link="PhoneBookEntry"
*
* @ejb.persistence table-name="PhoneBookEntry"
*
*/
public abstract class PhoneBookEntryBean
implements javax.ejb.EntityBean
{
/**
*
* @ejb.pk-field
* @ejb.persistence
* column-name="NAME"
* jdbc-type="VARCHAR"
* sql-type="VARCHAR(250)"
*
* @ejb.interface-method view-type="local"
*
*/
public abstract java.lang.String getName();
/**
* @ejb.interface-method view-type="local"
*/
public abstract void setName(java.lang.String newValue);
/**
*
* @ejb.persistence
* column-name="PHONE_NUMBER"
* jdbc-type="VARCHAR"
* sql-type="VARCHAR(250)"
*
* @ejb.interface-method view-type="local"
*
*/
public abstract java.lang.String getPhoneNumber();
/**
* @ejb.interface-method view-type="local"
*/
public abstract void setPhoneNumber(java.lang.String newValue);
/**
* @ejb.interface-method
*/
public abstract org.acme.phonebook.ejb.PhoneBookEntryValue
getPhoneBookEntryValue();
/**
* @ejb.create-method
*/
public java.lang.String ejbCreate(java.lang.String name,
java.lang.String phoneNumber)
throws javax.ejb.CreateException
{
setPhoneNumber(phoneNumber);
setName(name);
return null; // should not return primaryKey for CMP:
}
public void ejbPostCreate (java.lang.String name,
java.lang.String phoneNumber)
throws javax.ejb.CreateException
{
}
/**
* This is a create method which takes only the value of the
* primary key, because this object does not have automatic
* key generation turned on.
*
* @ejb.create-method
*/
public java.lang.String ejbCreate(java.lang.String name) throws
javax.ejb.CreateException {
setName(name);
return null;
}
public void ejbPostCreate(java.lang.String name)
throws javax.ejb.CreateException {
}
}
|
In PhoneBookEntryBean.java, shown in Listing 3, take a close look at the Javadoc comments. In this code, the Javadoc comments are more interesting and contain more information than the code itself. The annotations define the type of EJB, container-managed fields, finder queries, data types, and all the other information typically found in the deployment descriptors of an EJB. In addition, you aren't required to code the home interface, remote interface, and local interface classes. Maven and XDoclet do this all in the background during the build process.
The basic deployment descriptor needed to work with the OpenEJB container system is openejb-jar.xml, which is shown in Listing 4. This descriptor, in combination with the Javadoc annotations from PhoneBookEntryBean.java, eventually forms the ejb-jar.xml and other descriptors required by a standard J2EE-compliant EJB application.
Listing 4. Openejb-jar.xml
<?xml version="1.0"?>
<openejb-jar
xmlns="http://www.openejb.org/xml/ns/openejb-jar"
configId="org/acme/PhonebookEJB"
parentId="MysqlDatabase">
<cmp-connection-factory>
<resource-link>MysqlDataSource</resource-link>
</cmp-connection-factory>
<enterprise-beans>
<entity>
<ejb-name>PhoneBookEntry</ejb-name>
<jndi-name>PhoneBookEntry</jndi-name>
<local-jndi-name>
java:comp/env/ejb/PhoneBookEntryLocal
</local-jndi-name>
<table-name>phone</table-name>
<cmp-field-mapping>
<cmp-field-name>name</cmp-field-name>
<table-column>name</table-column>
</cmp-field-mapping>
<cmp-field-mapping>
<cmp-field-name>phoneNumber</cmp-field-name>
<table-column>phone</table-column>
</cmp-field-mapping>
</entity>
<session>
<ejb-name>PhoneBookSession</ejb-name>
<jndi-name>
org.acme.phonebook.ejb/PhoneBookSession/Home
</jndi-name>
<local-jndi-name>
java:comp/env/ejb/PhoneBookSessionLocal
</local-jndi-name>
</session>
</enterprise-beans>
</openejb-jar>
|
Note: The book Apache Geronimo Development and Deployment by Aaron Mulder has a great visual representation of the structure of this XML file. Basically, this file:
- Defines the entity bean that is deployed inside the container.
- Sets up the Java Naming and Directory Interface (JNDI) name.
- Declares that the bean is an entity EJB.
- Defines the data source that is being used.
- Defines the table name for the table that this entity EJB represents.
- Defines the fields that are container managed with the appropriate columns in the database table that they represent.
That’s it! With a single simple Java class and this deployment descriptor, you've done all that you need to do to deploy an entity EJB. In the past, it took at least a day or two to write entity EJBs. Now, it takes only a couple of hours.
Session EJBs behave essentially the same as entity EJBs when it comes to deployment. In fact, the way XDoclet is used here is similar to how it was used for the entity EJB earlier in the article. PhoneBookSessionBean.java, shown in Listing 5, shows the basics of the deployment descriptor required to work with session EJBs. It's actually much simpler than the deployment descriptor section for entity EJBs.
Listing 5. PhoneBookSessionBean.java
package org.acme.phonebook.ejb;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Phone book session bean. A place for all of the useful business
* methods that can be done with phone book entries.
*
* @ejb.bean name="PhoneBookSession"
* type="Stateless"
* local-jndi-name="java:comp/env/ejb/PhoneBookSessionLocal"
* jndi-name="org.acme.phonebook.ejb/PhoneBookSession/Home"
* view-type="both"
*
* @ejb.permission unchecked="true"
*
* @ejb.interface generate="local,remote"
* remote-class="org.acme.phonebook.ejb.PhoneBookSession"
* local-class="org.acme.phonebook.ejb.PhoneBookSessionLocal"
* @ejb.home generate="local, remote"
* remote-class="org.acme.phonebook.ejb.PhoneBookSessionHome"
* local-class="
* org.acme.phonebook.ejb.PhoneBookSessionLocalHome"
* @ejb.util generate="physical"
* @ejb.ejb-ref ejb-name="PhoneBookEntry" view-type="local"
* ref-name="ejb/PhoneBookEntryLocal"
* @web.ejb-local-ref
* name="ejb/PhoneBookSessionLocal"
* type="Session"
* home="org.acme.phonebook.ejb.PhoneBookSessionLocalHome"
* local="org.acme.phonebook.ejb.PhoneBookSessionLocal"
* link="PhoneBookSession"
*
*/
public abstract class PhoneBookSessionBean implements
javax.ejb.SessionBean {
/**
* Add a phone book entry.
* @param name the name
* @param number the number
*
* @ejb.interface-method view-type="both"
* @ejb.transaction type="Required"
*/
public void addEntry(java.lang.String name,
java.lang.String number) {
try {
PhoneBookEntryLocal entry =
PhoneBookEntryUtil.getLocalHome().
create(name,number);
} catch(Throwable ex) {
ex.printStackTrace();
}
}
/**
* Delete a phone book entry for the given name
* @param name the name to remove
* @ejb.interface-method view-type="both"
* @ejb.transaction type="Required"
*/
public void deleteEntry(java.lang.String name) {
try {
PhoneBookEntryLocal entry =
PhoneBookEntryUtil.getLocalHome().
findByPrimaryKey(name);
entry.remove();
} catch (Throwable ex) {
ex.printStackTrace();
}
}
/**
* Update a phone book entry for the given
* name with the given number.
* @param name the name
* @param number the phone number
* @ejb.interface-method view-type="both"
* @ejb.transaction type="Required"
*/
public void updateEntry(java.lang.String name,
java.lang.String number) {
try {
PhoneBookEntryLocal entry =
PhoneBookEntryUtil.getLocalHome().
findByPrimaryKey(name);
entry.setPhoneNumber(number);
} catch (Throwable ex) {
ex.printStackTrace();
}
}
/**
* Find an entry by name.
* @param name the name to look up.
* @return a phone book entry value representing the entry.
*
* @ejb.interface-method view-type="both"
* @ejb.transaction type="Required"
*/
public PhoneBookEntryValue findEntry(java.lang.String name) {
try {
PhoneBookEntryLocal entry =
PhoneBookEntryUtil.getLocalHome().
findByPrimaryKey(name);
return entry.getPhoneBookEntryValue();
} catch (Throwable ex) {
ex.printStackTrace();
}
return null;
}
/**
* List all of the phone book entries.
* @return a collection of PhoneBookEntryValue objects.
*
* @ejb.interface-method view-type="both"
* @ejb.transaction type="Required"
*/
public java.util.Collection listEntries() {
ArrayList values = new ArrayList();
try {
Collection entries =
PhoneBookEntryUtil.getLocalHome().findAll();
Iterator i = entries.iterator();
while(i.hasNext()) {
PhoneBookEntryLocal entry =
(PhoneBookEntryLocal)i.next();
values.add(entry.getPhoneBookEntryValue());
}
} catch (Throwable ex) {
ex.printStackTrace();
}
return values;
}
/**
* @ejb.create-method
* @ejb.transaction type="Required"
*/
public void ejbCreate ()
throws javax.ejb.CreateException
{
}
public void ejbPostCreate ()
throws javax.ejb.CreateException
{
}
protected javax.ejb.SessionContext _ctx = null;
public void setSessionContext(javax.ejb.SessionContext ctx)
{
_ctx = ctx;
}
protected javax.ejb.SessionContext getSessionContext()
{
return _ctx;
}
}
|
Notice that PhoneBookSessionBean.java really only defines the JNDI names, transaction attributes for the methods, names of the home interface, remote interface, and so on for the session EJB. The other aspects of what you would typically see in a J2EE deployment descriptor for a session EJB are generated using the annotation defined in the Java source code for the session EJB. These include the transaction types for each method and even the fact that the EJB is a stateless EJB.
XDoclet also generates a utility class used to look up the home and remote interfaces. Developers who write EJBs for a lot of different applications will realize the benefit in this. This lookup code is tricky and, honestly, boring to write. Developers are always looking at previous work that they have done or searching the Web to cut and paste this code into new applications that they're working on. Now XDoclet does it for them.
After coding the EJBs and generating the deployment descriptors as described earlier in this article, there are a few more things to do before running Maven to build the code. Listing 6 shows application.xml, which is a required deployment descriptor for Apache Geronimo. This is just a standard J2EE 1.4 requirement. It defines the Java Archive (JAR) files, WAR files, and other external resources that are required as part of this J2EE EAR.
Listing 6. Application.xml
<application
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/application_1_4.xsd"
version="1.4">
<module>
<ejb>phonebook-ejb.jar</ejb>
</module>
<module>
<web>
<web-uri>phonebook.war</web-uri>
<context-root>/phonebook</context-root>
</web>
</module>
<module>
<connector>
tranql-connector-1.0-SNAPSHOT.rar</connector>
</module>
</application>
|
After you have all these XML files in place, you can run the Maven build script provided with the example to quickly build all the source code. This process includes the generation of code using the XDoclet libraries. Maven is somewhat tricky to set up. Follow the steps in the "Dive into EJB Web applications with Geronimo" article to get it up and running.
This article explained how to generate the different deployment descriptors required to deploy J2EE applications using Apache Geronimo. It demonstrated the power of XDoclet and Maven by showing how the coding and deployment of EJBs on a computer running Apache Geronimo is a fairly trivial task.
What must be evident from this article is that the steps for deploying EJB applications on a computer running Apache Geronimo are really no different from those for any other J2EE-compliant application server, such as JBoss, WebSphere, or WebLogic. You can use Maven and XDoclet even if you use other application servers.
| Description | Name | Size | Download method |
|---|---|---|---|
| Source code for example | GeronimoPhonebook2.zip | 128 KB | HTTP |
Information about download methods
Learn
- Learn about the deployment architecture of Apache
Geronimo in the article "Understand Geronimo's deployment architecture."
- Read Neal Sanche's article "Dive into EJB Web applications with Geronimo."
- Find up-to-date information about Apache Geronimo on the Apache Geronimo Wiki Web site.
- Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
- Check out the developerWorks Apache Geronimo project area for articles, tutorials, and other resources to help you get started developing with Geronimo today.
- Check out the IBM Support for Apache Geronimo offering, which lets you develop Geronimo applications backed by world-class IBM support.
- Find helpful resources for beginners and experienced users at the Get started now with Apache Geronimo section of developerWorks.
- Browse all the Apache articles and free Apache tutorials available in the developerWorks Open source zone.
Get products and technologies
- Download Apache Geronimo
code, and obtain documentation and news.
- Download Maven software, and obtain Maven documentation on the Apache Maven Project Web site.
- Download the XDoclet code generation
engine, and get documentation, including EJB tag documentation, from the XDoclet Web site.
- Innovate your next open source development project with IBM trial software, available for download or on DVD.
- Download your free copy of IBM WebSphere® Application Server Community Edition V1.0 -- a lightweight J2EE application server built on Apache Geronimo open source technology that is designed to help you accelerate your development and deployment efforts.
Discuss

Kunal Mittal is a consultant specializing in Java technology, J2EE, and Web services technologies. He is the co-author of and has contributed to several books on these topics. He is currently working on a portal project for Sony Pictures Entertainment. For more information, visit his Web site at http://www.soaconsultant.com.





