 | Level: Intermediate Kunal Mittal (kunal@kunalmittal.com), Java and Web Services Specialist, Consultant
03 Jan 2006 Learn how to deploy Java™Server 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.
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, version 1.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," (developerWorks, July 2005) 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
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. (See Resources for a link to this book.)
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 | Description | Name | Size | Download method |
|---|
| Source code for example | GeronimoPhonebook2.zip | 128 KB | HTTP | Download Director |
|---|
Resources Learn
Get products and technologies
Discuss
About the author  | 
|  | 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. |
Rate this page
|  |