ejbRemove()

Discussions

EJB programming & troubleshooting: ejbRemove()

  1. ejbRemove() (15 messages)

    You can find this code in Mastering EJB on page 148 [Bean Managed Persistance] :

    public void ejbRemove() throws RemoteException {
          AccountPk primaryKey = entityContext.getPrimaryKey();
          ...
        --- Removing a row associtated with the primary key ----

    why in ejbRemove() we should getPrimaryKey from entityContext object [it not true that we have primarykey in on field of our bean class??? ]

    please Help :)

    --Thanx

    Threaded Messages (15)

  2. ejbRemove()[ Go to top ]

    Yah U R rite,

    It actually depends how U implement UR application N what it demands.
    C how U actually remove a row in a database,(by its primary key rite?)

    So he is getting a primary key object in this method.
    Or U can just use the field which U want 2 refer in this method.

    For Eg.
    ejbRemove()
    {
    this.varName = varName;
    }

    But ideally it is always done based on primary key.

    Thanks
    Jane
  3. ejbRemove()[ Go to top ]

    i don't unserstand what you mean ?
    you mean that it is not defferent to get primary key from entitycontext or use the field that we have in our bean class for primary key ?

    --Thanx
  4. ejbRemove()[ Go to top ]

    The main reason to do so , is becuase when the EJBRemove is being called , the container may choose not to do a load on the Serialized object and simple take a passivated object and return that to you with the appropriate Primary Key information in the Context. hence the local store of the primary key maybe technical incorrect or corrupt for that operation. Since from a programatic sense it is difficult to figure this out it is always safe to use the Primary Key from the Context. If I remember right the book does say something about it.

    Hope this helps.
  5. ejbRemove()[ Go to top ]

    do you mean that it is not safe to use the primary key field that we have in out bean class implemenetation ?

    but i see this approach i J2EE Tutorial from sun, there is not anything about getting primary key from entity context !

    how can u explain this ?
  6. ejbRemove()[ Go to top ]

    I see your point.

    Lets consider this. The primay key in the bean is a non Transient entity, it can be serialized ( which is a requirement ). If you look at the EJB contracts the setEJBContext call always happens before the ejbLoad / ejbActivate. So if the container was asked to remove an EJB , it happens to have had that particular EJB passivated , it can regenerate the context and supply it any bean which is still in memory and call remove on it, without having to do a load. Agreed, this might depend on how the Container is written but is totaly possible especially for CMP based beans not truly for BMP. Hence it is a better choice to use the Primary key from the context rather than the the one in the bean itsself. This will guarantee that it will work consistently across all Containers ( It is a myth however ;) ). So I guess the answer is not as clear cut as you'd expect it to be. The rule of thumb I typically use when in doubt be safe. The Spec guarantees that the Primary Key in the Context will be correct and not otherwise (the one in the bean , which is the room given to container writers to play with). Maybe all the containers out there are not optimized in this way , so we might have it safe.
  7. ejbRemove()[ Go to top ]

    Thanx a lot :)
  8. ejbRemove()[ Go to top ]

    if i get the answer , we can do this in ejbLoad too. is it true ?

    and can we do this is ejbActivate() method [getting primaryKey from entityContext] instead of inside all of these methods that we need it ?

    --Thanx
  9. ejbRemove()[ Go to top ]

    Hi,

    When I read the book (which in French is EJB Fondamental), I didn't understand
    why the author, in the Entity Bean BMP example, AccountBean.java didn't use the field "AccountId" instead of using getPrimaryKey() from the context.

    Whereas, I do understand the use of getPrimaryKey() inside the ejbLoad() method
    because, when ejbLoad() is called the bean is in the Pool and is not "ready".
    Hence, using the ctc is a way to get the instance of the bean associated with
    the EJB.

    However, I don't see why it's not correct to use the field accountID of the bean, since when ejbRemove() is called the bean is in the "ready" state and all its fields are mapped to a given data instance.



    I would really appreciate, you make this more clear for me.


    thanks
                 Olivier
  10. ejbRemove()[ Go to top ]

    Rajesh,

    I think your interpretation of the EJB spec is incorrect. Consider this quote from the EJB2.0 specification, section 12.1.4.1:

    "The instance is in the ready state when ejbRemove() is invoked and it will be
    entered into the pool when the method completes." (ready state means the instance has been assigned an entity identity and associated with that identity by a call to ejbActivate).

    and:

    "The container synchronizes the instance’s state before it invokes the ejbRemove method. This means that the state of the instance variables at the beginning of the ejbRemove method is the same as it would be at the beginning of a business method."

    I think it is quite clearly stated that an instance must be loaded and synchronized before ejbRemove may be invoked by the container.
    I can't think of a definite reason for not using the primary key field instead of getting the primary key from the entity context. Maybe it was done simply because the author wanted to choose some unified way of accessing the PK in callbacks, and in some callbacks you do have to use the EntityContext (ejbActivate). Anyway, AFAIK, in ejbRemove there should be no problem with using the beans instance's PK field.

    Gal
  11. ejbRemove()[ Go to top ]

    Gal ,

    I just went through the spec and yes you are correct. Reading the spec I came across this paragraph.

    Containers Contract For ejbRemove ()

    "The container invokes this method before it ends the life of an entity object as a result of a client invoking a remove operation.

    The container invokes this method in the transaction context determined by the transaction attribute of the invoked remove method.
    The container mush ensure that the identity of the associated entity object is still available to the instance in the ejbRemove() method ( i.e the instance can inoke the getPrimaryKey() or getEJBObject() method on its EntityContext in the ejbRemove() method).

    The container my ensure that the instances's state is synchronized from the state in the database before invoking ejbRemoe() method (i.e if the instance is not already synchronized from teh state in the database, the container must invoke ejbLoad before it invokes ejbRemove)."

    This further emphasizes your point ( feel stupid , but heck we all have to learn one way or the other ). However reading this paragraph I think using the getPrimaryKey method of the Context seems to be like a recomendation from the Spec authors more than anything else. Hence a good programming practice ( Ah now we get into preferences of how to code , I hate that. Lets keep off it, I shall try real hard too ).

    I am not convinced personally that in the event that the Container supports Row Level locking ( this means that object is synchronized with the db for the duration of the transaction ) it will call ejbLoad before the ejbRemove based on my interpretation of the spec ie.


    Thanx a bunch.
  12. ejbRemove()[ Go to top ]

    Rajesh,

    As I understand it, the container has to synchronize the state of the bean at least once before calling ejbRemove (just like a business method; see the quote in my previous post). Even if it does not, you can (and in my opinion should) update the PK field on ejbActivate. It may be a good idea to also nullify it on ejbPassivate and ejbRemove. This way you can allways access the PK directly (without using the entity context), and as a result make your code more readable (and require less casting). But, as you said, this is mostly a programming preference.

    Olivier,

    I don't have the book, can you post the relevant code? I don't understand why would they have a PK field if they never use it. Maybe they update the PK field in ejbActivate?

    Gal
  13. ejbRemove()[ Go to top ]

    You can download the PDF of the Book from this site. Look under books and articles.
  14. ejbRemove()[ Go to top ]

    I had the electronic version. I don't any more, and I don't intend to get it. I don't like that book. I think the spec is far better a source, and once you get to know it it's also better as a reference.

    Gal
  15. ejbRemove()[ Go to top ]

    Gal,

    Here is the source code for the ejbactivate, ejbLoad and ejbRemove we are talking about.

    (For my own opinion, I have really enjoyed this book and I found it's an excellent introduction for an EJB beginner)

    /**
     * Demonstration Bean-Managed Persistent Entity Bean.
     * This Entity Bean represents a Bank Account.
     */
    public class AccountBean implements EntityBean {

    protected EntityContext ctx;

    //
    // Bean-managed state fields
    //

    private String accountID; // PK
    private String ownerName;
    private double balance;

                      ......

    /**
    * Called by Container. Implementation can acquire
    * needed resources.
    */
    public void ejbActivate() {
    System.out.println("ejbActivate() called.");
    }

    /**
    * Removes entity bean data from the database.
    * Corresponds to when client calls home.remove().
    */
    public void ejbRemove() throws RemoveException {
    System.out.println("ejbRemove() called.");

    /*
    * Remember that an entity bean class can be used to
    * represent different data instances. So how does
    * this method know which instance in the database
    * to delete?
    *
    * The answer is to query the container by calling
    * the entity context object. By retrieving the
    * primary key from the entity context, we know
    * which data instance, keyed by the PK, that we
    * should delete from the DB.
    */
    AccountPK pk = (AccountPK) ctx.getPrimaryKey();
    String id = pk.accountID;

    PreparedStatement pstmt = null;
    Connection conn = null;
    try {
    /*
    * 1) Acquire a new JDBC Connection
    */
    conn = getConnection();

    /*
    * 2) Remove account from the DB
    */
    pstmt = conn.prepareStatement("delete from accounts where id = ?");
    pstmt.setString(1, id);

    /*
    * 3) Throw a system-level exception if something
    * bad happened.
    */
    if (pstmt.executeUpdate() == 0) {
    throw new RemoveException("Account " + pk + " failed to be removed from the database");
    }
    }
    catch (Exception ex) {
    throw new EJBException(ex.toString());
    }
    finally {
    /*
    * 4) Release the DB Connection
    */
    try { if (pstmt != null) pstmt.close(); }
    catch (Exception e) {}
    try { if (conn != null) conn.close(); }
    catch (Exception e) {}
    }
    }

    /**
    * Called by Container. Releases held resources for
    * passivation.
    */
    public void ejbPassivate() {
    System.out.println("ejbPassivate () called.");
    }

    /**
    * Called by the container. Updates the in-memory entity
    * bean object to reflect the current value stored in
    * the database.
    */
    public void ejbLoad() {
    System.out.println("ejbLoad() called.");

    /*
    * Again, query the Entity Context to get the current
    * Primary Key, so we know which instance to load.
    */
    AccountPK pk = (AccountPK) ctx.getPrimaryKey();
    String id = pk.accountID;

    PreparedStatement pstmt = null;
    Connection conn = null;
    try {
    /*
    * 1) Acquire a new DB Connection
    */
    conn = getConnection();

    /*
    * 2) Get account from the DB, querying
    * by account ID
    */
    pstmt = conn.prepareStatement("select ownerName, balance from accounts where id = ?");
    pstmt.setString(1, id);
    ResultSet rs = pstmt.executeQuery();
    rs.next();
    ownerName = rs.getString("ownerName");
    balance = rs.getDouble("balance");
    }
    catch (Exception ex) {
    throw new EJBException("Account " + pk + " failed to load from database", ex);
    }
    finally {
    /*
    * 3) Release the DB Connection
    */
    try { if (pstmt != null) pstmt.close(); }
    catch (Exception e) {}
    try { if (conn != null) conn.close(); }
    catch (Exception e) {}
    }

    }
    }

    Olivier
  16. ejbRemove()[ Go to top ]

    Gal,

    I am ok with you.

    Though I have not read the spec, I seems clear to me looking at the BMP Entity Bean Lifecycle diagram of the book, that clients can make the assumption that the bean is in a "ready" state when ejbRemove() is called by the container.
    I also think that it's good practice or more careful to use the getPrimaryKey() method.

    BUT ...

    ... if you look at the source code of ejbLoad() in the book, you'll see that
    when data are retrieved from the database using JDBC, only the "ownerName" and the "balance" fields are set with this values, i.e :
    --
    ownerName=rs.getString("ownnerName");
    balance = rs.getDouble("balance");
    ---

    "

    And the field "AccountID" is NOT set with the value of getPrimaryKey().

    Hence, this field has an incorrect value and so ejbRemove() cannot use it.

    It's perhaps an explanation why the authors of the book have used getPrimaryKey() in ejbRemove().



    Olivier