É possível criar uma classe de implementação de bean para um bean de sessão stateful
conforme introduzido na especificação Enterprise JavaBeans™ (EJB) 1.0
e significativamente simplificado pela especificação EJB 3.0. Um bean stateful é um tipo de bean de sessão que deve ser utilizado por um único cliente durante seu ciclo de vida e mantém um estado de conversação com o cliente que o está chamando.
Antes de Iniciar
Certifique-se de entender as regras de herança para cada anotação que você implementar. Por exemplo, a anotação @TransactionManagement é codificada apenas na classe do bean de sessão stateful. Não é possível usar a anotação @TransactionManagement na classe que estende ou qualquer classe superior na árvore de herança de classe.
Sobre Esta Tarefa
Beans de sessão stateful podem ter as seguintes visualizações: visualização local sem interface (novo no EJB 3.1), local de negócios, remota de negócios, local EJB 2.1, e cliente remoto EJB2.1. Um exemplo é um carrinho de compras no qual o cliente inclui itens durante uma sessão de compras online.
O exemplo a seguir mostra um bean de sessão stateful básico:
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;
}
}
Como com outros tipos de enterprise bean,
também é possível declarar metadados para beans de sessão stateful no descritor de implementação, em vez de usar anotações; por exemplo:
<?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>
- Codifique os métodos de inicialização e destruição, entendendo que eles executam em um contexto de segurança não especificado e em um contexto de transação não especificado. Durante a inicialização, a instância é criada, ocorre a injeção de dependência e
os retornos de chamada do interceptor do ciclo de vida PostConstruct são invocados. Os retornos de chamada do interceptor do ciclo de vida PreDestroy são invocados para um bean de sessão stateful quando um método de remoção é chamado. Também lembre-se que os retornos de chamada do interceptor do ciclo de vida PreDestroy não são chamados se o bean de sessão stateful expira enquanto no estado passivo, ou se uma exceção inesperada ocorre durante uma chamada de método no bean e o bean é descartado.
- Use os métodos PrePassivate e PostActivate se o bean de sessão stateful puder conter estado que não é serializável. O contêiner pode apassivar uma instância de bean de sessão stateful a qualquer momento em que ele não estiver cadastrado em uma transação ou executando uma solicitação de método no momento. A instância do bean de sessão stateful é movida para o estado passivo por meio da serialização de todos os dados de estado. Se qualquer um dos dados de estado não serializar, a instância do bean de sessão stateful é descartada pelo contêiner.
- Considere implementar a interface opcional javax.ejb.SessionSynchronization se os dados de estado do bean de sessão stateful precisarem ser reconfigurados após um retrocesso de transação. Os dados de estado de um bean de sessão stateful não são transacionais e não são automaticamente reconfigurados para o estado inicial como o resultado de um retrocesso de transação. Ao implementar o método afterCompletion da interface javax.ejb.SessionSynchronization, a instância do bean de sessão stateful pode se auto-reconfigurar para o estado inicial ou consistente.
- Use a notação @AccessTimeout para proibir solicitações do cliente simultâneas ou limitar quanto tempo um método aguarda até que o bloqueio da instância seja concedido. Por padrão, o contêiner permite solicitações do cliente simultâneas, mas serializa todas as chamadas de método e retornos de chamada invocados pelo contêiner para evitar acesso multiencadeado à instância de bean de sessão stateful. Esse comportamento é como usar a simultaneidade gerenciada por contêiner com bloqueios de gravação para beans de sessão singleton. Porém, diferentemente dos beans de sessão singleton, os beans de sessão stateful não podem ser configurados para usar simultaneidade gerenciada por bean e o tipo de bloqueio não pode ser alterado. Somente o valor de tempo limite de acesso pode ser modificado para beans de sessão stateful. O seguinte exemplo de código ilustra um bean de sessão stateful com um valor de tempo limite de acesso que proíbe solicitações do cliente simultâneas:
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;
}
}
Se nenhuma anotação for fornecida, o comportamento padrão será aguardar até que um bloqueio seja concedido. Não há limite de tempo para o período que um cliente aguarda até que um bloqueio seja concedido. Como nada é codificado no nível da classe, não há limite de tempo de espera para que um bloqueio seja concedido para todos os métodos da classe. Se a anotação @AccessTimeout for usada e o contêiner não puder conceder o bloqueio no limite de
tempo especificado, uma exceção javax.ejb.ConcurrentAccessTimeoutException ocorre no cliente. A anotação @AccessTimeout aplica-se apenas
a métodos declarados na mesma classe que está a anotação
@AccessTimeout. Para uma determinada classe, os metadados para a anotação
@AccessTimeout nunca são herdados de uma classe superior na árvore de herança
de classe.
Um valor de tempo limite de acesso de -1 indica que chamadas de método simultâneas bloqueiam o acesso à instância do bean indefinidamente (o padrão). Um valor de tempo limite de acesso de 0 indica que chamadas de método simultâneas não são permitidas. A exceção, javax.ejb.ConcurrentAccessException, ocorre quando a simultaneidade é detectada. E qualquer valor positivo indica a quantidade de tempo a aguardar até que o método possa prosseguir.
Antes da Java™ EE 6, o único comportamento de simultaneidade suportado para beans de sessão stateful era um tempo limite de acesso de -1, sem simultaneidade. Como a especificaçãoJava EE 6 mudou o comportamento padrão, uma propriedade de sistema que é suportada fornece o comportamento padrão antigo. Consulte Propriedades de sistema do contêiner EJB para obter informações adicionais sobre a propriedade de sistema com.ibm.websphere.ejbcontainer.EE5Compatibility.
Também é possível especificar a anotação @AccessTimeout usando o descritor de implementação XML e, se você usar o descritor de implementação XML, os metadados da anotação @AccessTimeout serão ignorados.
O exemplo a seguir usa o descritor de implementação XML
para especificar os mesmos metadados do exemplo anterior.
<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>
- É importante saber que a codificação XML do concurrent-methodType
segue os três estilos descritos na especificação EJB para compor
o XML para elementos do método de transação do contêiner. Os três estilos são: O estilo 1 usa o nome de método especial * para aplicar o valor de tempo limite de acesso a todos os métodos de negócios
do bean especificado.
<!-- Exemplo: Estilo 1 -->
<concurrent-method>
<method>
<method-name>*</method-name>
</method>
<access-timeout>
<timeout>2000</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
O estilo 2 é usado para se referir a um método de negócios com um nome específico e designar a ele o valor de tempo limite de acesso especificado. Se o nome do método estiver sobrecarregado, isto é, diversos métodos possuem o mesmo nome, mas assinaturas de método diferentes, todos os métodos com esse nome terão o valor de tempo limite de acesso especificado.
<!-- Exemplo: Estilo 2 -->
<concurrent-method>
<method>
<method-name>businessMethod</method-name>
</method>
<access-timeout>
<timeout>2000</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
O estilo 3 é usado para se referir a um método distinto
que corresponde ao nome de método determinado e possui uma assinatura de método que corresponde aos parâmetros de método listados. O estilo 3 tem precedência sobre
os estilos 1 e 2.
<!-- Exemplo: Estilo 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>
Se o XML estilo 1 for usado para definir um valor de tempo limite
de acesso, todas as anotações @AccessTimeout no bean serão ignoradas porque o nível do método um será usado no lugar.
- Assegure-se de que entenda as regras de herança das
anotações usadas.
- Beans de sessão stateful não são reentrantes, o que significa que o método do bean de sessão stateful chama a si mesmo de volta. Se uma chamada reentrante é feita para um bean de sessão stateful, uma exceção javax.ejb.ConcurrentAccessTimeoutException ocorre no cliente, independentemente do valor do tempo limite de acesso. Essa exceção não resulta no bean de sessão stateful que está sendo descartado, nem marca a transação para retrocesso, a menos que a exceção não seja tratada pelo responsável pela chamada.