Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Deploy J2EE applications on Apache Geronimo

Use OpenEJB and XDoclet for deployment descriptors

Kunal Mittal (kunal@kunalmittal.com), Java and Web Services Specialist, Freelance Developer
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.

Summary:  Learn how to deploy JavaServer Pages (JSPs), servlets, and different Enterprise JavaBeans (EJBs) on Apache Geronimo. This article includes the deployment steps required for Apache Geronimo, which are different from other Java 2 Platform, Enterprise Edition (J2EE) containers.

Date:  03 Jan 2006
Level:  Intermediate
Also available in:   Japanese

Activity:  13840 views
Comments:  

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.

J2EE deployment process

Apache Maven is used to build and deploy all the code for the example in this article. Therefore, many of the files are Maven-specific build scripts. The output is an Enterprise Archive (EAR) file. After the .ear file is built, you must deploy it on Apache Geronimo by running the following command:
$ java -jar bin/deployer.jar deploy phonebook.ear

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

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
Folder structure

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.


EJBs

Apache Geronimo uses OpenEJB as the EJB container system. The example contains two EJBs:

  • Container-managed entity EJB
  • Stateless session EJB

Container-managed entity 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.

Stateless session EJB

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.


Final steps

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.


Conclusion

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.



Download

DescriptionNameSizeDownload method
Source code for exampleGeronimoPhonebook2.zip128 KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Kunal Mittal

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.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source, Java technology
ArticleID=100962
ArticleTitle=Deploy J2EE applications on Apache Geronimo
publish-date=01032006
author1-email=kunal@kunalmittal.com
author1-email-cc=ruterbo@us.ibm.com