main website home
  • About this blog

    This blog features updates, opinions, and technical notes from Caucho engineers about Caucho products, the enterprise Java industry, and PHP. Caucho Technology is the creator of the Resin Application Server and the Quercus PHP in Java engine. A leader in Java performance since 1998, Caucho is a Sun JavaEE licensee with over 9000 customers worldwide.
  • Tags

    ajaxworld bam candi cdi cloud cluster comet configuration deploy devoxx eclipse ejb embedded flash flex google app engine hessian hmtp ioc java ee 6 javaone javazone jms messaging newsletter nyjug osgi php pomegranate quercus resin resin 4.0 REST servlet sfjug silicon valley code camp spring testing training tssjs watchdog webbeans web profile websockets wordpress
  • Meta

    • Register
    • Log in
    • Entries RSS
    • Comments RSS
    • WordPress.org
« Subetha on CanDI
pomegranate modules »

Java CanDI Injection in subetha

Studying the source code for a full application is the best way to really understand a technology like Java Injection (CanDI, JSR-299). Fortunately, Jeff Schnitzer, Scott Hernandez, and Jon Stevens have created a subetha mail, an open-source Java implementation of a mail list manager (like mailman) using CanDI extensively. Because subetha is also a sophisticated JavaEE application using EJB @Stateless beans, JMS queues with EJB @MessageDriven beans, servlets, and Hessian remote services, it’s a great overall application to study.

  • Services: CanDI and EJB @Stateless
  • Extensions and Plugins
  • Initialization with CanDI
  • Servlets with CanDI
  • Queue message listeners
  • XML configuration
  • Hessian Services
  • Conclusions
  • subetha CanDI/XML classes and patterns

Services

When looking at new source, I find it easiest to search for the main services, because the services give a quick roadmap to the architecture. Once I’ve got a mental map of the source, it’s easier to see how classes and functions fit into the design. From reading subetha, CanDI nicely identified the main services because they are either marked with @ApplicationScoped, @Service or @Stateless. Since subetha uses message queues, the two EJB @MessageDriven beans also act as services.

@ApplicationScoped services tend to store runtime state, while @Stateless services generally encapsulate persistence (JPA), database, or other transactional state, and @MessageDriven beans read from queues. Because all of the services are singletons, subetha uses the CanDI @Current injection binding type to wire them up. No XML is required.

A typical example of the subetha wiring is the InjectorBean @Stateless EJB which receives new mail messages, parses them and dispatches them to the inject queue for further processing. The CanDI @Current annotation wires four subetha services: FilterRunner, Encryptor, Detacher, and PostOffice. The subetha InjectorBean also uses CanDI to bind the JMS queue with a custom @BindingType @InjectQueue and a JavaMail session with a binding type @OutbountMTA. Finally, the @SubEtha binding type requests the internal SubEthaEntityManager, a DAO which encapsulates the JPA data store.

@Stateless(name="Injector")
@RolesAllowed(Person.ROLE_ADMIN)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class InjectorBean implements Injector
{
  @Current FilterRunner filterRunner;
  @Current Encryptor encryptor;
  @Current Detacher detacher;
  @Current PostOffice postOffice;

  @InjectQueue inboundQueue;
  @OutboundMTA Session mailSession;

  @SubEtha SubEthaEntityManager em;
 ...
}

This one class illustrates how CanDI encourages a declarative style of Java injection, as well as how EJB 3.0 has simplified. With CanDI, you describe the services and resources needed with the binding types, and use CanDI to bind the services together. The binding types are a small number of custom annotations which specify exactly what resource you want. Because they’re Java annotations, they are documented in JavaDoc and checked by the compiler. Subetha uses 6 binding types in total. When you have a singleton service, you’ll use @Current. When you have multiple resources, like subetha’s queues, you’ll create a descriptive annotation like @InjectQueue.

