You can create a bean implementation class for a stateful
session bean as introduced in the Enterprise JavaBeans™ (EJB) 1.0
specification and significantly simplified by the EJB 3.0 specification.
A stateful bean is a type of session bean that is intended for use
by a single client during its lifetime and maintains a conversational
state with the client that is calling it.
Before you begin
Make sure that you understand the inheritance rules for each
annotation you implement. For example, the @TransactionManagement
annotation is coded on the stateful session bean class only. You cannot
use the @TransactionManagement annotation in the class that it extends,
or any class higher in the class inheritance tree.
About this task
Stateful session beans can have the following
views: no-interface local view (new in EJB 3.1), business local, business
remote, EJB 2.1 local, and EJB2.1 remote client views. One example
is a shopping cart where the client adds items to the cart over the
course of an on-line shopping session.
The following example shows a basic stateful session bean:
package com.ibm.example;
public interface ShoppingCart {
void addToCart (Object o);
Collection getContents();
}
package com.ibm.example;
@Stateful
public class ShoppingCartBean implements ShoppingCart {
private ArrayList contents = new ArrayList();
public void addToCart (Object o) {
contents.add(o);
}
public Collection getContents() {
return contents;
}
}
As with other enterprise bean types,
you can also declare metadata for stateful session beans in the deployment
descriptor rather than using annotations; for example:
<?xml version="1.0"?>
<ejb-jar
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
version="3.1">
<enterprise-beans>
<ejb-name>ShoppingCartBean</ejb-name>
<business-local>com.ibm.example.ShoppingCart</business-local>
<ejb-class>com.ibm.example.ShoppingCartBean</ejb-class>
<session-type>Stateful</session-type>
</enterprise-beans>
</ejb-jar>
- Code the initialization and destruction methods, understanding
that they run in an unspecified security context and an unspecified
transaction context. During initialization, the instance is created,
dependency injection occurs, and PostConstruct life cycle interceptor
callbacks are invoked. The PreDestroy life cycle interceptor callbacks
are invoked for a stateful session bean when a remove method is called.
Also keep in mind that the PreDestroy life cycle interceptor callbacks
are not called if the stateful session bean times out while in the
passive state, or if an unexpected exception occurs during a method
invocation on the bean and the bean is discarded.
- Use PrePassivate and PostActivate methods if the stateful
session bean can contain state that is not serializable. The container
can passivate a stateful session bean instance anytime that it is
not enlisted in a transaction or currently running a method request.
The stateful session bean instance is moved to the passive state by
serializing all the state data. If any of the state data does not
serialize, the stateful session bean instance is discarded by the
container.
- Consider implementing the optional javax.ejb.SessionSynchronization
interface if the state data of the stateful session bean needs to
be reset after a transaction rollback. The state data of a stateful
session bean is not transactional and is not automatically reset to
the initial state as the result of a transaction rollback. By implementing
the afterCompletion method of the javax.ejb.SessionSynchronization
interface, the stateful session bean instance might reset itself to
the initial or consistent state.
- Use the @AccessTimeout notation to prohibit concurrent
client requests or limit how long a method waits for the instance
lock to be granted. By default, the container allows concurrent client
requests, but serializes all method calls and container-invoked callbacks
to prevent multi-threaded access to the stateful session bean instance.
This behavior is like using container-managed concurrency with write
locks for singleton session beans. However, unlike singleton session
beans, stateful session beans cannot be configured to use bean-managed
concurrency and the lock type cannot be changed. Only the access-timeout
value can be modified for stateful session beans.
The following code example illustrates a stateful
session bean with a concurrent access-timeout value that prohibits
concurrent client requests:
package com.ibm.example;
@Stateful
public class ShoppingCartBean implements ShoppingCart {
private ArrayList contents = new ArrayList();
@AccessTimeout( value=0 )
public void addToCart (Object o) {
contents.add(o);
}
public Collection getContents() {
return contents;
}
}
package com.ibm.example;
@Stateful
public class ShoppingCartBean implements ShoppingCart {
private ArrayList contents = new ArrayList();
@AccessTimeout( value=0 )
public void addToCart (Object o) {
contents.add(o);
}
public Collection getContents() {
return contents;
}
}
If no annotation is provided,
the default behavior is to wait until a lock is granted. No time limit
exists for how long a client waits for the lock to be granted. Because
nothing is coded at the class level, no wait time limit exists for
a lock to be granted for all methods of the class. If the @AccessTimeout
annotation is used and the container cannot grant the lock within
the specified time limit, a javax.ejb.ConcurrentAccessTimeoutException
exception occurs on the client. The @AccessTimeout annotation only
applies to methods that are declared in the same class as the @AccessTimeout
annotation. For a given class, the metadata for the @AccessTimeout
annotation is never inherited from a class higher in the class inheritance
tree.
An access-timeout value of -1 indicates
that concurrent method calls block access to the bean instance indefinitely
(the default). An access-timeout value of 0 indicates that concurrent
method calls are not allowed. The exception, javax.ejb.ConcurrentAccessException,
occurs when concurrency is detected. And any positive value indicates
the amount of time to wait until the method can proceed.
Prior to Java EE
6, the only concurrency behavior supported for stateful session beans
was an access-timeout of -1, no concurrency. Since the Java EE 6 specification changed the default
behavior, a system property is supported that provides the older default
behavior. See EJB container system properties for more information
about the com.ibm.websphere.ejbcontainer.EE5Compatibility system property.
You can also specify
the @AccessTimeout annotation using the XML deployment descriptor,
and if you use the XML deployment descriptor, the metadata from the
@AccessTimeout annotation is ignored. The following example uses the
XML deployment descriptor to specify the same metadata as the previous
example.
<session>
<ejb-name>ShoppingCartBean</ejb-name>
<concurrent-method>
<method>
<method-name>addToCart</method-name>
</method>
<access-timeout>
<timeout>0</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
</session>
- It is important to know that the XML coding of the concurrent-methodType
follows the three styles outlined in the EJB specification for composing
the XML for container-transaction method elements. The three styles
are: Style 1 uses the special method
name * to apply the access-timeout value to all business methods for
the specified bean.
<!-- Example: Style 1 -->
<concurrent-method>
<method>
<method-name>*</method-name>
</method>
<access-timeout>
<timeout>2000</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
Style
2 is used to refer to a business method with a specific name and assign
it the specified access-timeout value. If the method name is overloaded,
meaning multiple methods have the same name but different method signatures,
all methods with this name have the specified access-timeout value.
<!-- Example: Style 2 -->
<concurrent-method>
<method>
<method-name>businessMethod</method-name>
</method>
<access-timeout>
<timeout>2000</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
Style 3 is used to refer to a distinct method
that matches the given method name and has a method signature that
matches the method parameters listed. Style 3 takes precedence over
both style 1 and style 2.
<!-- Example: Style 3 -->
<concurrent-method>
<method>
<method-name>businessMethod</method-name>
<method-params>
<method-param>long</method-param>
<method-param>int</method-param>
</method-params>
</method>
<access-timeout>
<timeout>2000</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
If style
1 XML is used to define an access-timeout value, then all @AccessTimeout
annotations on the bean are ignored because the method level one is
used instead.
- Ensure that you understand the inheritance rules for the
annotations that you have used.
- Stateful session beans are not reentrant, which means that
the stateful session bean method calls itself back. If a reentrant
call is made to a stateful session bean, a javax.ejb.ConcurrentAccessTimeoutException
exception occurs on the client, regardless of the access-timeout value.
This exception does not result in the stateful session bean being
discarded, nor does it mark the transaction for rollback, unless the
exception is not handled by the caller.