Embeddable EJB 3.0

JBoss EJB 3.0 supports an embeddable version that can be run outside of the application server in standalone applications, junit tests, Tomcat, or even other non-jboss application servers. The full JBoss JEMS suite is not all embeddable yet, but here's what is available.

These are the limitations

Javadoc

Heres a link to the javadocs

Installing

Embeddable EJB 3.0 requires that all classes and configuration files be in your classpath so that it can locate them. Make sure the conf/ directory and all jars in the lib/ directory are in your classpath. That's about it. Also, you will need JDK 5.0. EJB 3.0 requires annotations and generics.

Using Embeddable EJB 3.0

Embeddable EJB 3.0 is built on top of the new JBoss Microcontainer that will be the core of JBoss 5.0. It is a dependency injection container and the configuration files will look very similar to other injection frameworks. It should be very possible to port Embeddable EJB 3.0 to other IoC frameworks. If you are interested in contributing such a port, please email us and we will be happy to include it within the distribution.

Defining a datasource

Open conf/embedded-jboss-beans.xml and search for DefaultDS. This example configures a default datasource that is used by the JMS Persistence Manager and is the default datasource for EJB3 Entity beans.

   <bean name="DefaultDSBootstrap" class="org.jboss.resource.adapter.jdbc.local.LocalTxDataSource">
      <property name="driverClass"><value>org.hsqldb.jdbcDriver</value></property>
      <property name="connectionURL"><value>jdbc:hsqldb:.</value></property>
      <property name="userName"><value>sa</value></property>
      <property name="jndiName"><value>java:/DefaultDS</value></property>
      <property name="minSize"><value>0</value></property>
      <property name="maxSize"><value>10</value></property>
      <property name="blockingTimeout"><value>1000</value></property>
      <property name="idleTimeout"><value>50000</value></property>
      <property name="transactionManager"><inject bean="TransactionManager"/></property>
      <property name="cachedConnectionManager"><inject bean="CachedConnectionManager"/></property>
      <property name="initialContextProperties"><inject bean="InitialContextProperties"/></property>
   </bean>

   <bean name="DefaultDS" class="java.lang.Object">
      <constructor factoryMethod="getDatasource">
         <factory bean="DefaultDSBootstrap"/>
      </constructor>
   </bean>

If you need to define your own datasource, basically cut and paste this XML. The properties are pretty self explanatory. DefaultDSBootstrap is the real configuration of the datasource. The DefaultDS bean is only there to make the datasource available for injection into other Microcontainer defined beans.

The DefaultDS, uses an in-memory database and thus will not persist changes to a file on disk. If you want changes persisted using the DefaultDS, then make the following change:

<property name="connectionURL"><value>jdbc:hsqldb:/home/put/your/path/here/localDB</value></property>

Security

Security works just like JBoss application server security. Only the user/role property file domain has been tested, but others should work too. A login-config.xml file must be available in your classpath. There is one already built for you in the conf/ directory of the distribution. Also, the JBoss Security manager is not loaded by default. It is configured in the security-beans.xml file in the conf/ directory but the MC file is not loaded by default. To enable it you must do:

      EJB3StandaloneBootstrap.deployXmlResource("security-beans.xml");

There is a security tutorial in the embedded distribution.

Embedding in Standalone Applications and JUnit tests

You can embedded EJB 3.0 in standalone applications and junit tests. See the org.jboss.ejb3.embedded package for more information on what classes you need. The tutorial has a bunch of examples for bootstrapping your applications. Check out the Main.java file in each one to see how it works.

The simplest way of finding EJBs/Entities to deploy is by using the EJB3StandaloneBootstrap.scanClasspath() method. It will search all paths returned by the java.class.path System property. Here's an example of bootstrapping Embeddable EJB 3.0 in a standalone environment. It is taken from the JMS mdb-standalone tutorial example.

      EJB3StandaloneBootstrap.boot(null);
      // initialize JBoss MQ core services
      EJB3StandaloneBootstrap.deployXmlResource("jboss-jms-beans.xml");
      // initialize configured test queue and topic
      EJB3StandaloneBootstrap.deployXmlResource("testjms.xml");
      // scan classpath for ejbs and MDBs
      EJB3StandaloneBootstrap.scanClasspath();

The boot() method creates the JBoss Microcontainer kernel and deploys the embedded-jboss-beans.xml file into it. This file creates a bunch of JBoss services like JNDI, Transaction Manager, and a default datasource. The boot() method also loads the ejb3-interceptors-aop.xml file which initializes AOP aspects that are used by the EJB containers.

