Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3
Note

Disclaimer that we do tweak and change this code frequently, without notice. It is the very heart of OpenEJB. To keep things tight and clean, we reserve the right to change it at anytime. Do not consider it a stable public API.

Overview in Code

First a glimpse of how OpenEJB looks internally. Here's a test that builds OpenEJB using it's internal API. This is somewhat similar to how you might see people constructing Jetty in code. All our internal tests look like this.

This usage involves no xml parsing or classpath scanning. If you don't give it to OpenEJB, OpenEJB doesn't know about it. This is OpenEJB with all the magic stripped away. Disclaimer that we do tweak and change this code frequently. It is the very heart of OpenEJB and we need to keep the flexibility to change it at anytime, so do not consider it a stable public API. If you are fine with some instability, you are welcome to use it. It is no doubt very powerfulAt a high level:

  1. You build your app in code using the JAXB tree in code and hand it to the ConfigurationFactory.
    1. The org.apache.openejb.jee package contains JAXB trees for ejb-jar.xml, beans.xml and all the Java EE deployment descriptors.
  2. The ConfigurationFactory will produce a fully canonical version of the app called the Info tree by:
    1. Merging all sources of meta-data – xml and annotations
    2. Resolving all ejb, persistence unit, datasource and other references
    3. Validating the app and looking for mistakes
  3. The Info tree is
    1. The singular source of information about the application from this point forward.
    2. Pure data with no smarts or logic of any kind.
    3. The instruction set of what would be built by the assembler.
  4. The Assembler will build and start the application exactly as described in the Info tree.
    1. When this step completes, you have a running application.
    2. Any failures prior to this point require no cleanup. Only the assembler builds "live" objects.
Code Block
titleStatefulTest.java
import javax.ejb.LocalBean;
import javax.ejb.Stateful;
import javax.naming.InitialContext;

import junit.framework.TestCase;
import org.apache.openejb.assembler.classic.Assembler;
import org.apache.openejb.assembler.classic.SecurityServiceInfo;
import org.apache.openejb.assembler.classic.TransactionServiceInfo;
import org.apache.openejb.client.LocalInitialContextFactory;
import org.apache.openejb.config.ConfigurationFactory;
import org.apache.openejb.jee.EjbJar;
import org.apache.openejb.jee.StatefulBean;

/**
 * This test case serves as a nice tiny template for other test cases
 * and purposely doesn't do anything very complicated.
 *
 * @version $Rev$ $Date$
 */
public class StatefulTest extends TestCase {

    @Override
    protected void setUp() throws Exception {

        System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, LocalInitialContextFactory.class.getName());

        ConfigurationFactory config = new ConfigurationFactory();
        Assembler assembler = new Assembler();

        assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class));
        assembler.createSecurityService(config.configureService(SecurityServiceInfo.class));

        EjbJar ejbJar = new EjbJar();
        ejbJar.addEnterpriseBean(new StatefulBean(MyBean.class));

        assembler.createApplication(config.configureApplication(ejbJar));
    }

    public void test() throws Exception {
        InitialContext context = new InitialContext();
        MyBean myBean = (MyBean) context.lookup("MyBeanLocalBean");

        assertEquals("pan", myBean.echo("nap"));
    }

    @Stateful
    @LocalBean
    public static class MyBean {

        public String echo(String string) {
            StringBuilder sb = new StringBuilder(string);
            return sb.reverse().toString();
        }
    }
}

Logical Overview

Slightly more detailed account of the above. Our startup and deploy world is broken into two phases:

1. configuration (app.jar -> AppInfo) we build up a fully normalized and validated tree. Some of the steps are

  • read in descriptors
  • process annotations filling in the descriptor tree
  • validating app compliance
  • resolving resource references
  • resolving ejb references
  • turning the descriptor tree into Info objects for final assembly
  • final validation check

2. assembly (AppInfo -> actual running app) we assemble a running app as detailed by the AppInfo

  • creating classloaders for the application
  • creating EntityManagers and EntityManagerFactories
  • creating live objects associated with resource-env-refs
  • creating deployment (CoreDeploymentInfo) objects for each ejb
  • creating the jndi enc of each ejb
  • adding method permission objects into the security system (JACC Provider)
  • creating transaction policy objects for each ejb
  • creating interceptor stacks and bindings for each ejb
  • adding ejbs to containers (which may also do things like create pools)
  • adding ejbs to the live ContainerSystem registry of ejbs
  • adding global jndi entries for each ejb

The listings above aren't necesarrily complete or perfectly ordered, but generally show the nature of the work done in each phase.

Configuration Phase

A goal is that nothing gets through configuration and into assembly if it can't actually be built. The configuration phase is where we're supposed to wipe away any ambiguity, fully normalize the app, make sure it's internally consistent, spec compliant and generally good to go. If it's not, no worries as we actually haven't built anything permanent yet. Everything in the configuration phase is temporary. If it fails the configuration phase we just issue an error and say "App will not be loaded" and that's it, there's nothing to undo.

...