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.