A Container is the component that runs a particular EJB. When an EJB-jar is deployed, typically a number of containers are created which are connected internally into Applications. The Application lets Containers handle references between beans, for example for JNDI EJB-references as specified in the EJB 1.1 specification.
But let's not dive into the nuts and bolts of the container component without first looking into the container's creation process. The component responsible for creating the container is the container factory.
The container factory, as its name implies, simply creates containers. Simple, right? Wrong !!! Lets investigate this process in more detail.
Given an EJB-jar that is ready for deployment, the container factory will create and initialize the necessary EJB-containers - one for each deployed EJB. The factory contains two central methods:deploy and undeploy. The deploy method takes a URL, which either points to an EJB-jar, or to a directory whose structure is the same as a valid EJB-jar(convenient for development purposes). Once a deployment has been made, it can be undeployed by calling undeploy on the same URL. A call to deploy with an already deployed URL will cause an undeploy followed by deployment of the URL, i.e. a re-deploy. JBoss has support for full re-deployment of both implementation and interface classes, and will reload any changed classes. This will allow you to develop and update EJBs without ever stopping a running server.
In order to properly deploy the bean into a container, the container factory has to have "intimate" knowledge about the bean being deployed to the finest level of granularity. This is where the notion of bean metadata comes into the picture. The metadata package, which in turn utilizes a standard DOM document model, creates an "object-tree" in-memory replica of ejb-jar.xml file. Having an object tree structure of bean metadata, the container factory can easily access it and then succesfully deploy a bean into a container. Bean metadata is actually a super set of other finer-grained metadata components like method, ejb-ref, environment entries, resource entries metadata.
Besides standard EJB 1.1 ejb-jar.xml file that contains metadata about beans being deployed, JBoss defines its own container configuration file - standardjboss.xml. Standardjboss.xml specifies default container configurations for each EJB bean type. Each configuration specifies which components to use, such as container invoker type, instance caches/pools and their sizes, persistence manager etc.
A quick look at standardjboss.xml gives us a hint about all default container configurations. EJB adminstrator/developer is also given an opportunity to override these default container settings in jboss.xml file. The advantage of this approach is that it gives great flexibility in the configuration of containers. As we have seen, all container configuration attributes have been externalized and as such are easily modifiable. Knowledgeable developers can even implement specialized container components such as instance pools or caches and easily integrate them with the container.
As an option, Jboss also attempts to verify EJB 1.1 specification compliance of the beans. For more details, the curious reader should look into the verifier package.
Having a bean and container metadata, the container factory iterates over all beans it has to deploy and:
- creates specific container subclass - sets all container attributes from container metadata* - adds all container interceptors* - adds container to application - after all beans have been succesfully deployed, starts application
*Note the difference between container interceptors in specific container subclasses
*The metadata specifies the type of TM (transaction manager) to use but, in fact, we need look it up from the naming tree. In fact, there is (and should be) only one TM per VM since transactions have to be coordinated across containers. Also note that EJBSecurityManager andRealmMapping are shared between containers (for more details refer to the security section of this paper).
The container factory can be invoked manually from a management console or automatically by using the AutoDeployer. AutoDeployer (which is an MBean) is a component that periodically checks EJB-jars for modification timestamps. If an update has been made the EJB-jar is re-deployed. When the server is started and an EJB-jar is found it will be deployed automatically.
The deployer is given a URL to watch. The URL can point to one of three things:
- directory whose contents are structured like an EJB-jar. Timestamp checks will be done on the META-INF/ejb-jar.xml file.
- directory into which EJB-jar files or directories containing valid EJB-jar contents is placed. This may only be a file URL, since it is not possible to do file listing checks on HTTP URL's.
The last variant is very powerful. The default configuration of JBoss starts an AutoDeployer that checks the /deploy directory. Here you can place any EJB-jars that you want to be deployed on startup. If you want to add deployments at runtime you simply drop them in that directory.
EnterpriseContext and its subclasses, StatefulSessionEnterpriseContext,StatelessSessionEntepriseContext, and EntityEntepriseContext implementEJBContext part of EJB 1.1 spec.
From a bean's perspective EJBContext is a gateway to container; it represents a way for a bean to perform callbacks to the container.
From a container's perspective, the container usesEntepriseContext to associate a bean instance with all information that the container needs about that instance to properly manage it. This infomation includes a callback reference to the container hosting the instance, synchronization associated with that instance, instance's transaction,Principal and object Id. Simply put, EntepriseContext associates a bean's instance with its metadata. It is the container's responsibilty to manage bean's context, which changes over the lifecycle of a bean.
JBoss container is mainly a framework into which one can plug in implementations of various parts. TheContainer itself does not perform any significant work other than connecting the various plugins. There are three subclasses of Container, each one implementing a particular bean-type:
EntityContainer handles EntityBeans, StatelessSessionContainer handles Stateless SessionBeans, and StatefulSessionContainer handles Stateful SessionBeans.
They are very similar, but are different in some respects. The stateless session container does not have an instance cache (since no instances have identity), and the entity container has an EntityPersistenceManager to help it with persisting entity beans in various storages.
The plugins can be added by implementing various interfaces, and by selecting them in the JBoss-specific deployment XML file (which can be edited in a GUI-tool). The interfaces are:
InstancePool andInterceptors are used in all three different types of containers. InstanceCache is only used for entity beans and stateful session beans. EntityPersistenceManager is only used for entity beans. StatefulSessionPersistenceManager is only used for stateful session beans.
These interfaces are described in detail below. All plugins have a callback to the container through which they can access all other plugins or configuration information. The container's main responsibility is therefore to manage the plugins, and to see to it that the plugins have all the information they need in order to implement some functionality.
All interceptors are created and added to the interceptor linked-list by the container factory. The last interceptor is not added by the container factory but rather by the container itself.
The order of the interceptor in the chain is not accidental. The idea behind ordering is that intereceptors that are not tied to a particular EnterpriseContext instance are positioned before interceptors that interact with caches and pools.
Implementors of the Interceptor interface form a linked-list like structure through which the MethodInvocation object is passed. The first interceptor in the chain is invoked whenContainerInvoker hands off MethodInvocation to the container. The last interceptor invokes the business method on the bean. There are usually between 3 and 6 interceptors in a chain depending on the bean type and container configuration. Interceptor semantic complexity ranges from simple to complex ones, but under the cover they all present the same simple interface. An example of a simple interceptor would be LoggingInterceptor, while a complex example is EntitySynchronizationInterceptor.
One of the main advantages of Interceptorpattern is flexibility in the arrangement of interceptors, as well as a clear semantic distinction between different interceptors. For example, logic for transaction and security is in TXInterceptor andSecurityInterceptor correspondingly.
If any of the interceptors fail, we don't have to continue the call further through, which is very useful if the interceptor that failed is before complex structures like caches.
InstancePool is used to manage the EJB-bean instances that are not associated with any identity. In fact, to be exact, EnterpriseContext objects that wrap non-associated bean instances are pooled in this data structure.
Depending on the underlying bean type hosted in a container, there are three different instance pool types. However, it is important to notice that each container has only one pool of either type.
Depending on the configuration, a container may choose to have a certain size of the pool containing recycled instances, or it may choose to instantiate and initialize an instance on demand.
The pool is used by the InstanceCache to acquire free instances for activation, and it is used by Interceptors to acquire instances to be used for Home interface methods (create and finder calls).
InstanceCache handles all EJB-instances that are in a active state, i.e. bean instances that have an identity attached to them.
Only entity and stateful session beans are cached. The cache key of an entity bean is the primary key. It is the session id for stateful session beans.
InstanceCache handles the list of active instances, and is also responsible for activating and passivating these instances. If an instance with a given identity is requested, and it is not currently active, the InstanceCache must use the InstancePool to acquire a free instance, and the persistence manager to activate the instance. Similarly, if it decides to passivate a certain active instance, it must call the persistence manager to passivate it and release the instance to theInstancePool.
The EntityPersistenceManager is responsible for the persistence of EntityBeans. This includes:
- Creating EntityBeans in a storage - Loading the state of a given primary key into an EJB-instance - Storing the state of a given EJB-instance - Removing the state from storage - Activating an EJB-instance - Passivating an EJB-instance
As per EJB 1.1 specification, JBoss supports two entity bean persistance semantics: CMP (Container Managed Persistence) and BMP (Bean Managed Persistence).
The CMP plugin, CMPPersistanceManager uses the default implementor of EntityPersistanceManager,JAWSPersistanceManager (JAWS-Just Another Web Store). JAWS performs performs basic O/R functionality against a JDBC-store.
The BMP implementor of the EntityPersistenceManagerinterface is BMPPersistanceManager. BMP persistance manager is fairly simple since all persistence logic is in the entity bean itself. The only duty of the persistence manager is to perform container callbacks.
The StatefulSessionPersistenceManager is responsible for the persistence of Stateful SessionBeans. This includes:
- Creating stateful sessions in a storage - Activating stateful sessions from a storage - Passivating stateful sessions to a storage - Removing stateful sessions from a storage
The default implementation of theStatefulSessionPersistenceManager is StatefulSessionFilePersistenceManager. As its name implies, StatefulSessionFilePersistenceManager utilizes the underlying file system to persist stateful SessionBeans. More specifically, persistence manager serializes beans in flat file under bean name + bean Id .ser files. Having a .ser file per bean instance, the Persistance Manager is able to restore a bean's state for activation and respectively store its state during passivation.