Jim,
I thought I might follow up on your question to:
1) show an example of using references, and
2) set the stage for a question regarding the EJB spec. that has been
nagging me for a while.
In your example, you have a Child entity which has a reference to an
Address entity, and which has references to a collection of Toy
entities. Using the normal EJB naming conventions, where Foo is the
remote interface and FooBean is the bean implementation class, then
you would have the following:
public class ChildBean implement EntityBean {
public String name; // child's primary key field
public Address address; // container managed reference to Address
public Collection toys; // container managed collection of Toys
// other stuff omitted
}
public class Address implements EntityBean {
public Integer id; // Address's primary key field
public String street; // various container managed fields
public String city;
public int zipCode;
// other stuff omitted
}
public class Toy implements EntityBean {
public Child child; // partial primary key, also a foreign key
public int index; // other half of the primary key
public String color; // some other container managed fields
// other stuff omitted
}
As you can see, we have container managed fields which are references
to the various entities' remote interfaces, or collections thereof.
These typically correspond to foreign keys in the underlying schema.
<vendor> We too will automatically create the various tables for you,
if you are not mapping to preexisting tables.</vendor>
The question that has been bothering me has to do with the primary key
for Toy. As you can see, Toy's primary key is a composite of a
foreign key referring to a Child, and an index indicating which toy it
is.
(Note that I am assuming the Child-to-Toy relationship is one-to-many,
not many-to-many. I.e., two children cannot own the same toy. This
is just a simplifying assumption, not a requirement of the model.)
Thus, the primary key type of Toy would be:
public class ToyPK implements Serializable {
public Child child;
public int index;
public int hashCode() {
// details omitted
}
public boolean equals(Object object) {
// details omitted
}
}
So, my question is how can we implement the hashCode and equals
method? In the EJB spec., it is required that I implement these
methods, but for fields which are remote references, it is not clear
to me that there is a portable and performant way to write these
methods.
The equals method is not overly complicated to implement:
public boolean equals(Object object) {
if(!(object instanceof ToyPK)) {
return false;
}
ToyPK that = (ToyPK) object;
try {
return this.index == that.index && this.child.isIdentical(that.child);
}
catch(RemoteException e) {
// if we are unable to call isIdentical, then assume the references
// are not the same
return false;
}
}
This was not too hard to write, but unfortunately has poor
performance, in that if I am not colocated with the EJBs, I have to do
an RPC to the server to handle the isIdentical method.
Much harder is writing the hashCode method. Obviously, computing a
hash code for an int is trivial, but what about the Child reference.
The best that I can do in a totally portable manner is to get the
child's handle, serialize it to an object output stream, an then
compute a hash code from the stream's underlying byte array:
ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
ObjectOutputStream objectOutput = new ObjectOutputStream(byteOutput);
Handle handle = child.getHandle();
objectOutput.writeObject(handle);
byte[] bytes = byteOutput.toByteArray();
int hashCode = 0;
for(int i = 0; i < bytes.length; i++) {
// be careful to rotate the hashCode around, so you get a full
// 32 bits of hashing, not just 8 bits.
hashCode =
(hashCode << 8) & 0xffffff00 |
(hashCode >> 24) & 0x000000ff;
hashCode += bytes[i];
}
Obviously, this code is not for the feint of heart, and it is not yet
even complete (it does not handle exceptions).
Furthermore, I am not totally sure this code will work portably, in
that I don't know that an EJBObject reference's handle is guaranteed
to serialize to same bytes every time. In fact, I would guess for a
lot of servers, it might not.
In summary, I think it is pretty much infeasible to implement the hashCode
method for this primary key class. Which leads me to one of the following
conclusions:
1) The EJB spec. should remove the requirement that a primary key class implement
hashCode and equals. (I personally see no good reason to need these methods, as
it encourages a very non-OO way of interacting with entity beans, but that is another
discussion).
2) The EJB spec. should add a requirement that every EJBObject
implement hashCode and equals method. Then, I could easily implement
the PK methods as:
public int hashCode() {
return index + child.hashCode();
}
public boolean equals(Object object) {
if(!(object instanceof ToyPK)) {
return false;
}
ToyPK that = (ToyPK) object;
return this.index == that.index && this.child.equals(that.child);
}
I apologize if the EJB 2.0 spec has already addressed this, and I just
missed it.
-jkw
Jim Archer wrote:
>
> Hi All...
>
> I'm trying to understand how references to entity beans work in EJB 1.1
> servers when using CMP. I'm sorry this is kind of convoluted, but I have
> been through a few books and and web sites and have not figured out how
> this works.
>
> I'm interested in modeling my world using entity beans that have reference
> to other entity beans, like I would in any other OO system. I don't
> understand how all this works in EJB when I am using CMP.
>
> If I have an eb that represents a child, and another eb that represents an
> address, I would like to put a reference to an Address eb in my Child eb
> and have CMP handle persisting both of the beans. If I do that will the
> address in some way be persisted with the Child eb (maybe by saving its
> primary key)? When I later do a find that loads the Child eb from the
> database will the Address eb be loaded as well?
>
> Now, what if I want to model the Child having some not fixed number of
> toys? I would like for the Child eb to have an instance of a Collection of
> Toy entity beans. Can I do this such that when the Child is persisted that
> all the toys get persisted as well?
>
> Thanks very much!
>
> 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".
===========================================================================
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".