I believe that our team has created something that is generally useful to the xdoclet and j2ee communitities, and am hoping to get a discussion going here with this community with the goal of making a contribution to the Xdoclet project.
In search for ways of simplifying J2EE development even further, we have recently created an xdoclet module, and some supporting framework code, which is described below. We call this "Plain Java Services" or simply "pjs". In addition to the xdoclet extensions, we have created a runtime support framework (such as a service locator, a generic message driven bean, and a command framework for use by the message driven bean). It is a two pass process for xdoclet. The first pass uses our pjs doclet to generate session beans, message driven beans, the business delegates and delegate factories. The second pass simply uses ejbdoclet, Weblogicdoclet (and/or jboss doclet), and springdoclet to create the Session bean related interfaces, deployment descriptors, and spring config. This module, and the accompanying runtime framework is complete and working. Please forgive the cross-post, but I was afraid this message would get buried in the cvs and jira messages on the developer list. Here's a high level description of our project. Purpose The aim of this project is to make it simple to create business services which leverage all the benefits provided by J2EE (Session and Message Driven Beans) by creating those services as plain java classes and interfaces which, themselves, have no container dependendencies. Clients of these services are written to the same interface implemented by the services themselves. This provides the following benefits: - Simplified development of business services, these are written as plain java classes and interfaces. The interfaces will contain annotations, which declaratively describe the required transactional, security semantics as well as synchronicity of methods. - Greatly simplified testing, since no container dependencies are required, simple standalone JUnits are sufficient. - Greatly simplify client development. Clients are written against the service interfaces themselves. A delegate implementation of this interfaces is created automatically by PJS, and may be provisioned in the client either by a factory class (also generated by PJS), by by a Spring ApplicationContext, or directly. Features Here we introduce the notion of Plain Java Services (a.k.a PJS). A Plain Java Service consists of the following hand-written elements: - A Plain Java Interface which defines some business methods and contains annotations (in the form of XDoclet javadoc tags) that describe the deployment (local/remote/both), transactional and run-time call (synchronous vs asynchronous) semantics of the service. These annotations are similar but not identical to the EJBGen tags already in wide use by our developers. - A Plain Java class (POJO), which implements the Plain Java Interface (above). The methods in such a class will contain your applications business logic. Given the annotated interface described above, our pjs doclet, in conjunction with ejbdoclet, weblogic doclet, and spring doclet, generate the artifacts that provide the extra semantics described by the annotations. These artifacts include: - Business Delegate (and J2EE ServiceLocator). Clients will call this (via the Plain Java Service Interface) - Business Delegate Factory. Clients may use this (or Spring, reflections, or direct instatiaion) to obtain an instance of the Business Delegate. - Session Bean source code. Synchronous method calls will be routed here via the Business Delegate. - Session Bean Interface - Session Bean Home Interface - Message Driven Bean source code. Asynchronous method calls will be routed here by the Business Delegate. - Deployment Descriptors - Spring context configuration files I'm providing a sample of what such an interface looks like, and what a generated delegate looks like. This should illustrate the difference between what ejbdoclet provides out-of-the-box, and what we have provided. Here's an example (hand-written) service interface: package order; /** * Order Manager Service * * @pjs.service name="OrderManager" spring-enabled="true" * @pjs.session.ejb.bean view-type="remote" * */ public interface OrderService { order.OrderDTO findOrderById(long orderId); /** @pjs.genBeanMethod type="asynchronous" */ void updateOrder(order.OrderDTO order); } Here's an example business delegate class, generated by pjs: ---------------------------------------------------------------- public class OrderServiceDelegate implements OrderService { public OrderServiceDelegate() {} /** * retrieveDTO * * @return */ public order.OrderDTO findOrderById(long orderId) { try { demo.dto.BaseDTO returnValue = getOrderServiceRemote().findOrderById(orderId); return returnValue; } catch (RemoteException e) { throw new RuntimeException("RemoteException in findOrderById ", e); } } public void updateOrder(order.OrderDTO order) { Object[] args = null; Collection params = new ArrayList(); params.add( baseDTO ); args = params.toArray(); Command command = new SpringBeanCommand(null, "updateOrder", args, "order.OrderService"); sendMessage(command); } protected order.pjsejb.OrderServiceRemoteHome getHome() { try { order.pjsejb.OrderServiceRemoteHome home = order.pjsejb.OrderServiceRemoteHome) J2EEServiceLocatorFactory.getInstance().getLocator().lookupHome(order.pjsejb .OrderServiceRemoteHome.JNDI_NAME, order.pjsejb.OrderServiceRemoteHome.class); return home; } catch (NamingException e) { throw new RuntimeException("Naming Exception in getHome() ", e); } } protected order.pjsejb.OrderServiceRemote getOrderServiceRemote() { try { order.pjsejb.OrderServiceRemote remote = getHome().create(); return remote; } catch (CreateException e) { throw new RuntimeException("CreateException in getOrderServiceRemote() ", e); } catch (RemoteException e) { throw new TavantRuntimeException("RemoteException in getOrderServiceRemote() ", e); } } protected void sendMessage(Command message) { try { QueueConnectionFactory factory = J2EEServiceLocatorFactory.getInstance().getLocator().lookupQueueConnectionFa ctory("OrderServiceConnectionFactory"); QueueConnection queueCon = factory.createQueueConnection(); QueueSession queueSession = queueCon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = framework.J2EEServiceLocatorFactory.getInstance().getLocator().lookupQueue(" OrderServiceQueue"); QueueSender queueSender = queueSession.createSender(queue); ObjectMessage msg = queueSession.createObjectMessage(message); queueSender.send(msg); } catch (NamingException e) { throw new RuntimeException("Naming Exception in sendMessage() ", e); } catch (JMSException e) { throw new RuntimeException("JMS Exception in sendMessage() ", e); } } } ________________________________________________ Tom Drake, Senior Architect, Infrastructure Development Tavant Technologies, Inc. ------------------------------------------------------- This SF.Net email is sponsored by: IntelliVIEW -- Interactive Reporting Tool for open source databases. Create drag-&-drop reports. Save time by over 75%! Publish reports on the web. Export to DOC, XLS, RTF, etc. Download a FREE copy at http://www.intelliview.com/go/osdn_nl _______________________________________________ xdoclet-devel mailing list xdoclet-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/xdoclet-devel