Retour vers les EJB 2.0

« Nom de Zeus !
Marty va chercher la DeLorean. On retourne dans le passé en 2001, à l’époque de la sortie de J2EE 1.3 !
Il faut absolument qu’on brûle retrouve les spécifications des EJB 2.0. »

« Mais on ne risque pas de modifier le continuum espace-temps ? »

Quelquefois, avec les EJB 2 Entity (soit la couche de persistance) et un serveur d’application adéquat, suite à une erreur de programmation, on pourra avoir une remontée d’erreur dans les logs qui fait référence à : [EJB 2.0 Spec. 10.5.2].
Ce qui est mieux, c’est encore de savoir à quoi çà correspond. Heureusement dans les specs, c’est plutôt bien détaillé.

Extrait : [EJB 2.0 Spec. 10.5.2]

10.5.2 Bean Provider’s entity bean instance’s view

The following describes the entity bean instance’s view of the contract as seen by the Bean Provider:

The entity Bean Provider is responsible for implementing the following methods in the abstract entity bean class:

  • A public constructor that takes no arguments.

  • public void setEntityContext(EntityContext ic);
    A container uses this method to pass a reference to the
    EntityContext interface to the entity bean instance. If the entity bean instance needs to use the EntityContext interface during its lifetime, it must remember the EntityContext interface in an instance variable.
    This method executes with an unspecified transaction context (Refer to Subsection 17.6.5 for how the Container executes methods with an unspecified transaction context). An identity of an entity object is not available during this method. The entity bean must not attempt to access its persistent state and relationships using the accessor methods during this method.
    The instance can take advantage of the
    setEntityContext() method to allocate any resources that are to be held by the instance for its lifetime. Such resources cannot be specific to an entity object identity because the instance might be reused during its lifetime to serve multiple entity object identities.

  • public void unsetEntityContext();
    A container invokes this method before terminating the life of the instance.
    This method executes with an unspecified transaction context. An identity of an entity object is not available during this method. The entity bean must not attempt to access its persistent state and relationships using the accessor methods during this method.
    The instance can take advantage of the
    unsetEntityContext() method to free any resources that are held by the instance. (These resources typically had been allocated by the setEntityContext() method.)

  • public PrimaryKeyClass ejbCreate<METHOD>(…);
    There are zero
    [13] or more ejbCreate<METHOD>(…) methods, whose signatures match the signatures of the create<METHOD>(…) methods of the entity bean’s home interface. The container invokes an ejbCreate<METHOD>(…) method on an entity bean instance when a client invokes a matching create<METHOD>(…) method on the entity bean’s home interface.
    The entity Bean Provider’s responsibility is to initialize the instance in the
    ejbCreate<METHOD>(…) methods from the input arguments, using the get and set accessor methods, such that when the ejbCreate<METHOD>(…) method returns, the persistent representation of the instance can be created. The entity Bean Provider is guaranteed that the values that will be initially returned by the instance’s get methods for container-managed fields will be the Java language defaults (e.g. 0 for integer, null for pointers), except for collection-valued cmr-fields, which will have the empty collection (or set) as their value. The entity Bean Provider must not attempt to modify the values of cmr-fields in an ejbCreate<METHOD>(…) method; this should be done in the ejbPostCreate<METHOD>(…) method instead.
    The entity object created by the
    ejbCreate<METHOD> method must have a unique primary key. This means that the primary key must be different from the primary keys of all the existing entity objects within the same home. However, it is legal to reuse the primary key of a previously removed entity object. The implementation of the Bean Provider’s ejbCreate<METHOD>(…) methods should be coded to return a null.[14]
    An ejbCreate<METHOD>(…) method executes in the transaction context determined by the transaction attribute of the matching create<METHOD>(…) method, as described in subsection. The database insert operations are performed by the container within the same transaction context after the Bean Provider’s ejbCreate<METHOD>(…) method completes.

  • public void ejbPostCreate<METHOD>(…);
    For each ejbCreate<METHOD>(…) method, there is a matching ejbPostCreate<METHOD>(…) method that has the same input parameters but whose return type is void. The container invokes the matching ejbPostCreate<METHOD>(…) method on an instance after it invokes the ejbCreate<METHOD>(…) method with the same arguments. The instance can discover the primary key by calling getPrimaryKey() on its entity context object.
    The entity object identity is available during the
    ejbPostCreate<METHOD>(…) method. The instance may, for example, obtain the component interface of the associated entity object and pass it to another enterprise bean as a method argument.
    The entity Bean Provider may use the
    ejbPostCreate<METHOD>(…) to set the values of cmr-fields to complete the initialization of the entity bean instance.
    An
    ejbPostCreate<METHOD>(…) method executes in the same transaction context as the previous ejbCreate<METHOD>(…) method.

  • public void ejbActivate();
    The container invokes this method on the instance when the container picks the instance from the pool and assigns it to a specific entity object identity. The ejbActivate() method gives the entity bean instance the chance to acquire additional resources that it needs while it is in the ready state.
    This method executes with an unspecified transaction context. The entity bean must not attempt to access its persistent state or relationships using the accessor methods during this method.
    The instance can obtain the identity of the entity object via the
    getPrimaryKey(), getEJBLocalObject(), or getEJBObject() method on the entity context. The instance can rely on the fact that the primary key and entity object identity will remain associated with the instance until the completion of ejbPassivate() or ejbRemove().

  • public void ejbPassivate();
    The container invokes this method on an instance when the container decides to disassociate the instance from an entity object identity, and to put the instance back into the pool of available instances. The
    ejbPassivate() method gives the instance the chance to release any resources that should not be held while the instance is in the pool. (These resources typically had been allocated during the ejbActivate() method.)
    This method executes with an unspecified transaction context. The entity bean must not attempt to access its persistent state or relationships using the accessor methods during this method.
    The instance can still obtain the identity of the entity object via the
    getPrimaryKey(), getEJBLocalObject(), or getEJBObject() method of the EntityContext interface.

  • public void ejbRemove();
    The container invokes the
    ejbRemove() method on an entity bean instance in response to a client-invoked remove operation on the entity bean’s home or component interface or as the result of a cascade-delete operation. The instance is in the ready state when ejbRemove() is invoked and it will be entered into the pool when the method completes.
    The entity Bean Provider can use the
    ejbRemove method to implement any actions that must be done before the entity object’s persistent representation is removed.
    The container synchronizes the instance’s state before it invokes the
    ejbRemove method.
    This means that the state of the instance at the beginning of the
    ejbRemove method is the same as it would be at the beginning of a business method.
    This method and the database delete operation(s) execute in the transaction context determined by the transaction attribute of the
    remove method that triggered the ejbRemove method. The instance can still obtain the identity of the entity object via the getPrimaryKey(), getEJBLocalObject(), or getEJBObject() method of the EntityContext interface.
    After the entity Bean Provider’s
    ejbRemove returns, and in the same transaction context, the Container removes the entity bean from all relationships in which it participates before removing the entity object’s persistent representation.
    Since the instance will be entered into the pool, the state of the instance at the end of this method must be equivalent to the state of a passivated instance. This means that the instance must release any resource that it would normally release in the
    ejbPassivate() method.

  • public void ejbLoad();
    When the container needs to synchronize the state of an enterprise bean instance with the entity object’s persistent state, the container calls the
    ejbLoad() method.
    The entity Bean Provider can assume that the instance’s persistent state has been loaded just before the
    ejbLoad() method is invoked. It is the responsibility of the Bean Provider to use the ejbLoad() method to recompute or initialize the values of any instance variables that depend on the entity bean’s persistent state. In general, any transient state that depends on the persistent state of an entity bean should be recalculated using the ejbLoad() method. The entity bean can use the ejbLoad() method, for instance, to perform some computation on the values returned by the accessor methods (for example, uncompressing text fields).
    This method executes in the transaction context determined by the transaction attribute of the business method that triggered the
    ejbLoad method.

  • public void ejbStore();
    When the container needs to synchronize the state of the entity object’s persistent state with the state of the enterprise bean instance, the container first calls the ejbStore() method on the instance.
    The entity Bean Provider should use the
    ejbStore() method to update the instance using the accessor methods before its persistent state is synchronized. For example, the ejbStore() method may perform compression of text before the text is stored in the database.
    The Bean Provider can assume that after the
    ejbStore() method returns, the persistent state of the instance is synchronized.
    This method executes in the same transaction context as the previous
    ejbLoad or ejbCreate method invoked on the instance. All business methods invoked between the previous ejbLoad or ejbCreate<METHOD> method and this ejbStore method are also invoked in the same transaction context.

  • public primary key type or collection ejbFind<METHOD>(…);
    The Bean Provider of an entity bean with container-managed persistence does not write the finder (
    ejbFind<METHOD>(…)) methods.
    The finder methods are generated at the entity bean deployment time using the Container Provider’s tools. The syntax for the Bean Provider’s specification of finder methods is described in Chapter 11, “EJB QL: EJB Query Language for Container-Managed Persistence Query Methods”.

  • public type ejbHome<METHOD>(…);
    The container invokes this method on the instance when the container selects the instance to execute a matching client-invoked
    <METHOD>(…) home method. The instance is in the pooled state (i.e., it is not assigned to any particular entity object identity) when the container selects the instance to execute the ejbHome<METHOD> method on it, and it is returned to the pooled state when the execution of the ejbHome<METHOD> method completes.
    The
    ejbHome<METHOD> method executes in the transaction context determined by the transaction attribute of the matching <METHOD>(…) home method, as described in Section 17.6.2.
    The entity bean provider provides the implementation of the
    ejbHome<METHOD>(…) method. The entity bean must not attempt to access its persistent state or relationships using the accessor methods during this method because a home method is not specific to a particular bean instance.

  • public abstract type ejbSelect<METHOD>(…);
    The Bean Provider may provide zero or more select methods. A select method is a query method that is not directly exposed to the client in the home or component interface. The Bean Provider typically calls a select method within a business method.
    The Bean Provider defines the select methods as
    abstract methods.
    The select methods are generated at the entity bean deployment time using the Container Provider’s tools.
    The syntax for the specification of select methods is described in Chapter 11, “EJB QL: EJB Query Language for Container-Managed Persistence Query Methods”.
    The
    ejbSelect<METHOD> method executes in the transaction context determined by the transaction attribute of the invoking business method.

 