Like CanDI, the EJB configuration is configured by annotations, without relying on any XML. By keeping all the configuration and binding information to the class, the class becomes self-documenting: you don’t need to read the XML side by side with the classes to understand what’s going on. For InjectBean, the @Stateless annotation is all that’s necessary to declare a stateless EJB. The @TransactionAttribute protects the methods with transactions, and the @RolesAllowed ensures that only admin users can access the InjectBean.

Extensions and Plugins

We all want out software to be flexible and extensible, and CanDI can help creating a simple plugin system. Subetha has two plugin types: Filters and Blueprints, and uses CanDI to discover all extension classes. Because CanDI already scans all the classes, it automatically lets you query existing plugins using the BeanManager class.

class BeanManager {
  Set getBeans(Type type. Annotation...bindings);
}

In subetha, the Filters and Blueprints are gathered in a startup service and stored in a FilterRegistry and BlueprintRegistry.

Initialization Services

An interesting use of CanDI in subetha is using a @Startup service for initialization. Since Resin’s CanDI automatically starts any bean marked with @Startup, subetha can declare all its startup in the class itself without relying on any XML configuration.

Servlets

The subetha servlets use CanDI to bind services to the servlets, making servlets look just like CanDI services. An example is the InjectorServlet, which allows POST of new messages and uses the Injector service to do the actual work.

public class InjectorServlet extends HttpServlet
{
  @Current AccountMgr accMgr;
  @Current Injector inj;
  @Current SubEthaLogin resinLogin;
  ...
}

Message Listeners (MDB)

Subetha uses two queues to store and process messages: an @InjectQueue for inbound messages and a @DeliveryQueue to send messages to JavaMail. To process the messages, subetha has two corresponding @MessageDriven beans, InjectListener and DeliveryListener. Like the services, the message listeners describe the services to use with binding type annotations and rely on CanDI for the binding.

@MessageDriven
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class InjectListener implements MessageListener
{
  @DeliveryQueue BlockingQueue outboundQueue;
  @SubEtha SubEthaEntityManager em;

  public void onMessage(Message qMsg)
  ...
}

XML configuration

While CanDI eliminates XML for wiring, you still need to configure resources and may need user-customization. For example, databases and JavaMail services need specific configuration. I’ve pulled out two examples from the subetha configuration that illustrate interesting CanDI concepts: configuring a subetha service, and configuring a @BindingType for a standard JMS queue.

subetha has one main configurable service, the SMTPService, which listens for new messages, and which users may want to change the IP address or TCP port. The XML for the service uses the class package and name as <smtp:SMTPService> and configures properties using XML tags.

<web-app xmlns="http://caucho.com/ns/resin"
       xmlns:resin="urn:java:com.caucho.resin"
       xmlns:smtp="urn:java:org.subethamail.core.smtp">

  <smtp:SMTPService>
     <port>2500
     <bindAddress>192.168.1.10</bindAddress>
     <fallbackHost>localhost:2525</fallbackHost>
  </smtp:SMTPService>

subetha also uses XML to configure the JMS queues and binds the queues to the subetha custom binding types, @InjectQueue and @DeliverQueue. The configuration looks like the following:

<web-app xmlns="http://caucho.com/ns/resin"
       xmlns:resin="urn:java:com.caucho.resin"
       xmlns:queue="urn:java:org.subethamail.core.queue"
       xmlns:smtp="urn:java:org.subethamail.core.smtp">

  <jms:FileQueue>
    <queue:InjectQueue/>
    <Named>inject</Named>
  <jms:FileQueue>

  <ejb-message-bean class="org.subethamail.core.queue.InjectListener">
    <destination>#{inject}</destination>
  <ejb-message-bean>

Hessian web services

Interestingly, subetha has chosen to expose several of its services as Hessian services. Because Hessian works with serializable Java classes (with a zero-arg constructor), the Java code itself is independent of Hessian. The Hessian services are declared in the XML, like servlets:

