> Hi,
>
> thanks for the effort with answering my questions! To maybe
> better explain what I'm aiming at here:
>
> - Using CMP and CMR I can have a nice EJB scenario with 1:n
> relationship
> Artist <1:n> Cd. My understanding is that container is responsible
> for handling the relationship code so that I can always trust that
> I'm getting valid references no matter how I use cd.getArtist(),
> cd.setArtist(), artist.getCds(), artist.getCds(). When implementing
> the beans, I do not have to worry about whether there is
> caching or not,
> what is the caching strategy, etc. That I can leave to container,
> which is the added value of EJB's.
Well... this holds water until you cluster. There are important bits of
info the app server can't know if you don't tell them to him, and they
could impact caching/performance improvements. Will all DB write
statements be issued by CMP EJBs? Or BMP EJBs? Refer to sections 10.5.9
and 12.1.9 on EJB 2.0-fr2 spec. This is why some EJB 1.1 containers
allowed for an isDirty() or isModified() methods, returning a boolean
signalling the container whether it should call ejbStore or not.
>
> - I believe same thing _should_ be reachable using BMP's. I
> should be able
> to create BMP entity beans that keep the references valid with
> any use of cd.getArtist(), artist.setCds() etc. I should
> not have to worry
> about caching, trascations etc. as long as I follow the
> rules regarding
> call-back methods ejbLoad(), ejbActivate() etc - that's
> what the container
> is there for! But how to do this?
You'd have to reimplement a lot of the container. Using CMP, the
container knows not only when these methods were executed, it also knows
WHAT was executed. On EJB 2.0, it also knows at all times which fields
were touched since the last ejbStore.
>
> - 1:n relationships are quite common in all designs so this
> should be a
> common and basic problem.
>
> - If using remote interfaces is a problem, I think having only local
> interfaces to entity beans is perfectly acceptable.
>
> >> >> Now, I would implement this so that the relationship fields
> >> >> (Cd.artist and
> >> >> Artist.cds) are lazy loaded.
> >> >
> >> >This implies that you're not caching anything.
> Transaction isolation
> >> >comes into play here as well. These are important details when
> >> >considering stale-data scenarios.
> >>
> >> In this example I'm assuming that there is caching of EJBs
> which is
> >> handled by container. And that the transaction is
> initiated by a call
> >> to session bean (session facade).
> >
> >Super. EJB instances are cached.
> >What's the caching schema?
>
> Do I have to know that? Can't I leave it to container /
> decide it deploy -time?
No. The container has defaults, but they usually unleash havoc in
clustered environments. Usually you're stuck to Commit Option C. You may
be able to work your way up to Option A, bean per bean, as long as you
know something the container doesn't know (for instance, that CD is
inmutable: once created it stays as is, except relationships).
Optimizing applications in a clustered environment is an art in itself,
as the optimizations you can use are heavily dependant on the system
you're developing.
>
> >Relationships are lazy-loaded. How?
> >You load the PK's for the relationships lazily?
> >You have a special Collection implementation that loads the EJBs
> >lazily? Both?
>
> Like:
>
> ArtistBean {
> private Collection cds;
> private boolean cdsLoaded = false;
>
> public Collection getCds() {
> if (!cdsLoaded) {
> try {
> BmpCdLocalHome cdHome = (BmpCdLocalHome)
> HomeFactory.getInstance()
> .intraEjbLookUpEjbRef("java:comp/env/ejb/Cd");
> cds = cdHome.findByArtistId(id);
> cdsLoaded = true;
> } catch (NamingException n) {
> throw new EJBException (n);
> } catch (FinderException f) {
> throw new EJBException(f);
> }
> }
> return cds;
> }
> /*...ejbLoad() / ejbStore() do not touch cds. So far I have
> artist.cds as
> read - only.*/
> }
Superb, so you load the CDs just-in-time. You rely on the container
loading the actual instances when necessary.
You should:
Mark both private fields as transient.
Clear at least cdsLoaded in ejbPassivate or in ejbLoad.
Or drop the caching of the loaded Collection altogether. Check out the
instance lifetime charts and commit options for BMP EBs on section 12 of
the spec (12.1.3 and 12.1.9).
Essentially, this could happen:
You start a transaction and load "Bruce Springsteen".
You fetch CDs.
Transaction ends, the instance is reused when someone else loads
"Madonna".
You fetch CDs (but they're already loaded!).
You're into shock-and-awe since you find out that Madonna released "Born
In The USA"!!!
This assumes you're using EJB 2.0. If you load the CDs the way you are
in EJB 1.1, ejbStore will be called at least once for each and every CD
you've loaded before the transaction ends, just because you've loaded
them.
>
> Cd {
> private Integer artistId;
> private BmpArtistLocal artist;
> private boolean artistLoaded = false;
>
> public BmpArtistLocal getArtist() {
> if (!artistLoaded) {
> try {
> BmpArtistLocalHome artistHome = (BmpArtistLocalHome)
> HomeFactory.
> getInstance()
> .intraEjbLookUpEjbRef("java:comp/env/ejb/Artist");
> artist = artistHome.findByPrimaryKey(artistId);
> artistLoaded = true;
> } catch (FinderException f) {
> throw new EJBException(f);
> } catch (NamingException n) {
> throw new EJBException(n);
> }
> }
> return artist;
> }
>
> public void setArtist(OBmpArtistLocal artist) {
> this.artist = artist;
> this.artistId = artist.getId();
>
> this.artistLoaded = true;
> }
> }
>
Again, careful what you cache here.
> >> // make sure that artist EJBs reference the right cd EJB
> >> artist.addCd(this);
> >
> >What's that? You can't pass 'this' there. Pass the PK or the handle.
>
> Ok, sorry, that was just pseudocode, that would be handle then....
>
> >Bear in mind that if you execute this code:
> >
> >Artist {
> > addCd(Cd cd) {
> > cdList.add(cd.getPrimaryKey() );
> > }
> >}
> >
> >You'll need to mark the bean as reentrant.
>
> Why? Client -> Artist.addCd() -> cd.getPrimaryKey() - there's
> no loop or re-entrancy? Of course if you mean that
> artist.addCd() was called from cd.setArtist - yes, there's a
> problem. And marking the bean as re-entrant opens up another
> can of worms, I think. Oh well...
>
> >> What I am trying to accomplish here is nice automatic relationship
> >> handling a la CMP CMR but with BMP. I am aware that it is probably
> >> not the easiest route, but this is for testing / education
> purposes.
> >
> >I also take it that you're planning to use Remote interfaces. That's
> >the whole problem. With local interfaces the container can
> make certain
> >assumptions that will allow for complete consistency without huge
> >performance penalties.
> >
> >Essentially it boils down to these situations that the
> container must
> >handle somehow:
> >
> >You're using Remote interfaces (so calls and lookups may come from
> >anywhere).
> >
> >When do you issue the ejbStore call? Right away, at certain
> intervals,
> >at the end of the transaction? If you fire it before the transaction
> >commits, how does your database rollback segment behave?
> >If caching is enabled, when will cached instances on other servers be
> >updated?
>
> For sure container should call ejbStore before the end of
> transaction, I would imagine. You cannot call it after the
> trasaction has ended. How could commit / rollback work then?
> Sorry, maybe I missed your point...
Of course. But that's all you know; not WHEN it'll call, nor HOW MANY
TIMES it'll call.
You also can't be sure of the sequence in which it'll be called. And you
need not to worry when using CMP.
>
> I'm quite happy with having only local interfaces to the
> entity beans since they are usually behind session facade
> anyway. There has to be way to implement relationships with
> BMP's decently, a la CMP CMR. After all a well-known design
> strategy is to implement BMP that inherits CMP, so that you
> can deploy CMP's when you container supports them, or fall
> back to BMP's with more limited containers.
No, that's not a well known design strategy. That's a well known sound
bite. Trying to code this way leads to frustration, not to mention it's
an unnecessary burden. CMP is available today on each and every server
that hasn't reached EOL. If you by any chance have to deploy on
Websphere, you'd be better going to the nearest Santer�a and buying
candles and Saint's stamps. No pun intended, but the contract on BMP
leaves a big burden on the developer. You also expect to cluster, which
elevates the problems heavily, and also, there are no Local interfaces
on EJB 1.1... Are you using that, or 2.0?
>http://developer.java.sun.com/developer/technicalArticles/ebeans/sevenr
ules/
That article is aged. It's EJB 1.1-- you won't be able to deploy as EJB
2.0. Having dual semantics implementations isn't as trivial as it was in
EJB 1.1.
>
>Those who implement this strategy and use CMR with CMP's have to solve
this problem with BMP's...
Yes, or drop the BMP implementation they don't need and can't fix.
>
>Can anybody point to a good source of information on how to handle
entity bean relationships correctly with BMPs?
Your not far in your implementation. Just remember to clean the caches.
Adding VO's for CDs would help a lot as well.
HTH,
JP
===========================================================================
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".