Jim,

You say: "Now the code in performLimitCheck() could query the database
directly, or work with a collection of EJBs. We don't really care at
this point."

Actually, I think you care very much.  If you do indeed work with a collection
of EJBs (which I would assume are Account entities) then you will see the
balance as defined after the withdrawal.

Note that I agree that the database will not be modified unitl 7, but you
modify the entity in 4, and any other time you access that same entity in
the same transaction, it will have the same balance as what you set it to.

To be more precise, your performLimitCheck will obtain a collection
of Account objects including the modified account, and add up the
balances for all Accounts.  If this is less that $100, the current
transaction will be marked for rollback.

Note that the only issue I see is that the validation logic must occur
in the same transaction (and typically in the same VM) as the withdrawal.

The colocality constraint is due to the fact that the EJB spec requires
the detection of local diamonds (that is, getting to the same Entity via
multiple references) but does not require the detection of non-local
diamonds.

Basically, I don't see what you are doing as problematic, so long as you
use entity beans, and have colocality between your SBs and your EBs.

I agree that if you try to do the validation in SQL, you will run into
problems.  But if you stick to the EJB model, it will all work properly.

-jkw

James Cook wrote:
>
> OK, here is a fairly interesting design question that surfaces when you begin to
> design non-trivial EJBs. Unfortunately, I will have to trivialize the example to
> make it easily presentable. The major assumption that you will have to make is
> an EJB cannot always validate itself. Sometimes the validation of an entity bean
> (a row in the database) can only be determined by another method external to the
> entity bean.
>
> Trivial Example
> ============
> A bank allows its customers to have multiple accounts, but the balance in all
> accounts combined, cannot be less than $100.
>
> Design
> ======
> Logically, we would create a stateless session bean Teller, that directly
> manipulates Account entity beans. Our database is set to read-uncommitted, a
> common and default setting of most databases. The withdrawal method in Teller
> performs the following pseudocode logic:
>
> 1. Teller.withdrawal (String accountPK, BigDecimal amount) {
> 2.     // do the dirty work
> 3.     Account account = accountHome.findByPrimaryKey(accountPK);
> 4.     account.withdrawal(amount);
> 5.     // make sure account balances didn't drop below limit
> 6.     performLimitCheck();
> 7. }
>
> Now the code in performLimitCheck() could query the database directly, or work
> with a collection of EJBs. We don't really care at this point.
>
> The Design Problem
> ===============
> The flaw with the above logic has to do with the order that the EJB container
> performs its operations. Line 4 above causes the ejbContainer to perform an
> ejbLoad() on our Account bean. Next the withdrawal() method is invoked and the
> bean's attributes reflect the new amount. Note: No data has been written to the
> database yet! By the time line 6 performs its validation of the current state of
> the database, the database hasn't changed one bit. It will always report that
> all is fine.
>
> It isn't until line 7 that the ejbContainer invokes ejbStore() and the Account
> bean writes the data to the database. At this time, the database may be in an
> invalid state.
>
> The Workaround
> =============
> I'm not sure there is a good one. In my trivial example, some would argue that
> the performLimitCheck() should take into consideration the withdrawal amount
> when validating the database. I would argue that this is a trivial example.
> Suppose there was business logic in the AccountBean that added interest to the
> account at the same time the withdrawal amount reduced the balance? Given more
> complex scenarios this "pre-validation" technique continues to have other
> problems.
>
> The only workaround that I can see is to call ejbStore() before validating the
> bean, or in a worse case, invoke it at the end of the withdrawal() method. This
> shouldn't cause any integrity problems that I can see, although most entity
> beans would suffer performance slowdowns due to multiple ejbStore() calls.
>
> The Solution
> ==========
> The EJB spec authors should give us a way to tie a validation method to each
> session bean method. This could be extended to entity beans, but that doesn't
> help us. This validation method would be called by the EJB container after all
> ejbStore() methods are called, and before the transaction is closed.
>
> As always, I am interested in your feedback. Please comment.
>
> jim

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff EJB-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to