Chapter 30. EJBs on JBoss
The EJB Container Configuration and Architecture
The JBoss EJB container architecture employs a modular plug-in approach. All key aspects of the EJB container may be replaced by custom versions of a plug-in and/or an interceptor by a developer. This approach allows for fine tuned customization of the EJB container behavior to optimally suite your needs. Most of the EJB container behavior is configurable through the EJB JAR
META-INF/jboss.xml
descriptor and the default server-wide equivalent standardjboss.xml
descriptor. We will look at various configuration capabilities throughout this chapter as we explore the container architecture.
30.1. The EJB Client Side View
We will begin our tour of the EJB container by looking at the client view of an EJB through the home and remote proxies. It is the responsibility of the container provider to generate the
javax.ejb.EJBHome
and javax.ejb.EJBObject
for an EJB implementation. A client never references an EJB bean instance directly, but rather references the EJBHome
which implements the bean home interface, and the EJBObject
which implements the bean remote interface. Figure 30.1, “The composition of an EJBHome proxy in JBoss.” shows the composition of an EJB home proxy and its relation to the EJB deployment.
Figure 30.1. The composition of an EJBHome proxy in JBoss.
The numbered items in the figure are:
- The EJBDeployer (
org.jboss.ejb.EJBDeployer
) is invoked to deploy an EJB JAR. AnEJBModule
(org.jboss.ejb.EJBModule
) is created to encapsulate the deployment metadata. - The create phase of the
EJBModule
life cycle creates anEJBProxyFactory
(org.jboss.ejb.EJBProxyFactory
) that manages the creation of EJB home and remote interface proxies based on theEJBModule
invoker-proxy-bindings
metadata. There can be multiple proxy factories associated with an EJB and we will look at how this is defined shortly. - The
ProxyFactory
constructs the logical proxies and binds the homes into JNDI. A logical proxy is composed of a dynamicProxy
(java.lang.reflect.Proxy
), the home interfaces of the EJB that the proxy exposes, theProxyHandler
(java.lang.reflect.InvocationHandler
) implementation in the form of theClientContainer
(org.jboss.proxy.ClientContainer
), and the client side interceptors. - The proxy created by the
EJBProxyFactory
is a standard dynamic proxy. It is a serializable object that proxies the EJB home and remote interfaces as defined in theEJBModule
metadata. The proxy translates requests made through the strongly typed EJB interfaces into a detyped invocation using theClientContainer
handler associated with the proxy. It is the dynamic proxy instance that is bound into JNDI as the EJB home interface that clients lookup. When a client does a lookup of an EJB home, the home proxy is transported into the client VM along with theClientContainer
and its interceptors. The use of dynamic proxies avoids the EJB specific compilation step required by many other EJB containers. - The EJB home interface is declared in the ejb-jar.xml descriptor and available from the EJBModule metadata. A key property of dynamic proxies is that they are seen to implement the interfaces they expose. This is true in the sense of Java's strong type system. A proxy can be cast to any of the home interfaces and reflection on the proxy provides the full details of the interfaces it proxies.
- The proxy delegates calls made through any of its interfaces to the
ClientContainer
handler. The single method required of the handler is:public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
. TheEJBProxyFactory
creates aClientContainer
and assigns this as theProxyHandler
. TheClientContainer
's state consists of anInvocationContext
(org.jboss.invocation.InvocationContext
) and a chain of interceptors (org.jboss.proxy.Interceptor
). TheInvocationContext
contains:- the JMX
ObjectName
of the EJB container MBean theProxy
is associated with - the
javax.ejb.EJBMetaData
for the EJB - the JNDI name of the EJB home interface
- the transport specific invoker (
org.jboss.invocation.Invoker
)
The interceptor chain consists of the functional units that make up the EJB home or remote interface behavior. This is a configurable aspect of an EJB as we will see when we discuss thejboss.xml
descriptor, and the interceptor makeup is contained in theEJBModule
metadata. Interceptors (org.jboss.proxy.Interceptor
) handle the different EJB types, security, transactions and transport. You can add your own interceptors as well. - The transport specific invoker associated with the proxy has an association to the server side detached invoker that handles the transport details of the EJB method invocation. The detached invoker is a server side component.
The configuration of the client side interceptors is done using the
jboss.xml
client-interceptors
element. When the ClientContainer
invoke method is called it creates an un-typed Invocation
(org.jboss.invocation.Invocation
) to encapsulate request. This is then passed through the interceptor chain. The last interceptor in the chain will be the transport handler that knows how to send the request to the server and obtain the reply, taking care of the transport specific details.
As an example of the client interceptor configuration usage, consider the default stateless session bean configuration found in the
server/production/standardjboss.xml
descriptor. Example 30.1, “The client-interceptors from the Standard Stateless SessionBean configuration.” shows the stateless-rmi-invoker
client interceptors configuration referenced by the Standard Stateless SessionBean.
Example 30.1. The client-interceptors from the Standard Stateless SessionBean configuration.
<invoker-proxy-binding> <name>stateless-rmi-invoker</name> <invoker-mbean>jboss:service=invoker,type=jrmp</invoker-mbean> <proxy-factory>org.jboss.proxy.ejb.ProxyFactory</proxy-factory> <proxy-factory-config> <client-interceptors> <home> <interceptor>org.jboss.proxy.ejb.HomeInterceptor</interceptor> <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor> <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor> <interceptor call-by-value="false"> org.jboss.invocation.InvokerInterceptor </interceptor> <interceptor call-by-value="true"> org.jboss.invocation.MarshallingInvokerInterceptor </interceptor> </home> <bean> <interceptor>org.jboss.proxy.ejb.StatelessSessionInterceptor</interceptor> <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor> <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor> <interceptor call-by-value="false"> org.jboss.invocation.InvokerInterceptor </interceptor> <interceptor call-by-value="true"> org.jboss.invocation.MarshallingInvokerInterceptor </interceptor> </bean> </client-interceptors> </proxy-factory-config> </invoker-proxy-binding>
<container-configuration> <container-name>Standard Stateless SessionBean</container-name> <call-logging>false</call-logging> <invoker-proxy-binding-name>stateless-rmi-invoker</invoker-proxy-binding-name> <!-- ... --> </container-configuration>
This is the client interceptor configuration for stateless session beans that is used in the absence of an EJB JAR
META-INF/jboss.xml
configuration that overrides these settings. The functionality provided by each client interceptor is:
- org.jboss.proxy.ejb.HomeInterceptor: handles the
getHomeHandle
,getEJBMetaData
, and remove methods of theEJBHome
interface locally in the client VM. Any other methods are propagated to the next interceptor. - org.jboss.proxy.ejb.StatelessSessionInterceptor: handles the
toString
,equals
,hashCode
,getHandle
,getEJBHome
andisIdentical
methods of theEJBObject
interface locally in the client VM. Any other methods are propagated to the next interceptor. - org.jboss.proxy.SecurityInterceptor: associates the current security context with the method invocation for use by other interceptors or the server.
- org.jboss.proxy.TransactionInterceptor: associates any active transaction with the invocation method invocation for use by other interceptors.
- org.jboss.invocation.InvokerInterceptor: encapsulates the dispatch of the method invocation to the transport specific invoker. It knows if the client is executing in the same VM as the server and will optimally route the invocation to a by reference invoker in this situation. When the client is external to the server VM, this interceptor delegates the invocation to the transport invoker associated with the invocation context. In the case of the Example 30.1, “The client-interceptors from the Standard Stateless SessionBean configuration.” configuration, this would be the invoker stub associated with the
jboss:service=invoker,type=jrmp
, theJRMPInvoker
service.org.jboss.invocation.MarshallingInvokerInterceptor: extends theInvokerInterceptor
to not optimize in-VM invocations. This is used to forcecall-by-value
semantics for method calls.
30.1.1. Specifying the EJB Proxy Configuration
To specify the EJB invocation transport and the client proxy interceptor stack, you need to define an
invoker-proxy-binding
in either the EJB JAR META-INF/jboss.xml descriptor
, or the server standardjboss.xml
descriptor. There are several default invoker-proxy-bindings
defined in the standardjboss.xml
descriptor for the various default EJB container configurations and the standard RMI/JRMP and RMI/IIOP transport protocols. The current default proxy configurations are:
- entity-rmi-invoker: a RMI/JRMP configuration for entity beans
- clustered-entity-rmi-invoker: a RMI/JRMP configuration for clustered entity beans
- stateless-rmi-invoker: a RMI/JRMP configuration for stateless session beans
- clustered-stateless-rmi-invoker: a RMI/JRMP configuration for clustered stateless session beans
- stateful-rmi-invoker: a RMI/JRMP configuration for clustered stateful session beans
- clustered-stateful-rmi-invoker: a RMI/JRMP configuration for clustered stateful session beans
- message-driven-bean: a JMS invoker for message driven beans
- singleton-message-driven-bean: a JMS invoker for singleton message driven beans
- message-inflow-driven-bean: a JMS invoker for message inflow driven beans
- jms-message-inflow-driven-bean: a JMS inflow invoker for standard message driven beans
- iiop: a RMI/IIOP for use with session and entity beans.
To introduce a new protocol binding, or customize the proxy factory, or the client side interceptor stack, requires defining a new
invoker-proxy-binding
. The full invoker-proxy-binding
DTD fragment for the specification of the proxy configuration is given in Figure 30.2, “The invoker-proxy-binding schema”.
Figure 30.2. The invoker-proxy-binding schema
The
invoker-proxy-binding
child elements are:
- name: The
name
element gives a unique name for theinvoker-proxy-binding
. The name is used to reference the binding from the EJB container configuration when setting the default proxy binding as well as the EJB deployment level to specify addition proxy bindings. You will see how this is done when we look at thejboss.xml
elements that control the server side EJB container configuration. - invoker-mbean: The
invoker-mbean
element gives the JMXObjectName
string of the detached invoker MBean service the proxy invoker will be associated with. - proxy-factory: The
proxy-factory
element specifies the fully qualified class name of the proxy factory, which must implement theorg.jboss.ejb.EJBProxyFactory
interface. TheEJBProxyFactory
handles the configuration of the proxy and the association of the protocol specific invoker and context. The current JBoss implementations of theEJBProxyFactory
interface include:- org.jboss.proxy.ejb.ProxyFactory: The RMI/JRMP specific factory.
- org.jboss.proxy.ejb.ProxyFactoryHA: The cluster RMI/JRMP specific factory.
- org.jboss.ejb.plugins.jms.JMSContainerInvoker: The JMS specific factory.
- org.jboss.proxy.ejb.IORFactory: The RMI/IIOP specific factory.
- proxy-factory-config: The
proxy-factory-config
element specifies additional information for theproxy-factory
implementation. Unfortunately, its currently an unstructured collection of elements. Only a few of the elements apply to each type of proxy factory. The child elements break down into the three invocation protocols: RMI/RJMP, RMI/IIOP and JMS.
For the RMI/JRMP specific proxy factories,
org.jboss.proxy.ejb.ProxyFactory
and org.jboss.proxy.ejb.ProxyFactoryHA
the following elements apply:
- client-interceptors: The
client-interceptors
define the home, remote and optionally the multi-valued proxy interceptor stacks. - web-class-loader: The web class loader defines the instance of the
org.jboss.web.WebClassLoader
that should be associated with the proxy for dynamic class loading.
The following
proxy-factory-config
is for an entity bean accessed over RMI.
<proxy-factory-config> <client-interceptors> <home> <interceptor>org.jboss.proxy.ejb.HomeInterceptor</interceptor> <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor> <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor> <interceptor call-by-value="false"> org.jboss.invocation.InvokerInterceptor </interceptor> <interceptor call-by-value="true"> org.jboss.invocation.MarshallingInvokerInterceptor </interceptor> </home> <bean> <interceptor>org.jboss.proxy.ejb.EntityInterceptor</interceptor> <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor> <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor> <interceptor call-by-value="false"> org.jboss.invocation.InvokerInterceptor </interceptor> <interceptor call-by-value="true"> org.jboss.invocation.MarshallingInvokerInterceptor </interceptor> </bean> <list-entity> <interceptor>org.jboss.proxy.ejb.ListEntityInterceptor</interceptor> <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor> <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor> <interceptor call-by-value="false"> org.jboss.invocation.InvokerInterceptor </interceptor> <interceptor call-by-value="true"> org.jboss.invocation.MarshallingInvokerInterceptor </interceptor> </list-entity> </client-interceptors> </proxy-factory-config>
For the RMI/IIOP specific proxy factory,
org.jboss.proxy.ejb.IORFactory
, the following elements apply:
- web-class-loader: The web class loader defines the instance of the
org.jboss.web.WebClassLoader
that should be associated with the proxy for dynamic class loading. - poa: The portable object adapter usage. Valid values are
per-servant
andshared
. - register-ejbs-in-jnp-context: A flag indicating if the EJBs should be register in JNDI.
- jnp-context: The JNDI context in which to register EJBs.
- interface-repository-supported: This indicates whether or not a deployed EJB has its own CORBA interface repository.
The following shows a
proxy-factory-config
for EJBs accessed over IIOP.
<proxy-factory-config> <web-class-loader>org.jboss.iiop.WebCL</web-class-loader> <poa>per-servant</poa> <register-ejbs-in-jnp-context>true</register-ejbs-in-jnp-context> <jnp-context>iiop</jnp-context> </proxy-factory-config>
For the JMS specific proxy factory,
org.jboss.ejb.plugins.jms.JMSContainerInvoker
, the following elements apply:
- MinimumSize: This specifies the minimum pool size for MDBs processing. This defaults to 1.
- MaximumSize: This specifies the upper limit to the number of concurrent MDBs that will be allowed for the JMS destination. This defaults to 15.
- MaxMessages: This specifies the
maxMessages
parameter value for thecreateConnectionConsumer
method ofjavax.jms.QueueConnection
andjavax.jms.TopicConnection
interfaces, as well as themaxMessages
parameter value for thecreateDurableConnectionConsumer
method ofjavax.jms.TopicConnection
. It is the maximum number of messages that can be assigned to a server session at one time. This defaults to 1. This value should not be modified from the default unless your JMS provider indicates this is supported. - KeepAliveMillis: This specifies the keep alive time interval in milliseconds for sessions in the session pool. The default is 30000 (30 seconds).
- MDBConfig: Configuration for the MDB JMS connection behavior. Among the elements supported are:
- ReconnectIntervalSec: The time to wait (in seconds) before trying to recover the connection to the JMS server.
- DeliveryActive: Whether or not the MDB is active at start up. The default is true.
- DLQConfig: Configuration for an MDB's dead letter queue, used when messages are redelivered too many times.
- JMSProviderAdapterJNDI: The JNDI name of the JMS provider adapter in the
java:/
namespace. This is mandatory for an MDB and must implementorg.jboss.jms.jndi.JMSProviderAdapter
. - ServerSessionPoolFactoryJNDI: The JNDI name of the session pool in the
java:/
namespace of the JMS provider's session pool factory. This is mandatory for an MDB and must implementorg.jboss.jms.asf.ServerSessionPoolFactory
.
Example 30.2, “A sample JMSContainerInvoker proxy-factory-config” gives a sample
proxy-factory-config
fragment taken from the standardjboss.xml
descriptor.
Example 30.2. A sample JMSContainerInvoker proxy-factory-config
<proxy-factory-config> <JMSProviderAdapterJNDI>DefaultJMSProvider</JMSProviderAdapterJNDI> <ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI> <MinimumSize>1</MinimumSize> <MaximumSize>15</MaximumSize> <KeepAliveMillis>30000</KeepAliveMillis> <MaxMessages>1</MaxMessages> <MDBConfig> <ReconnectIntervalSec>10</ReconnectIntervalSec> <DLQConfig> <DestinationQueue>queue/DLQ</DestinationQueue> <MaxTimesRedelivered>10</MaxTimesRedelivered> <TimeToLive>0</TimeToLive> </DLQConfig> </MDBConfig> </proxy-factory-config>