The deployXmlResource() method deploys a JBoss Microcontainer XML file that is available in your Classpath. In the above example, it loads jboss-jms-beans.xml which are initialize the core services for JMS. It also loads the testjms.xml file that contains user definitions of topics and queues that their app is using.

The scanClasspath() method looks scans all jars and directories listed in the java.class.path System property. This environment variable is not guaranteed to be accurate, so you may have to result to some of the advanced deployment options discussed in the advanced-deployment tutorials. The scanClasspath() method is also overloaded with a comma delimited string parameter where you can specify a list of jars/directories to scan only and not he entire classpath.

Testing with JUnit

Testing Embeddable EJBs with JUnit is really very much the same as running a standalone SE app. One thing you might want to do is to bootstrap the container only at the beginning of testing and not with every method call. Here is a code snippet for doing this:

   public static Test suite() throws Exception
   {
      TestSuite suite = new TestSuite();
      suite.addTestSuite(EmbeddedEjb3TestCase.class);


      // setup test so that embedded JBoss is started/stopped once for all tests here.
      TestSetup wrapper = new TestSetup(suite)
      {
         protected void setUp()
         {
            startupEmbeddedJboss();
         }

         protected void tearDown()
         {
            shutdownEmbeddedJboss();
         }
      };

      return wrapper;
   }

   public static void startupEmbeddedJboss()
   {
         EJB3StandaloneBootstrap.boot(null);
         EJB3StandaloneBootstrap.scanClasspath();
   }

   public static void shutdownEmbeddedJboss()
   {
      EJB3StandaloneBootstrap.shutdown();
   }

This code snippet is taken from the test-with-junit example tutorial. Basically this will make sure that startupEmbeddedJBoss and shutdownEmbeddedJBoss only happen once for all test methods in that class.

Embedding EJB 3.0 into a WAR/Tomcat

You can initialize WAR deployments in servlet code like you do in standalone code, but there is a better solution. JBoss comes with a context listener class that you can use to configure your application. You put the following in your web.xml file of your WAR.

   <context-param>
      <param-name>jboss-kernel-deployments</param-name>
      <param-value>embedded-jboss-beans.xml, jboss-jms-beans.xml</param-value>
   </context-param>

   <listener>
      <listener-class>org.jboss.ejb3.embedded.ServletBootstrapListener</listener-class>
   </listener>

The jboss-kernel-deployments param specifies a list of JBoss Microcontainer resources to deploy when the WAR is created. These XML files are comma delimited and must be in your classpath (in your WEB-INF/classes directory for example). The tutorial has a full example. If you are not using JMS then you can remove the jboss-kernel-deployments context-param as embedded-jboss-beans.xml will be loaded automatically by the ServletBootstrapListener. If you have defined your own datasources, or JMS queues or topics, you must additionally add these XML files to the jboss-kernel-deployments context-param list. All of the XML files must be available in the WAR's classpath.

The ServletBootstrapListener will automatically scan all Jars within /WEB-INF/lib for EJBs and Entity beans that can be deployed. If you have more complex deployments then you can turn off scanning by this context-param:

   <context-param>
      <param-name>automatic-scan</param-name>
      <param-value>false</param-value>
   </context-param>

You can use the advanced deployment techniques instead to deploy your EJBs as described below.

JNDI Requirements

EJB requires JNDI. Embeddable EJB 3.0 comes with a local-only JBoss JNDI implementation. The default configuration initializes and uses this JBoss JNDI implementation at runtime even in Tomcat or other app server environments. To connect to it you must use the following JNDI properties
      Hashtable props = new Hashtable();
      props.put("java.naming.factory.initial", "org.jnp.interfaces.LocalOnlyContextFactory");
      props.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
Just like any app that uses JNDI, you can set these properties as System properties, or have a jndi.properties file that is in your classpath.

It is theoritically possible (no tests done yet) to use other vendor's JNDI implementations as long as they allow you to bind into them (EJB creates a bunch of bindings). For instance, Tomcat's JNDI implementation is read-only at runtime, so you are required to use JBoss's implementation.

Tutorial

The tutorial goes through a bunch of different ways to configure your embedded EJB 3.0.

Advanced Deployment Tutorials

If you have more complex deployment requirements, these tutorials walk you through different ways you can deploy your EJBs/Entities.