<web-app xmlns="http://caucho.com/ns/resin">

  <servlet-mapping url-pattern="/api/AccountMgr"
                   servlet-class="org.subethamail.core.acct.AccountMgrBean">
     <protocol uri="hessian:"/>
  </servlet-mapping>

</web-app>

Conclusions

Since one of the major difficulties with any new technology like CanDI is discovering the useful patterns (and anti-patterns), having a well-written, complete example to study is invaluable. Subetha, along with being well-written and designed, is a particularly good example because it intelligently uses the bulk of the important JavaEE 6 technologies: CanDI, EJB @Stateless beans, Servlets, JSP, JMS queues and EJB MDB beans, as well as commonly used technologies like Velocity and Hessian web services.

For me, it’s also nice to look through some code showing how CanDI will be used in practice, because my perspective as an implementer of CanDI is different from people actually using the spec. In particular, it was good to see the advantages of the declarative injection style with self-documenting annotations actually work out in practice. Plus, as something of a surprise, to see the importance of the @Startup services and to see the CanDI plugin capabilities used in one of the first full CanDI applications.

subetha CanDI/EJB classes and patterns

Patterns

  • Singleton state services
  • Startup beans
  • EJB session bean managers
  • Extension beans
  • Servlets
  • Scheduled tasks
  • Named resources
  • Queues - JMS using BlockingQueue and EJB message-driven beans.

BindingTypes

  • @Current - standard bindings used for most services
  • @OutboundMTA - SMTP Session resource
  • @SubEtha - JPA EntityManager
  • @DeliveryQueue - JMS queue
  • @InjectQueue - JMS queue
  • @Name - used for Resin resources (should be changed)

Service Beans (@ApplicationScoped and @Service)

  • PostfixTcpTableService - incoming connection service
  • EncryptorBean - encryption/decription service
  • FilterRunnerBean - runs filters on message
  • ListWizardBean - creates a list from a Blueprint
  • SMTPService - wrapper around SMTPServer for main outgoing msgs

Init/Startup Beans

  • BootstrapperBean - used for a fresh install
  • ScannerService - scans for blueprints and filters on startup
  • VelocityService - velocity initialization on startup

Servlets

  • Backend - repository for services
  • ArchiveServlet
  • ExportServlet
  • InjectorServlet
  • ListServlet

Scheduled Tasks

  • IndexerBean
  • CleanupBean

Stateless Beans

  • AccountMgrBean - updates a user record
  • AdminBean - subscribe/unsubscribe
  • DeliveratorBean - delivers messages
  • DetacherBean - multipart-mime
  • InjectorBean - parses incoming and sends to injector queue
  • ArchiverBean - access to the message archive
  • ListMgrBean - mailing list management
  • PostOfficeBean - sends system mail messages to users

Queues and Message Driven Beans

  • @InjectQueue - inbound messages
  • @DeliveryQueue - outbound messages
  • DeliveryListener
  • InjectListener

Hessian

  • AccountMgrBean
  • AdminBean
  • ListWizardBean
  • InjectorBean
  • ArchiverBean
  • ListMgrBean
  • IndexerBean
  • EegorBringMeAnotherBrainBean

Tags: candi, ejb, resin

This entry was posted on Monday, June 8th, 2009 at 12:08 pm and is filed under Engineering. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply

You must be logged in to post a comment.


Caucho Technology is proudly powered by WordPress and Quercus®
Entries (RSS) and Comments (RSS).

  • HOME |
  • CONTACT US |
  • DOCUMENTATION |
  • BLOG |
  • WIKI 4 |
  • WIKI 3 |
  • Resin: Java Application Server
Copyright (c) 1998-2012 Caucho Technology, Inc. All rights reserved.
caucho® , resin® and quercus® are registered trademarks of Caucho Technology, Inc.
resin® is a cloud optimized, java® application server that supports the java ee webprofile ®