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

Reply via email to