Mr-Happy-ManHeureusement en 2013, le cauchemar EJB 2 est terminé, car depuis on a bénéficié de Hibernate, EJB 3 et JPA (depuis JEE5) qui ont permis de largement simplifier les choses.

Références :

Publicités

Set or not set une relation d’un EJB Entity 2 dans ejbCreate() ?

Avec les EJB 2, il est possible de définir des relations entre les entités (de type many-to-one, one-to-many).

Le problème se pose lorsque que l’on veut créer un enregistrement en relation avec l’enregistrement principal que l’on va persister (cas d’une insertion en base).
Par exemple si l’on persiste une instance de l’objet Client, et que celui-ci possède une relation (0-n) vers une table Adresse, on va tout d’abord créer l’instance de Client (avec ejbCreate() en EJB 2), puis l’instance de Adresse également via un ejbCreate(), le tout dans une même transaction.

La question est : où placer le rattachement de Adresse à Client ?
Si l’on essaie dans la méthode ejbCreate() de Adresse d’appeler setClient(monClient) (correspond à une relation FK en BDD), cela ne fonctionnera pas.
On aura une exception du type :

java.lang.IllegalStateException: A CMR field cannot be set in ejbCreate; this should be done in the ejbPostCreate method instead [EJB 2.0 Spec. 10.5.2].

Donc la solution est de définir une méthode ejbPostCreate() avec les mêmes paramètres que la méthode ejbCreate() dans le bean Adresse, et d’y ajouter l’instruction :

setClient(monClient)

Et là çà fonctionne en principe.

BONUS : Et pour voir la spec EJB 2.0 en détail, notamment concernant les EJB Entity : Retour vers les EJB 2.0.