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".

Reply via email to