ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Using XDoclet: Developing EJBs with Just the Bean Class

by Dion Almaer
01/30/2002

Have you developed an EJB? Have you been frustrated at having to create and manipulate the XML deployment descriptors, as well as the interfaces? I certainly have. I was recently working on an EJB for the Xbeans open source project and I decided to use another open source tool -- XDoclet -- to generate the XML descriptors and interfaces for me.

Using XDoclet will enable you to work more efficiently within the J2EE framework. You will have a simpler view of your beans and the relationships between them, and many of the annoyances will be taken out of your development.

This article will discuss the XDoclet tool, how to use it, and how to extend it. In this article, we will create a session bean that uses the Javadoc tags, and run XDoclet on the bean.

What is XDoclet?

XDoclet is a tool that has evolved from the original EJBDoclet tool that Rickard Oberg created. The idea was simple: Instead of managing multiple files for each EJB, view the entire component through the Bean class itself. How can this be done? Java doesn't have the "attributes" that .NET is touting, but it does have Javadoc tags. We can place special @ tags into Javadoc comments, and have a Doclet tool that looks for these tags. The tool then generates the appropriate XML descriptors and interfaces for the given set of beans. XDoclet built on the EJBDoclet idea by extending the framework beyond the realm of EJBs. Now you can generate Web Services, Web Application descriptors, and even extend the system to fulfill your individual needs.

The @ tags have a standard format, containing a "namespace" and a "tagname" that belongs to that namespace. Then properties of the tag are passed in via name="value" arguments to the tag. Here is a generic example:

/**
 * @namespace:tag name="value" name2="value2" ...
 */

The current namespaces used are:

ejb
Standard EJB information (not vendor specific).
jboss
Information specific to the JBoss application server.
weblogic
Information specific to the BEA WebLogic application server.
webSphere
Information specific to the IBM WebSphere application server.
orion
Information specific to the Orion application server (Oracle).
castor
Generates mapping information for the Castor framework.
mvcsoft
Generates files for the MVCSoft EJB2.0 persistence manager.
soap
Generates SOAP descriptors.
struts
Generates struts-config.xml from Form and Action.
web
Generates web.xml configuration for Web Applications.
jsp
Generates tag library extension descriptor information.

As you can see, there is substantial support for many frameworks beyond the EJB world (hence the change of name from EJBDoclet to XDoclet).

Session Bean: Create a Session Bean Using the Special Javadoc Tags

Now that we have talked about the tool, let's get into the real example. We will start with a Session EJB. This EJB is part of the Xbeans framework, but for this example, it doesn't matter what the bean does. All we care about is how we take a bean class, "mark it up" with Javadoc tags, and then use XDoclet to generate the meta files for us.

The file ReceiverBean.java will hold the following method: documentReady(Document doc). This method takes a DOM document and passes it to the next Xbean in the chain.

Class Level Definitions

At the class level, we need to define:

  1. The fact that this is a stateless session bean.
  2. The JNDI name.
  3. Environment entries.
  4. Vendor specific attributes (WebLogic pooling information).

Tag: @ejb:bean

The only required attribute for this tag is to tell XDoclet the name of the bean. We will also define the type of bean, the JNDI name to bind the home stub, and the display name:

/**
 *   This is the EJB Receiver Xbean
 *
 *   @ejb:bean type="Stateless"
 *             name="ejbReceiver"
 *             jndi-name="org.xbeans.ejb.receiver.Receiver"
 *             display-name="EJB Receiver Xbean"
 *
 * ... other javadoc tags ...
 */
public class ReceiverBean implements SessionBean, DOMSource {

The most common attributes for the ejb:bean tag are:

name
The name of the EJB (used in descriptors).
type
Defines the bean's "type." For session beans, this is either Stateful or Stateless. For Entities, it is CMP or BMP.
jndi-name
Provides the JNDI name of the bean that will be used in the vendor-specific deployment descriptors (for "remote" interface).
local-jndi-name
Same as jndi-name, but used for the Local interface.
view-type
Indicates which "views" to the bean are to be supported. Either remote or local, or both.

As for all of the tags, check out the documentation to see the full list of options.

Tag: @ejb:env-entry

This tag defines an environment entry that will be configured in JNDI via the special java:comp/env context. We will define an environment entry that the bean will use to look up the next Xbean in the chain:

/**
 *   This is the EJB Receiver Xbean
 *
 * ... other javadoc tags ...
 *
 *   @ejb:env-entry name="channelBean" type="java.lang.String"
 *                  value="com.your.ChannelBean"
 *
 * ... other javadoc tags ...
 */
public class ReceiverBean implements SessionBean, DOMSource {

Tag: @weblogic:pool

Now we will configure the vendor-specific pooling characteristics, using WebLogic for the sake of argument. To denote that we are in a vendor-specific world, we have the weblogic namespace:

/**
 *   This is the EJB Receiver Xbean
 *
 * ... other javadoc tags ...
 *
 *   @weblogic:pool max-beans-in-free-pool="1000"   
 *                  initial-beans-in-free-pool="10"
 *
 * ... other javadoc tags ...
 */
public class ReceiverBean implements SessionBean, DOMSource {

This tag will configure the pooling parameters in the WebLogic-specific deployment descriptor (weblogic-ejb-jar.xml).

Related Reading

Java and XML, 2nd Ed.Java and XML, 2nd Ed.
By Brett McLaughlin
Table of Contents
Index
Sample Chapter
Full Description
Read Online -- Safari

There are many other class-level tags allowing you to tweak anything that you can in the deployment descriptors. Here is a high-level glimpse at some of the "standard" tags that you may want to use in your development:

@ejb:bean
The only compulsory tag, it configures the basics for the bean.
@ejb:home
This tag provides information on the home interfaces. You can tell XDoclet to extend a custom interface, which home interfaces should be generated (none, remote, local,or both), the package the interfaces should be placed into, and more.
@ejb:interface
Similar to the home tag, but configures information related to the component interface (remote and/or local).
@ejb:finder
Defines finder methods on an entity beans home interface.
@ejb:select
Defines select methods on an entity beans home interface.
@ejb:pk
Defines the primary key for an entity bean. XDoclet can generate the primary key class for you.
@ejb:data-object
Data objects (a.k.a value objects) can be automatically generated for entity beans via this tag.
@ejb:ejb-ref
Configures EJB references.
@ejb:ejb-external-ref
Configures EJB references to beans that are located in other applications. Here you need to pass in information such as the type of bean, and home/remote classes.
@ejb:resource-ref
Configures a resource reference.
@ejb:security-role-ref
Configures a security role reference.
@ejb:transaction
Defines the transactional behavior for all methods in remote and home interfaces of this bean with transaction type of type. Can be overridden by using transaction tags on individual methods.
@ejb:permission
Allow the role role-name to call all methods in remote and home interfaces of this bean.
@ejb:security-identity
Specifies whether the caller's security identity is to be used for the execution of the methods of the enterprise bean or whether a specific run-as identity is to be used.

Method-Level Definitions

We want to tag at the method level. If we want a given method to be part of the remote interface, we simply tell XDoclet via a method level tag:

  /**
   *  The method that the sender uses to pass the Document
   *
   *  @ejb:interface-method view-type="remote"
   */
  public void documentReady(Document incomingDocument) {

You will always use this tag. You will go through the methods in your bean class, and if you wish a client to access it, you place this tag above the method signature. If you wanted the access to be via a local interface, you simply change the view-type value to local.

Here are some of the other EJB method-level tags:

@ejb:relation
Defines a relationship for an EJB2.0 CMP Entity bean.
@ejb:home-method
Define the method as an ejbHome* method.
@ejb:persistent-field
Creates the CMP field "X" in the generated CMP layer of type "foo", and concrete implementations of the getX/setX methods. For BMP, it will generate getX/setX methods that keep track of a dirty flag (so that ejbStore is only called when necessary).
@ejb:pk-field
Flags the primary key field.
@ejb:transaction
Defines the transactional behavior for this method (given a valid transactional attribute: NotSupported | Supports | Required | RequiresNew | Mandatory | Never.
@ejb:permission
Defines the methods permission (given a comma-separated list of roles that should be allowed to access this method).

Build: Running XDoclet on the Bean

Now we have one Java source file, ReceiverBean.java, which has been tagged for XDoclet. We need to run XDoclet, telling it to generate all of the fluff for us. The preferred way to run the tool is through the Jakarta-Ant build system. Ant is the ubiquitous Java build system that everyone seems to be using now. If you haven't worked with Ant, check out the Jakarta website, or "Open Source Java: Ant".

The XDoclet folk have developed Ant tasks that we simply place into our build file (build.xml) to invoke the doclet engine. There are two main tasks: <ejbdoclet/> and <webdoclet/>. Since we are working with an EJB, let's peruse the ejbdoclet target in our build file:

<target name="ejbdoclet" depends="prepare">

<taskdef name="ejbdoclet"
         classname="xdoclet.ejb.EjbDocletTask" classpath="${java.class.path};${xdoclet.jar.path};
        ${log4j.jar.path};${ant.jar.path}"/>

<ejbdoclet
sourcepath="${java.dir}"
destdir="${generated.java.dir}"
ejbspec="2.0">

<fileset dir="${java.dir}">
    <include name="**/ReceiverBean.java" />
</fileset>

<remoteinterface/>
<homeinterface/>
<deploymentdescriptor destdir="${build.dir}/ejb/META-INF"/>

<jboss     destdir="${build.dir}/ejb/META-INF"
            version="2.4" xmlencoding="UTF-8" />
<weblogic  destdir="${build.dir}/ejb/META-INF"  
            xmlencoding="UTF-8"
            validatexml="true"/>
<webSphere destdir="${build.dir}/ejb/META-INF" />
<orion     destdir="${build.dir}/ejb/META-INF" />

</ejbdoclet>
</target>

There is a lot of information in this file, so we should break it up and discuss the pieces:

Tag: <taskdef>

First things first; we need to tell the Ant build system about the <ejbdoclet/> tag. We define the name of the tag, the class that implements the tag, and pass in the classpath that it can use. In this case, we use properties that have been set up at the top of the build.xml file that point to the various libraries that we need:

<taskdef name="ejbdoclet" classname="xdoclet.ejb.EjbDocletTask"
classpath="${java.class.path};${xdoclet.jar.path};${log4j.jar.path};
${ant.jar.path}"/>

Tag: <ejbdoclet>

The outermost tag tells Ant to run the EJBDoclet task. We pass in the location of our code, where to generate the XML descriptors and Java source, and the version of the EJB spec we are referring to (again, using properties):

<ejbdoclet
 sourcepath="${java.dir}"
 destdir="${generated.java.dir}"
 ejbspec="2.0">

Tag: <fileset>

We tell the <ejbdoclet> tag where to find our beans, using the <fileset> directive. Our example will find all code named ReceiverBean.java located in any subdirectory of the ${java.dir}:

<fileset dir="${java.dir}">
    <include name="**/ReceiverBean.java" />
 </fileset>

Standard Tags: Interfaces and XML Deployment Descriptors

The next set of tags will make sure that the remote interface, home interface, and standard XML deployment descriptor (ejb-jar.xml) will be generated:

<remoteinterface/>
<homeinterface/>
<deploymentdescriptor destdir="${build.dir}/ejb/META-INF"/>

Vendor-Specific Tags: Interfaces and XML Deployment Descriptors

The final set of tags allow for the generation of vendor-specific deployment descriptors. If you are only deploying your EJBs on one server, you would just have one entry. Since I want my Xbean EJB to be able to be deployed on as many vendor application servers as possible, I placed all of the vendors' tags. It's great that I can generate these vendor-specific files without really knowing anything about the particulars of these app servers!

<jboss     destdir="${build.dir}/ejb/META-INF"
           version="2.4" xmlencoding="UTF-8" />
<weblogic  destdir="${build.dir}/ejb/META-INF"  
           xmlencoding="UTF-8" 
           validatexml="true"/>
<webSphere destdir="${build.dir}/ejb/META-INF" />
<orion     destdir="${build.dir}/ejb/META-INF" />

Now, to build everything for the Xbean EJB, I simply run Ant in the same directory as my build file. I have to make sure that the Ant libraries (ant.jar, jaxp.jar, an XML parser), and the xdoclet.jar file, are in my CLASSPATH. For example, assuming a Windows environment:

% set CLASSPATH=%CLASSPATH%;c:/lib/ant.jar;c:/lib/jaxp.jar;c:/lib/xerces.jar;
  c:/lib/xdoclet.jar;c;/lib/log4j.jar;c:/lib/ejb.jar

% ant ejbdoclet
[runs ant on the ejbdoclet task]

% ant
[runs ant on the default task. In this case it will generate the source, xml descriptors, then compile them, and package everything as an ejb-jar file]

Download the example files from this article here.

Note: Please check out the full build.xml that is part of the examples file accompanying this article/

Extensibility of XDoclet

XDoclet is highly extensible. It has been architected in such a way that you can edit the output of descriptors and interfaces, and create your own through the use of its simple templating mechanism. Each output file has a corresponding template file, with an extension of .j. Open up the xdoclet.jar archive to see a bunch of them. You will see that there are sets of XML tags that have simple logic for knowing what to output from the templates. Here is a simple example taken from the existing EJB template, which will output the display name for the given bean taken from the @ejb:bean display-name property:

<display-name>
 <XDtClass:classTagValue tagName="ejb:bean" 
                         paramName="display-name"/>
</display-name>

This classTagValue XML tag gives a simple interface for displaying a property of a tag. There are a slew of tags that allow for loops, checking if a tag or property exists, and much more. If you ever need to tweak the output or create your own templates, you have support. When would you want to create your own template? How about if you wanted to add support for another application server, or a special O/R database? If you do create your own templates, please submit them to the open source project!

Merge Points: Abstracting XML Deployment Code

Our session bean used the @ejb:env-entry tag to configure an environment variable channelBean with the value com.your.ChannelBean. Do we really want to hard-code this kind of thing in the bean class itself? Maybe not. We have a couple of choices here; one solution is to define the value in the Ant build script. Then, if the value needs to be changed at deploy time we could change the property, and rerun Ant. To make this change we first tweak the build.xml file:

<property name="env-channelBean" value="com.my.ChannelBean" />

and then change the bean class itself:

/**
 *  @ejb:env-entry name="channelBean" type="java.lang.String"   
 *                 value="${env-channelBean}"
 */

Another solution is to use merge points. EJB environment entries have a merge point to allow us the ability to add in our own entries (kind of like a C #include). If we created a file named ejb-entries-<ejbName.xml, it would be sucked into the template mechanism, and will be output in the final ejb-jar.xml.

Conclusion

We have shown how to develop EJBs using XDoclet. This free open source solution can simplify your EJB development, allowing you to work just with a bean class and have the interfaces and descriptors generated for you. This framework is growing, and isn't just for EJBs. Being able to flag methods that you wish to become available via SOAP, configuring your Web applications (even for using Struts) is great. Over time, there will be more and more additions. Some other tools even generate XDoclet tags for you, such as the Middlegen code generation tool for EJB 2.0 Entity Beans.

Dion Almaer is a Principal Technologist for The Middleware Company, and Chief Architect of TheServerSide.Com J2EE Community.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.