|
9.5. Using XDocletXDoclet is an open source code generation engine designed for use with Ant, and you can pick it up for free at http://xdoclet.sourceforge.net/. It'll write code for you, especially deployment descriptors, and is often used for Web and EJB development. XDoclet comes with a number of Ant tasks built-in, shown in Table 9-9.
XDoclet lets you generate code and deployment descriptors by embedding tags in your code, much like the tags you'd use for Javadoc. There are entire books written about XDoclet because it's an extensive tool. Though there's not room for that level of coverage herethis is a book about Ant, not XDocletI'll take a look at several examples creating Web and EJB applications here, giving the XDoclet story from Ant's point of view. 9.5.1. Developing ApplicationsYou use the XDoclet webdoclet task to develop Web applications. The attributes of this task appear in Table 9-10, and the possible nested elements in Table 9-11.
You use tags prefixed with an @ to tell XDoclet what you want it to do. In Example 9-6, in this servlet's code, ServletApp.java, I'm telling Ant how to set up the deployment descriptor, web.xml. Example 9-6. The servlet's code ch09/servlet/ServletApp.javapackage app.web; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; /** * @web.servlet * display-name="Servlet App" * load-on-startup="1" * name="ServletApp" * * @web.servlet-init-param * name="param1" * value="value1" * * @web.servlet-init-param * name="param2" * value="value2" * * @web.servlet-mapping * url-pattern="/app/*" * * @author Steve */ public class ServletApp extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.getWriter( ).println("No worries."); } } To use webdoclet from Ant, you have to use a taskdef task this way to set up the webdoclet task (See Chapter 12): <taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask" classpathref="app.class.path"/> To create web.xml for this servlet, you use a deploymentdescriptor element inside the webdoclet element: <deploymentdescriptor servletspec="2.3" destdir="${app.web-inf.dir}"/> The complete build file appears in Example 9-7. It compiles the code, creates web.xml, and is designed to be used from a directory named build right under the XDoclet directory (xdoclet-1.2.1 is the current version as of this writing), while the servlet's code is stored in the directory build/src/java/app/web. Example 9-7. The servlet's build file ch09/servlet/build.xml<?xml version="1.0"?> <project default="main" basedir="."> <property name="lib.dir" value="../lib"/> <property name="app.dir" value="."/> <property name="app.dist.dir" value="${app.dir}/output"/> <property name="app.src.dir" value="${app.dir}/src"/> <property name="app.java.dir" value="${app.src.dir}/java"/> <property name="app.generated-src.dir" value="${app.dist.dir}/generated-src"/> <property name="app.web-inf.dir" value="${app.dist.dir}/web-inf"/> <property name="app.classes.dir" value="${app.dist.dir}/classes"/> <property name="app.xdoclet.force" value="false"/> <path > <fileset dir="${lib.dir}"> <include name="*.jar"/> </fileset> </path> <target name="init"> <tstamp> <format property="TODAY" pattern="d-MM-yy"/> </tstamp> <taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask" classpathref="app.class.path"/> <mkdir dir="${app.classes.dir}"/> <mkdir dir="${app.generated-src.dir}"/> </target> <target name="webdoclet" depends="init"> <webdoclet destdir="${app.generated-src.dir}" excludedtags="@version,@author,@todo" force="${app.xdoclet.force}" verbose="false"> <fileset dir="${app.java.dir}"> <include name="**/Servlet*.java"/> </fileset> <deploymentdescriptor servletspec="2.3" destdir="${app.web-inf.dir}"/> </webdoclet> </target> <target name="compile" depends="webdoclet"> <javac destdir="${app.classes.dir}" classpathref="app.class.path" debug="on" deprecation="on" optimize="off"> <src path="${app.java.dir}"/> <src path="${app.generated-src.dir}"/> </javac> </target> <target name="main" depends="compile"> <echo>Using XDoclet....</echo> </target> </project> When you run this build file, it'll create a complete web.xml for this servlet; here is the crucial part: <servlet> <servlet-name>ServletApp</servlet-name> <display-name>Servlet App</display-name> <servlet-class>app.web.ServletApp</servlet-class> <init-param> <param-name>param1</param-name> <param-value>value1</param-value> </init-param> <init-param> <param-name>param2</param-name> <param-value>value2</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>ServletApp</servlet-name> <url-pattern>/app/*</url-pattern> </servlet-mapping> In this way, XDoclet can write deployment descriptors for you if you remember to put all needed information in your source code files using XDoclet tags. 9.5.2. Working with EJB ContainersThis XDoclet Ant task executes EJB-specific sub-tasks to support EJB development. You can see the attributes of this task in Table 9-12. The legal nested elements appear in Table 9-13.
The source code for an EJB, Appbean.java, appears in Example 9-8 and shows how the ejbdoclet task works. The embedded XDoclet tags hold data for the ejbdoclet task, which will create a deployment descriptor and write code. Example 9-8. The EJB bean ch09/ejb/Appbean.javapackage app.web; import javax.ejb.*; /** * * @ejb.bean name="App" * description="App example bean" * jndi-name="ejb/App" * type="Stateless" * * @ejb.security-role-ref role-link="Administrator" * role-name="admin" * * @ejb.permission role-name="App" * @ejb.permission role-name="Administrator" * * @ejb.transaction type="Required" * @ejb.transaction-type type="Container" * * @author Steven */ public abstract class AppBean implements SessionBean { /** * Add and return values. * * @ejb.interface-method view-type="remote" */ public double adder(int x, int y) { return x + y; } public void ejbActivate( ) { } public void ejbPassivate( ) { } public void setSessionContext(SessionContext ctx) { } /** * Remove * * @ejb.transaction * type="Mandatory" */ public void ejbRemove( ) { } } In the build file, you use taskdef to tell Ant about the ejbdoclet task: <taskdef name="ejbdoclet" classname="xdoclet.modules.ejb.EjbDocletTask" classpathref="app.class.path"/>
You can create a deployment descriptor, ejb-jar.xml, with the deploymentdescriptor element: <deploymentdescriptor destdir="${app.meta-inf.dir}" description="ejbbean"/> The entire build file appears in Example 9-9. This file is designed to be run from a directory named ejbbuild right under the XDoclet unzip directory with the servlet's code in the directory build/src/java/app/web. Example 9-9. The EJB bean build file ch09/ejb/build.xml<?xml version="1.0" ?> <project default="main" basedir="."> <property name="lib.dir" value="../lib"/> <property name="app.dist.dir" value="output"/> <property name="app.src.dir" value="src"/> <property name="app.java.dir" value="${app.src.dir}/java"/> <property name="app.generated-src.dir" value="${app.dist.dir}/generated-src"/> <property name="app.web-inf.dir" value="${app.dist.dir}/web-inf"/> <property name="app.classes.dir" value="${app.dist.dir}/classes"/> <property name="app.lib.dir" value="lib"/> <property name="app.meta-inf.dir" value="meta-inf"/> <property name="app.xdoclet.force" value="false"/> <path > <fileset dir="${lib.dir}"> <include name="*.jar"/> </fileset> <fileset dir="${app.lib.dir}"> <include name="*.jar"/> </fileset> </path> <target name="init"> <tstamp> <format property="TODAY" pattern="d-MM-yy"/> </tstamp> <taskdef name="ejbdoclet" classname="xdoclet.modules.ejb.EjbDocletTask" classpathref="app.class.path"/> <mkdir dir="${app.classes.dir}"/> <mkdir dir="${app.generated-src.dir}"/> <mkdir dir="${app.meta-inf.dir}" /> </target> <target name="ejbdoclet" depends="init"> <ejbdoclet destdir="${app.generated-src.dir}" mergedir="parent-fake-to-debug" excludedtags="@version,@author,@todo" ejbspec="2.0" force="${app.xdoclet.force}" verbose="false"> <fileset dir="src/java"> <include name="**/*.java"/> </fileset> <remoteinterface/> <localinterface/> <homeinterface/> <localhomeinterface/> <entitycmp/> <entitybmp/> <session/> <deploymentdescriptor destdir="${app.meta-inf.dir}" description="ejbbean"/> </ejbdoclet> </target> <target name="compile" depends="ejbdoclet"> <javac destdir="${app.classes.dir}" classpathref="app.class.path" debug="on" deprecation="on" optimize="off"> <src path="${app.java.dir}"/> <src path="${app.generated-src.dir}"/> </javac> </target> <target name="main" depends="compile"> <echo>Using EJBDoclet....</echo> </target> </project> Running this build file creates EJB interface code and a deployment descriptor, ejb-jar.xml. Here is the relevant part of the generated ejb-jar.xml: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd"> <ejb-jar > <description><![CDATA[ejbbean]]></description> <display-name>Generated by XDoclet</display-name> <enterprise-beans> <!-- Session Beans --> <session > <description><![CDATA[App example bean]]></description> <ejb-name>App</ejb-name> <home>app.web.AppHome</home> <remote>app.web.App</remote> <local-home>app.web.AppLocalHome</local-home> <local>app.web.AppLocal</local> <ejb-class>app.web.AppSession</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> <security-role-ref> <role-name>admin</role-name> <role-link>Administrator</role-link> </security-role-ref> </session> . . . <!-- Assembly Descriptor --> <assembly-descriptor > <!-- To add additional assembly descriptor info here, add a file to your XDoclet merge directory called assembly-descriptor.xml that contains the <assembly-descriptor></assembly-descriptor> markup. --> <security-role> <role-name>App</role-name> </security-role> <security-role> <role-name>Administrator</role-name> </security-role> <method-permission > <role-name>App</role-name> <role-name>Administrator</role-name> <method > <ejb-name>App</ejb-name> <method-name>*</method-name> </method> </method-permission> . . . <!-- transactions --> <container-transaction > <method > <ejb-name>App</ejb-name> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> <container-transaction > <method > <ejb-name>App</ejb-name> <method-intf>LocalHome</method-intf> <method-name>remove</method-name> <method-params> </method-params> </method> <trans-attribute>Mandatory</trans-attribute> </container-transaction> <container-transaction > <method > <ejb-name>App</ejb-name> <method-intf>Home</method-intf> <method-name>remove</method-name> <method-params> </method-params> </method> <trans-attribute>Mandatory</trans-attribute> </container-transaction> . . . </ejb-jar> XDoclet is a powerful tool that's still developing. Currently, you can only run it in Ant, but a command-line tool is in the works. Once you get the hang of it, XDoclet helps with Web and EJB application development in a way that makes sense; when you modify your code, you modify the deployment descriptors and the EJB code you generate at the same time. It's a tool worth watching. |
|