Skip to main content

Dive into EJB Web applications with Geronimo

Adding Maven, Struts, and XDoclet to the mix

Neal Sanche (neal@nsdev.org), Java developer and author, Freelance
Neal Sanche is a Java developer recently beached in the Microsoft® .NET world and fighting for any ties back to his old, comfortable roots. His experience includes development of several commercial J2EE applications, as well as several stand-alone Java applications. In his spare time, he writes music, takes photographs, and writes technical articles. See several examples at his Web site. Contact Neal at neal@nsdev.org.

Summary:  Dive deeper into the inner workings of the powerful Apache Geronimo application server, and learn how to use it to develop database applications. Java™ Developer Neal Sanche began the voyage with the article, "Three ways to connect a database to a Geronimo application server" (developerWorks, June 2005), which leads you through creating a simple phonebook database application. In this article, you'll see how the initial database application is extended and provided with a functional user interface built using Apache Struts and an Enterprise JavaBeans (EJB) back end. You'll also discover how to use the Apache Maven build system to build, package, and deploy the phonebook database application. Use this article to learn how to simplify your enterprise Web application development process.

Date:  19 Jul 2005
Level:  Introductory
Activity:  1466 views

Technology overview

Before jumping into the example application, you might want to get your feet wet first by taking a closer look at the three technologies that will be used to create and deploy the application. (To read more about each of these technologies, see Resources for links.

Maven is an application for building Java applications, from source code to packaging to Web sites. The Geronimo application server was built using the Maven application's build system. At its core, Maven's extensible framework allows the creation of modules that perform several actions involved in building software components. Related to Apache Ant -- the Java build tool -- Maven's actions have been compared to the results generated by using the UNIX command make. Maven scripting also lets you automatically deploy your application into a running Geronimo server. This article shows how you can use Maven to package your source code into a full Java 2 Platform, Enterprise Edition (J2EE) enterprise application.

Struts is a Web application framework based on the Model 2 architecture (see Resources for a link to a good description of the JSP Model 2 architecture). This hybrid architecture separates business logic and display logic as much as possible. Struts accomplishes this by separating business logic into pure Java classes that do the work of manipulating your data, as well as providing a rich tag library that can be used to display the data when it's time to write JavaServer Pages (JSPs). (Of the myriad Web development frameworks available -- many with high acclaim, such as Tapestry and JavaServer Faces -- Struts continues to be one of my favorites.)

XDoclet has its roots in the long-time Java documentation tool, Javadoc. The developers of XDoclet originally used Javadoc in a novel way, using specialized comments to generate a model that can then be compiled into source code.They moved away from the actual use of Javadoc, producing their own variant called Xjavadoc. However, the use of tags in the Javadoc comments of your source code to produce automatically generated code still remains unchanged from the early days of XDoclet. Writing the source code and deployment descriptor files in a J2EE application can be tedious. For every one hundred or so lines of Java code, you can expect to generate at least three times as much supporting J2EE descriptor code to get the job done. To reduce much of the pain of developing a multitiered enterprise application, XDoclet comes to the rescue, providing code tagging and code generation so that the deployment descriptors are mostly generated automatically. This hides a lot of the complexity of J2EE, but be aware of what the code generator is building, because you'll have to read through it if things don't go as you expect.


Deployment plans

As mentioned in the introduction, the Geronimo team uses Maven to build the entire application server. You can harness the power of the Maven build tool to compile your application source code, perform code generation (with the help of XDoclet), bundle your enterprise application modules, and finally deploy them to your running Geronimo server.

The process starts with three files. The first, project.xml, defines what is commonly referred to as the Project Object Model (POM). It lists the pertinent information about your application -- including the application name -- who's involved with writing it, its version number, the dependencies that are important to build the application, and a general statement of how to build the application. For the purposes of this article, you're mainly concerned with the dependencies section of the POM. (See Resources for a link to the entire POM file.)

Maven uses the dependencies section of project.xml to download the artifacts it needs to build an application from designated repositories on the Internet. One such repository, iBiblio (see Resources for a link), contains hundreds of open source Java libraries and supporting files, as well as POM information for those libraries. It has a wealth of information collected for the sole purpose of simplifying the Java developer's life during the application build process. The dependency section of the project.xml file for the phonebook application consists of 23 dependencies, half of these being .jar files needed to support Struts and the DisplayTag tag library. The rest of the dependencies are mainly XDoclet requirements. Without Maven, each of these dependencies would need to be bundled with the sample application.

Maven simply downloads all the dependent artifacts the first time the application is compiled. Subsequent compilation runs draw on Maven's local repository (a local cache of the downloaded artifacts usually found in a .maven directory of your $HOME directory) for the artifacts there.

Install Maven 1.0.2

Our example application requires some initial setup of Maven for everything to work correctly. First you need to install Maven 1.0.2 (see Resources for a link to the Maven Web site). After installation is complete, type maven at your command line. You'll see information similar to the following displayed:

E:\Documents and Settings\Neal\My Documents\eclipse\workspace\Phonebook> maven
 __  __
|  \/  |__ _Apache__ ___
| |\/| / _` \ V / -_) ' \  ~ intelligent projects ~
|_|  |_\__,_|\_/\___|_||_|  v. 1.0.2

Compile Geronimo

Next, compile Geronimo from source code following the instructions found on the Wiki (see Resources for a link). After a successful build, the Geronimo artifacts are in your local repository. They are required for building the sample application. After Geronimo is compiled, find and install the geronimo-deployment-plugin-1.0-SNAPSHOT.jar file into your $MAVEN_HOME/plugins directory; otherwise you may see a message like the following:

Tag library requested that is not present: 'geronimo:deploy' in plugin: 'null'

Install XDoclet 1.2.3

Finally, install XDoclet 1.2.3 into your Maven repository. If, when trying to build the sample application, a Maven message appears stating that it can't find some of the other XDoclet 1.2.3 artifacts, you might need to download the XDoclet 1.2.3 (lib bundle) and extract the .jar files in your local Maven repository under .maven/repository/xdoclet/jars (see Resources for a link to the XDoclet Web site). If you're a Windows user, you should find this Maven directory under your C:\Documents and Settings\username directory. If you're a UNIX user, you should find this directory under your home directory. You should also install the XDoclet Maven plug-in by adding the maven-xdoclet-plugin-1.2.3.jar into your $MAVEN_HOME/plugins directory.

The successful build

After you have these prerequisites in place, the build process should go smoothly. Of course, you can attempt the build before doing the above work and see which files Maven cannot find, and then install only those files. You can try running Maven inside the sample application's top directory. At first, many artifacts will be downloaded, and at the end, you'll see the BUILD SUCCESSFUL message.

To understand a little more about what Maven is doing, take a look at the maven.xml and project.properties files. Maven is goal oriented. It reads through maven.xml and attempts to satisfy all the goals specified in the default attribute of the top-level project element. In this case, it tries to satisfy everything that the deploy goal states as its prerequisites; namely, it will try to build the .ear file, then it tries to stop and start the application. The deployment of the application is performed by the Geronimo Deployment Maven plug-in mentioned earlier. Of course, your Geronimo server should be running -- otherwise your build will fail with a message similar to this:

Failed to retrieve RMIServer stub: javax.naming.ServiceUnavailableException 
[Root exception is java.rmi.ConnectException: Connection refused to 
host: 10.0.0.7; nested exception is:
        java.net.ConnectException: Connection refused: connect]

If you receive this message, start your Geronimo server using a command like the following:

E:\geronimo-snapshot>java -jar bin\server.jar org/apache/geronimo/
DebugConsole org/apache/geronimo/RuntimeDeployer

This command tells Geronimo to start its server, the DebugConsole application configuration, and the RuntimeDeployer configuration.

The debug console

The DebugConsole (shown in Figure 1) is an optional component that lets you view what's running inside a Geronimo server through a small Web application (see http://localhost:8080/debug-tool).


Figure 1. The Geronimo DebugConsole
The Geronimo DebugConsole

Sample top page

After you've built the example application, you can visit its top-level page where you'll see something much like Figure 2.


Figure 2. The Geronimo Phonebook example application built with Struts 1.2.7
The Geronimo Phonebook example application built with Struts 1.2.7

Post application build: A look under the hood

Now that you've successfully built the application and have seen the power and simplicity of using Maven, it's time to take a look at the file layout and some of the code necessary to make it all happen. The Web application layer will be explained first, followed by the EJB layer. Finally you'll see the connective tissue -- the deployment plans and configuration files that tie everything together and make it all work. Refer to the file directory tree shown in Figure 3 as a reference to where you can find the files.


Figure 3. Directory layout of the sample application files
Directory layout of the sample application files

The Web application layer

The Web application is written using JSPs and the Struts 1.2.7 framework. In the src/webapp directory you'll find the files that comprise the sample application's Web interface.

This application consists of two main views: the phone number list and the phone number edit screen. All the required features for editing simple records from a database (add, delete, edit, update, and list) are present. The src/java/org/acme/phonebook/struts directory contains a number of Struts actions that perform these required functions, such as creation of new entries, deletion of entries, listing all the entries, and editing existing entries.

The Struts Tiles template system was used to ensure that minimal effort was spent making the Web application look the way it does. The site-template.jsp file in the webapp/pages directory defines the look for the application.

The two main JSPs that will be explained are the EditPhoneNumberPage.jsp and the ListPhoneNumbersPage.jsp. Each of these pages and its function in the application is described in Listing 1.


Listing 1. EditPhoneNumberPage.jsp
<%@ page language="java"%>
<%@ taglib uri="/tags/struts-bean" prefix="bean"%>
<%@ taglib uri="/tags/struts-html" prefix="html"%>
<%@ taglib uri="/tags/struts-tiles" prefix="tiles"%>
<tiles:insert page="/pages/site-template.jsp" flush="true">
       <tiles:put name="content" type="string">

<hr>
<h1><bean:message key="h1.EditPhoneNumberPage" /></h1>
<hr>

<h2><bean:write name="phoneBookEntryForm" property="action"/>
</h2>

<html:form action="/pages/SaveEntry.do">
<table>
  <tr>
  <td>
<bean:message key="prompt.EditPhoneNumberPage.name" />
  </td>
  <td>
<html:text property="name" size="40" />
  </td>
  </tr>
  <tr>
  <td>
<bean:message key="prompt.EditPhoneNumberPage.phoneNumber" />
  </td>
  <td>
<html:text property="phoneNumber" size="40" /></td>
  </tr>
  <html:hidden property="action" />
  <html:hidden property="pk" />
  <tr>
  <td></td>
  <td>
<html:submit>
<bean:message key="button.submit" />
</html:submit> <html:reset>
<bean:message key="button.reset" />
</html:reset>
  </td>
  </tr>
  </table>
  </html:form>
  </tiles:put>
</tiles:insert>

In Listing 1, the first few lines set up the tag libraries that will be active within the page. They also set up the content area of the site template as the location where the content will be displayed. This example shows a simple Struts-based entry form with some <bean:message> tags to show strings from a resource file (located in webapp/WEB-INF/classes/resources/application.properties). The form submits a name and a phone number to a Struts action called SaveEntry.do.

If you look at the class Javadoc tag in the SaveEntry.java source file in Listing 2, you'll see the first example of XDoclet tags in this application. These tags define all of the properties necessary to generate the Struts deployment descriptor, which is called struts-config.xml.


Listing 2. SaveEntry.java JavaDoc class tag.
/**
 * Save an Entry
 * 
 * @struts.action
 *    name = "phoneBookEntryForm"
 *    path = "/pages/SaveEntry"
 *    scope = "request"
 *    input = "/pages/EditPhoneNumberPage.jsp"
 *    unknown = "false"
 *    validate = "false"
 * @struts.action-forward
 *    name = "success"
 *    path = "/pages/ListNumbers.do"
 *    redirect = "true"
 */

This code sample, in a nutshell, demonstrates that this action, called /pages/SaveEntry, takes its input from the EditPhoneNumberPage.jsp and uses a phoneBookEntryForm to marshal the user's input from the page to the Java code. After the action is complete, it redirects to the /pages/ListNumbers action to display the number list.

The ListNumbers action, which you can find in the ListNumbers.java file, makes a call to the Session EJB, called PhoneBookSession, using the code in Listing 3.


Listing 3. Excerpt of the execute() method of the ListNumbers action.
PhoneBookSessionLocal session = 
      PhoneBookSessionUtil.getLocalHome().create();

// Call the method
Collection c = session.listEntries();

// Put the retrieved information into the request attributes
// so the page can render them.
request.setAttribute("numbers", c);

As shown in Listing 3, you can see the use of a PhoneBookSessionUtil class. This is an XDoclet-generated class that helps with getting the home interfaces of the PhoneBookSession object. A session is created and its listEntries() method is called, which returns a collection of all the phone book entries. Then the numbers attribute in the request object is set to that collection. This has the effect of putting the phone numbers into a named location that the JSP page that is used to display the entries can retrieve and use to write out the list, as shown in Listing 4.


Listing 4. Display Tag in ListPhoneNumbersPage.jsp
<display:table name="numbers" requestURI="ListNumbers.do" 
    scope="request" pagesize="5" id="row_obj">

    <display:column property="name" title="Name"/>
    <display:column property="phoneNumber" title="Phone"/>

    <display:column title="Actions">
         <logic:present name="row_obj">
              <html:link action="/pages/EditEntry" 
                    paramId="id" paramName="row_obj" 
                    paramProperty="name">Edit</html:link>
              <html:link action="/pages/DeleteEntry" 
                    paramId="id" paramName="row_obj" 
                    paramProperty="name"  
                    onclick="return confirmDelete('Number')">
                    Delete
              </html:link>
         </logic:present>
    </display:column>
...
</display:table>

The EJB layer

There are two EJB classes in this application. The first one, which uses Container-Managed Persistence (CMP) to provide object-based access to a simple database table, is called PhoneBookEntryBean. The second class is a stateless session bean, which provides the business logic. Often it's desirable to manipulate CMP beans through a stateless session bean, because session beans can be set up to provide transactions on the database so that updates can be rolled back in the event of an error. Also, performing all CMP operations in a session bean shields the Web application from having to know any of the implementation details of the database access layer. So if replacement of that layer with another technology occurs (such as using a Hibernate persistence layer), the code in the Web application won't need to be changed.

XDoclet is used heavily in the EJB layer to provide the deployment descriptor generation. This is important to reduce the maintenance effort required to build this type of application. Download the source code and look at the class Javadoc comments for both PhoneBookEntryBean.java and PhoneBookSessionBean.java to see many of the XDoclet tags used to define EJB classes.

To generate a method on the stateless session bean, it's sufficient to add an XDoclet tag, called @ejb.interface-method, with a view-type property of local, remote, or both. This tells XDoclet to generate the appropriate methods in the local interface, remote interface, or both interfaces for the session bean. You can also control the transaction type. See Listing 5 for an example of one of the interface methods for listing phonebook entries and returning their value object representations.


Listing 5. listEntries() method of the PhoneBookSessionBean.java class
/**
 * 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;
}


The connective tissue

In my previous article, "Three ways to connect a database to a Geronimo application server" (developerWorks, June 2005), the importance of Geronimo's various deployment plans was explained in detail. Getting this small application to a functional state was very challenging and required many small options to be present within the deployment plans, as well as interactions between XDoclet tags, the code the tags generate, and the deployment plans. Going through the details, however, is beyond the scope of this article. The example program has many configuration files and deployment plans, nearly all of which are found in the src/resources subtree of the project. The following paragraphs briefly describe the pertinent details of these files to show where you'd need to make modifications to get future applications working.

The ear subdirectory contains the enterprise application deployment descriptors, the application.xml file, and the geronimo-application.xml file. In this application, these files are configured to provide an application-scoped Java Database Connectivity (JDBC) connector. Read "Three ways to connect a database to a Geronimo application server" (developerWorks, June 2005) for details on doing that. The mysql-plan.xml and tranql-connector-1.0-SNAPSHOT.rar files are part of this configuration, as well as module definitions in both the application.xml and geronimo-application.xml files, to cause the runtime deployer to set up the JDBC connector properly.

The geronimo-application.xml file contains an <application> element that has an attribute called configId. This element is essential to the correct operation of the automatic deployment feature of the Maven build script. The value this is set to can be used in the id attribute of any <deploy:*> tags in the maven.xml file, as shown in Listing 6.


Listing 6. maven.xml start goal.
<goal name="start">
 <deploy:distribute
   uri="deployer:geronimo:jmx:rmi://localhost/jndi/rmi:/JMXConnector"
   username="system"
   password="manager"
   home="${basedir}"
   module="target/${pom.artifactId}.ear"
 />
 <deploy:start
   uri="deployer:geronimo:jmx:rmi://localhost/jndi/rmi:/JMXConnector"
   username="system"
   password="manager"
   id="org/acme/PhoneBook"/>
 </goal>

In Listing 6, because the configId attribute in the geronimo-application.xml file is set to org/acme/PhoneBook, it must also be the value of the id attributes in the automatic deployment statements. The Geronimo team has designed a nice, automated deployment facility here. However, if you often deploy automatically, make sure to check your temp directories, because they could be filling up with old deployment files.

Next in our list of subdirectories, in the resources directory, is the ejb directory. Inside the META-INF subdirectory is the openejb-jar.xml deployment descriptor. This file is essential for making all the linkages between your database and your entity (CMP) beans. It's also necessary to make small modifications to this file to ensure appropriate Java Naming and Directory Interface (JNDI) names are present for your enterprise beans. This file is shown in Listing 7.


Listing 7. 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>
            <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>
            <local-jndi-name>
                  java:comp/env/ejb/PhoneBookSessionLocal
            </local-jndi-name>
        </session>
    </enterprise-beans>
</openejb-jar>

The most important element of Listing 7 is <cmp-connection-factory> and its <resource-link> subelement. The name inside the <resource-link> element must match the name of the JDBC connector configuration, as shown in the following excerpt:

...
<connectiondefinition-instance>
       <name>MysqlDataSource</name>
...

The <local-jndi-name> elements in the openejb-jar.xml elements are also essential to get things to work. If you receive errors about JNDI names not being found, you've probably set one of these elements incorrectly.

Also of note in Listing 7 are the <table-name> and <table-column> elements for your entity beans, where you must configure which database tables and columns map to the entity bean fields. See the <cmp-field-mapping> elements in Listing 7 for two examples of doing this.

The last directory is the src/resources directory named merge. The contents of this directory relate directly to the way XDoclet code generation is performed. XDoclet takes information from Javadoc tags, but it also merges information in specially named files inside a merge directory. These merge files contain some of the configuration information for the Web application layer. In the src/resources/merge directory of the project, the taglibs.xml file allows all the tag libraries in the application to be defined. There are also many of the files that are merged into web.xml and struts-config.xml when XDoclet generates them.

Another deployment plan exists in the src/webapp/WEB-INF/geronimo-jetty.xml file shown in Listing 8.


Listing 8. geronimo-jetty.xml
<?xml version="1.0"?>
<web-app
      xmlns="http://geronimo.apache.org/xml/ns/web/jetty"
      xmlns:naming="http://geronimo.apache.org/xml/ns/naming"
      configId="org/acme/PhoneBookWeb"
      >

    <context-priority-classloader>true</context-priority-classloader>

</web-app>

The M4 release of Geronimo has renamed the geronimo-jetty.xml deployment plan to geronimo-web.xml. As a result, you need to remove /jetty in Listing 8 if you're using the M4 release. All other code will run as described in the article with Geronimo M4.

This deployment plan, shown in Listing 8, has one important line in it. Without the <context-priority-classloader> element set to true, the Struts application is unable to run because of conflicts in the classes available in the Geronimo library. Setting this value to true tells Geronimo to use standard Web application scoping when looking up classes. This means that the application is insulated from any other applications running in the server. But it also means that any classes the application needs must be bundled with the application.

All of the bundling of .jar components that the application depends on are specified in the project.xml dependencies section and are handled automatically by Maven.

The final configuration file, named project.properties, drives much of the build process and is located in the root directory of the project. This file is a storehouse of XDoclet-related information and information about what to include inside .war files, and even properties that control the Java compiler output formats.

Putting all of these elements together takes a lot of time, but hopefully you'll be able to use this example application as a stepping stone along your way.


Summary

This article provides a very basic starting template for a much larger application. In adding more CMP beans and session beans for business logic, you can create a more interesting Web application. I've demonstrated the definite benefits of the Maven build system for reducing the complexity of compiling and producing the nested file structure of the final .ear file. The XDoclet code-generation system was also used to simplify the process of generating the EJB artifacts, the Struts artifacts, and the Web application artifacts necessary for compiling the final phonebook application. Using this sample application, you should now be able to take advantage of Maven and XDoclet to simplify your enterprise application development process.

Geronimo developers have carefully crafted the server itself, following the Sun J2EE specifications, and have produced a product that clearly separates deployment and configuration issues from the details necessary for the container to host the application.



Download

DescriptionNameSizeDownload method
Source code for the example phonebook applicationGeronimoPhonebook2.zip128 KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Neal Sanche is a Java developer recently beached in the Microsoft® .NET world and fighting for any ties back to his old, comfortable roots. His experience includes development of several commercial J2EE applications, as well as several stand-alone Java applications. In his spare time, he writes music, takes photographs, and writes technical articles. See several examples at his Web site. Contact Neal at neal@nsdev.org.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source, Java technology, WebSphere
ArticleID=89138
ArticleTitle=Dive into EJB Web applications with Geronimo
publish-date=07192005
author1-email=neal@nsdev.org
author1-email-cc=ruterbo@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers