Hi guys

The last few days I was playing around with Ricards doclet stuff.

I think we should create a little framework for it to make it more
powerful. (I believe the idea of using doclets is great, because it
gives us an type safe object model with additional meta data.)

As additional capabilities I could imagine:  
- smart PKGeneration - if PK is simple Java type (eg Integer),
  we dont need a extra PK  
- SourcefileValidator - check the given files before generating
  anything
- TestClientGenerator - maby a little complex but should be possible
  for simple test runs (create, find, set/get, ...)

With view of CMP2.0 I tried to automatically generate the
<relationships> tags of the ejb-jar.xml file. Therefor I added some
doclet tags and wrote a class RelationAssembler that tries to figure
out the relations between the given classes. For easy use I put it into
the same package I hope that is OK.

You only have to put the source file to the other files of the package
and insert into EJBDoclet in the ejbxml-method between the
</assembly-descriptor> and </ejb-jar> lines (~line 287) the following
code line:
new RelationAssembler (root, System.out).dump (out, 3);

and recompile it...

Any comments are welcome

Bye Daniel

---8<-- The Java Source Code ------------------------------------------

package com.dreambean.ejbdoclet;

import java.io.*;
import java.util.*;
import com.sun.javadoc.*;

/**
    Used on a collection of CMP bean source files following the tag convention, this 
tool
    generates <code>RelationAssembler.Relation</code> objects for each relation 
between the 
    given objects. <br>
    The Getter and Setter (actually only the Getters) for the Container Managed 
Relationship
    fields must use the following tags:
    <dl>
    <dt><code><b>@cmr-field</b></code></dt><dd>for marking this method as a getter or 
setter for a
    CMR field 
    </dd><dt><code><b>@cmr-related-name</b></code></dt><dd> if the 
returntype/parameter of this method
    is a Collection, this tag needs to be set to specify the type (classname) of 
    collected (related) objects.
    </dd><dt><code><b>@cmr-related-field-name</b></code></dt><dd>in case of 
bidirectional navigation
    the name of the corresponding field in the related class must be given here
    </dd>
    <dl>

    used tags:
        entity-cmp,
        dependent-object,
        cmr-field,
        cmr-related-name,
        cmr-related-field-name,
        dependent-name,
        ejb-name,

    @author <A href="mailto:[EMAIL PROTECTED]">Daniel Schulze</A>
    @version 0.1
*/
public class RelationAssembler
{
    // Constants -----------------------------------------------------
     
    // Attributes ----------------------------------------------------
    RootDoc root;
    PrintStream log;

    Hashtable relations;

    // Constructors --------------------------------------------------

    /** Creates a new RelationAssembler object 
    * @param _root the RootDoc of the Doclet run
    * @param _log a PrintStream for logging */
    public RelationAssembler (RootDoc _root, PrintStream _log)
    {
        root = _root;
        log = _log;
        
        start ();
    }
    

    // public --------------------------------------------------------

    /** starts assembling the relationships of the given repository */
    public void start ()
    {
        relations = new Hashtable ();

        Iterator entities = getCMPEntities ();
        while (entities.hasNext ())
            processClass ((ClassDoc) entities.next ());

        Iterator dependents = getDependentObjects ();
        while (dependents.hasNext ())
            processClass ((ClassDoc) dependents.next ());
    }

    /** Dumps the generated Relations into the given PrintStream with the given indent 
depth
    * @param _out PrintStream to dump into (the ejb-jar.xml file)
    * @param _indent the indent depth */
    public void dump (PrintStream _out, int _indent)
    {
        String i = "";
        while (_indent-- > 0) i += " ";
        
        _out.println(i+"<relationships>");
        Iterator it = getRelations ();
        while (it.hasNext ())
        {
          Relation r = (Relation)it.next ();
  
          _out.println(i+i+"<ejb-relation>");
          _out.println(i+i+i+"<ejb-relation-name>"+r.name+"</ejb-relation-name>");
  
          _out.println(i+i+i+"<ejb-relationship-role>");
          
_out.println(i+i+i+i+"<ejb-relationship-role-name>"+r.role1.name+"</ejb-relationship-role-name>");
          
_out.println(i+i+i+i+"<multiplicity>"+r.role1.multiplicity+"</multiplicity>");
          _out.println(i+i+i+i+"<role-source>");
          
_out.println(i+i+i+i+i+"<"+r.role1.sourceType+">"+r.role1.sourceName+"</"+r.role1.sourceType+">");
          _out.println(i+i+i+i+"</role-source>"); 
          if (!"".equals (r.role1.cmrFieldName)) 
          {
          _out.println(i+i+i+i+"<cmr-field>");
          
_out.println(i+i+i+i+i+"<cmr-field-name>"+r.role1.cmrFieldName+"<cmr-field-name>");
          if (!"".equals (r.role1.cmrFieldType))
          
_out.println(i+i+i+i+i+"<cmr-field-type>"+r.role1.cmrFieldType+"<cmr-field-type>");
          _out.println(i+i+i+i+"</cmr-field>"); 
          }
          _out.println(i+i+i+"</ejb-relationship-role>");
  
          _out.println(i+i+i+"<ejb-relationship-role>");
          
_out.println(i+i+i+i+"<ejb-relationship-role-name>"+r.role2.name+"</ejb-relationship-role-name>");
          
_out.println(i+i+i+i+"<multiplicity>"+r.role2.multiplicity+"</multiplicity>");
          _out.println(i+i+i+i+"<role-source>");
          
_out.println(i+i+i+i+i+"<"+r.role2.sourceType+">"+r.role2.sourceName+"</"+r.role2.sourceType+">");
          _out.println(i+i+i+i+"</role-source>"); 
          if (!"".equals (r.role2.cmrFieldName)) 
          {
          _out.println(i+i+i+i+"<cmr-field>");
          
_out.println(i+i+i+i+i+"<cmr-field-name>"+r.role2.cmrFieldName+"<cmr-field-name>");
          if (!"".equals (r.role2.cmrFieldType))
          
_out.println(i+i+i+i+i+"<cmr-field-type>"+r.role2.cmrFieldType+"<cmr-field-type>");
          _out.println(i+i+i+i+"</cmr-field>"); 
          }
          _out.println(i+i+i+"</ejb-relationship-role>");
          
          _out.println(i+i+"</ejb-relation>");
        }       
        _out.println(i+"</relationships>");
    }
    


    /** Returns the created Relation objects */
    public Iterator getRelations ()
    {
        return relations.values ().iterator ();
    }

    
    // protected -----------------------------------------------------


    /** Processes the given class.
    * @param the class to process */
    protected void processClass (ClassDoc _clazz)
    {
        ClassDoc current = _clazz;
        Iterator cmrFields = getCMRFields (current);
        while (cmrFields.hasNext ())
        {
                MethodDoc field = (MethodDoc) cmrFields.next ();
            try {
                log.print ("  processing "+current.name ()+"."+getFieldName 
(field)+"...");

                // if we dont find the related class
                // it must be a relationship with a bean outside
                // so we cant assemble it
                // if the bean shall be included to the jar, then the
                // develeoper must add it to the scaned classes...
                ClassDoc related = getRelatedClass (field);

                // names for this relation
                String name1 = current.name () + "." + getFieldName (field);
                String name2 = related.name ();                 
                Relation relation = new Relation ();
                
                // check from this fields view
                String rt = field.returnType ().qualifiedTypeName ();
                if (rt.equals ("java.util.Collection") ||
                    rt.equals ("java.util.Set"))
                {
                        // to many
                        relation.role2.multiplicity = "many";
                        relation.role1.cmrFieldType = rt;
                } else
                {
                        // to one
                        relation.role2.multiplicity = "one";
                        relation.role1.cmrFieldType = "";
                }
                        relation.role1.cmrFieldName = getFieldName (field);

                String rf = getRelatedFieldName (field);
                if (!rf.equals (""))
                {
                        // bidirectional relationship...
                        
                        MethodDoc relField = findCMRField (related, rf);
                    name2 += ("." + getFieldName (relField));
                    // check from the related fields view
                    rt = relField.returnType ().qualifiedTypeName ();
                        if (rt.equals ("java.util.Collection") ||
                            rt.equals ("java.util.Set"))
                        {
                                // to many
                                relation.role1.multiplicity = "many";
                                relation.role2.cmrFieldType = rt;
                        } else
                        {
                                // to one
                                relation.role1.multiplicity = "one";
                                relation.role2.cmrFieldType = "";
                        }
                        relation.role2.cmrFieldName = getFieldName (relField);
                } else
                {
                        // unidirectional relationship...
                    // check from the related fields view - must be "one"
                        relation.role1.multiplicity = "one";
                        relation.role2.cmrFieldType = "";
                        relation.role2.cmrFieldName = "";
                }
                
                if (relations.get (name2+"-"+name1) == null)
                {
                        // relation does not jet exist...
                    relation.name = name1 + "-" + name2;

                    // create role names...
                    if (relation.role1.multiplicity.equals ("one"))
                    {
                        if (relation.role2.multiplicity.equals ("one"))
                        {
                            // one2one
                                relation.role1.name = current.name () + " has one " + 
related.name ();
                                relation.role2.name = related.name () + " belongs to 
one " + current.name ();
                        } else
                        {
                            // one2many
                                relation.role1.name = current.name () + " has many " + 
related.name () + "s";
                                relation.role2.name = related.name () + " belongs to 
one " + current.name ();
                        }                               
                    } else
                    {
                        if (relation.role2.multiplicity.equals ("one"))
                        {
                            // many2one
                                relation.role1.name = current.name () + " belongs to 
one " + related.name ();
                                relation.role2.name = related.name () + " has many " + 
current.name () + "s";
                        } else
                        {
                            // many2many
                                relation.role1.name = current.name () + " has many " + 
related.name () + "s";
                                relation.role2.name = related.name () + " has many " + 
current.name () + "s";
                        }                               
                    }
                    
                    // create source entries
                    relation.role1.sourceType = isCMPEntity 
(current)?"ejb-name":(isDependentObject (current)?"dependent-name":"???");
                    relation.role1.sourceName = getEJBName (current);

                    relation.role2.sourceType = isCMPEntity 
(related)?"ejb-name":(isDependentObject (related)?"dependent-name":"???");
                    relation.role2.sourceName = getEJBName (related);
                        
                    // ...and create it.
                        relations.put (relation.name, relation);      
                        log.println ("relationship \""+relation.name+"\" added.");
                        
                } else
                        log.println ("relationship \""+name2+"-"+name1+"\" already 
exists.");
                
                
            } catch (Exception _e) {
                log.println ("ERROR: "+_e.getMessage ()+" skip");
            }
        }
    }        


    /** Finds the named class in the repository.
    * @param _className the name of the class to look for
    * @return a ClassDoc object for the class
    * @throws Exception if this class wasnt found     */
    protected ClassDoc getClassForName (String _className) throws Exception
    {
        ClassDoc result = root.classNamed (_className);
        if (result == null)
           throw new Exception ("Class \""+_className+"\" not in repository!");
        return result;
    }
    
    /** Returns the fields name from a given getter or setter method.
    * @param _m a getter or setter method for a field
    * @return the name of the field. (methodname minus the first 3 letters,
    * fist letter moved to lowercase)     */
    protected String getFieldName (MethodDoc _m)
    {
        String uppercase = _m.name ().substring (3);
        // return uppercase;

        char[] chars = uppercase.toCharArray ();
        chars[0] = Character.toLowerCase (chars[0]);
        return new String (chars);
    }

    /** Returns all classes with the <code><b>stateless-session</b></code> tag
    * @return Iterator over all stateless session classes */
    protected Iterator getStatelessSessions ()
    {
        ClassDoc[] c = root.classes (); 
        Vector result = new Vector ();
        for (int i = 0, l = c.length; i < l; ++i)
        {
                if (c[i].tags ("stateless-session").length > 0)
                    result.add (c[i]);
        }
        return result.iterator ();
    }
    
    /** Returns all classes with the <code><b>stateful-session</b></code> tag
    * @return Iterator over all stateful session classes */
    protected Iterator getStatefulSessions ()
    {
        ClassDoc[] c = root.classes (); 
        Vector result = new Vector ();
        for (int i = 0, l = c.length; i < l; ++i)
        {
                if (c[i].tags ("stateful-session").length > 0)
                    result.add (c[i]);
        }
        return result.iterator ();
    }
    
    /** Returns all classes with the <code><b>entity-cmp</b></code> tag
    * @return Iterator over all CMP entities classes */
    protected Iterator getCMPEntities ()
    {
        ClassDoc[] c = root.classes (); 
        Vector result = new Vector ();
        for (int i = 0, l = c.length; i < l; ++i)
        {
                if (c[i].tags ("entity-cmp").length > 0)
                    result.add (c[i]);
        }
        return result.iterator ();
    }
    
    /** Returns all classes with the <code><b>dependent-object</b></code> tag
    * @return Iterator over all dependent object classes */
    protected Iterator getDependentObjects ()
    {
        ClassDoc[] c = root.classes (); 
        Vector result = new Vector ();
        for (int i = 0, l = c.length; i < l; ++i)
        {
                if (c[i].tags ("dependent-object").length > 0)
                    result.add (c[i]);
        }
        return result.iterator ();
    }



    /** Returns all getter methods with the <code><b>cmp-field</b></code> tag
    * @param _clazz the class to inspect
    * @return Iterator over all CMP fields of the give class */
    protected Iterator getCMPFields (ClassDoc _clazz)
    {
        MethodDoc[] m = _clazz.methods (); 
        Vector result = new Vector ();
        for (int i = 0, l = m.length; i < l; ++i)
        {
                if (m[i].tags ("cmp-field").length > 0 &&
                    m[i].name ().startsWith ("get"))
                    result.add (m[i]);
        }
        return result.iterator ();
    }
    
    /** Returns all getter methods with the <code><b>cmr-field</b></code> tag
    * @param _clazz the class to inspect
    * @return Iterator over all CMR fields of the give class */
    protected Iterator getCMRFields (ClassDoc _clazz)
    {
        MethodDoc[] m = _clazz.methods (); 
        Vector result = new Vector ();
        for (int i = 0, l = m.length; i < l; ++i)
        {
                if (m[i].tags ("cmr-field").length > 0 &&
                    m[i].name ().startsWith ("get"))
                    result.add (m[i]);
        }
        return result.iterator ();
    }
    
    /** Returns all create methods
    * @param _clazz the class to inspect
    * @return Iterator over all create methods of the give class */
    protected Iterator getCreateMethods (ClassDoc _clazz)
    {
        MethodDoc[] m = _clazz.methods (); 
        Vector result = new Vector ();
        for (int i = 0, l = m.length; i < l; ++i)
        {
                if (m[i].name ().startsWith ("ejbCreate"))
                    result.add (m[i]);
        }
        return result.iterator ();
    }
    
    /** Returns all home methods
    * @param _clazz the class to inspect
    * @return Iterator over all home methods of the give class */
    protected Iterator getHomeMethods (ClassDoc _clazz)
    {
        MethodDoc[] m = _clazz.methods (); 
        Vector result = new Vector ();
        for (int i = 0, l = m.length; i < l; ++i)
        {
                if (m[i].name ().startsWith ("ejbHome"))
                    result.add (m[i]);
        }
        return result.iterator ();
    }
   
   
    /** Returns whether the value of the <code><b>ejb-name</b></code> or the
    * <code><b>dependent-name</b></code> tag of the given class. Or an empty String 
    * if none is set.
    * @param _clazz the class to inspect
    * @return ejb-name or dependent-name or empty string */
    protected String getEJBName (ClassDoc _c)
    {
                if (_c.tags ("ejb-name").length > 0)
                    return _c.tags ("ejb-name")[0].text ();
                    
                if (_c.tags ("dependent-name").length > 0)
                    return _c.tags ("dependent-name")[0].text ();
                    
                return "";
        }
        
    
    /** Returns true if the<code><b>entity-cmp</b></code> tag is set
    * @param _clazz the class to inspect
    * @return true, if entity-cmp tag is set */
    protected boolean isCMPEntity (ClassDoc _c)
    {
        return (_c.tags ("entity-cmp").length > 0);
    }
    
    
    /** Returns true if the <code><b>dependent-object</b></code> tag is set
    * @param _clazz the class to inspect
    * @return true, if dependent-object tag is set */
    protected boolean isDependentObject (ClassDoc _c)
    {
        return (_c.tags ("dependent-object").length > 0);
    }
    
    /** Returns the name of the PrimaryKey class for the given class.
    * @param class to inspect
    * @return the PrimaryKeys class name or empty string if none */
    protected String getPKName (ClassDoc _clazz) 
    {
        String result = "";
        Iterator i = getCreateMethods (_clazz);
        if (i.hasNext ()) 
           result = ((MethodDoc)i.next ()).returnType ().qualifiedTypeName ();
        return result;
    }
    
    /** Returns the getDATA method if defined else null
    * @param class to inspect
    * @return the MethodDoc object for the getDATA () method */
    protected MethodDoc getDataMethod (ClassDoc _clazz) 
    {
        MethodDoc[] m = _clazz.methods (); 
        for (int i = 0, l = m.length; i < l; ++i)
        {
                if (m[i].tags ("data-method").length > 0 &&
                    m[i].name ().startsWith ("get"))
                return m[i];
        }
        return null;
    }




    /** Assumed that the given method is a get_cmr-field_ method, this method tries to
    *   figure out the related class of this field. <br>
    *   If the returntype of the method is a collection, the 
<code><b>cmr-related-name</b></code>
    *   tag is looked for. The found class must have an <code><b>ejb-name</b></code> 
tag
    *   to be given back as result.
    * @param _m the getCMRFIELD () method
    * @return the ClassDoc of the related ejb object
    * @throws Exception if no fitting class was found */
    protected ClassDoc getRelatedClass (MethodDoc _m)  throws Exception
    {
        String returntype = _m.returnType ().qualifiedTypeName ();
        
        if (returntype.equals ("java.util.Collection") ||
            returntype.equals ("java.util.Set"))
        {
                // Oops! then we must assume we have a cmr-related-name tag...
                if (_m.tags ("cmr-related-name").length > 0)
                {
                        returntype = _m.tags ("cmr-related-name")[0].text ();
            }
            else
               returntype = "";
        } 
        
        ClassDoc result = null;
        try { result = root.classNamed (returntype);} catch (Exception _e) {}
        if (result != null && !getEJBName (result).equals (""))
            return result;      
            
                // maby it is an RemoteInterface that not yet exists?
        try { result = root.classNamed (returntype+"Bean");} catch (Exception _e) {}
        if (result != null && !getEJBName (result).equals (""))
            return result;      
        
        throw new Exception ("related class \""+returntype+"\" not specified or 
found!");
    }
        
    
    /** Returns the fieldname of the related field if this is a bidirectional 
relationship.
    *   If no <code><b>cmr-related-field-name</b></code> tag is set, it is assumed 
that this 
    *   is an unidirectional relationship.
    * @param the cmr-field mehtod to inspect
    * @return the value of the cmr-related-field-name tag or empty string*/
    protected String getRelatedFieldName (MethodDoc _m)
    {
        String result = "";
                if (_m.tags ("cmr-related-field-name").length > 0)
                {
                        result = _m.tags ("cmr-related-field-name")[0].text ();
            }
        
        return result; 
    }
        
    
    /** Tries to find the getCMR-FIELD () method of the given class with the given
    *   field name.
    * @param _clazz the class to inspect
    * @param _fieldName the name of the field to look for
    * @return the MethodDoc object of the getCMR-FIELD () method
    * @throws Exception if no such field were found */
    protected MethodDoc findCMRField (ClassDoc _clazz, String _fieldName) throws 
Exception
    {
        Iterator i = getCMRFields (_clazz);
        while (i.hasNext ())
        {
                MethodDoc m = (MethodDoc) i.next ();
                String fieldName = getFieldName (m);
                if (_fieldName.equalsIgnoreCase (fieldName))
                    return m;
        }
        throw new Exception ("No field with name \""+_fieldName+"\" found!");
    }
    

    // private -------------------------------------------------------

    

    // InnerClass ----------------------------------------------------

    class Relation
    {
        Relation ()
        {
                role1 = new Role ();
                role2 = new Role ();
        }
        
        public String name;    //
        public Role   role1;   //
        public Role   role2;   //
        
        
    }

    class Role
    {
        public String name;
        public String multiplicity;    //
        public String sourceType;
        public String sourceName;
        public String cmrFieldName;    //
        public String cmrFieldType;    //
    }

}


---8<-- The Generated XML File ----------------------------------------

<ejb-jar>
   <description>Test</description>
   <display-name>Test</display-name>
   <enterprise-beans>
      <entity>
         <description></description>
         <ejb-name>Order</ejb-name>
         <home>cmp20.OrderHome</home>
         <remote>cmp20.Order</remote>
         <ejb-class>cmp20.OrderCMP</ejb-class>
         <persistence-type>Container</persistence-type>
         <prim-key-class>cmp20.OrderPK</prim-key-class>
         <reentrant>True</reentrant>
         <cmp-field>
            <description></description>
            <field-name>Id</field-name>
         </cmp-field>
         <cmp-field>
            <description></description>
            <field-name>Date</field-name>
         </cmp-field>
         <ejb-ref>
            <ejb-ref-name>ejb/Customer</ejb-ref-name>
            <ejb-ref-type>Entity</ejb-ref-type>
            <home>cmp20.CustomerHome</home>
            <remote>cmp20.Customer</remote>
            <ejb-link>Customer</ejb-link>
         </ejb-ref>
         <ejb-ref>
            <ejb-ref-name>ejb/Product</ejb-ref-name>
            <ejb-ref-type>Entity</ejb-ref-type>
            <home>cmp20.ProductHome</home>
            <remote>cmp20.Product</remote>
            <ejb-link>Product</ejb-link>
         </ejb-ref>
      </entity>
      <entity>
         <description></description>
         <ejb-name>Product</ejb-name>
         <home>cmp20.ProductHome</home>
         <remote>cmp20.Product</remote>
         <ejb-class>cmp20.ProductCMP</ejb-class>
         <persistence-type>Container</persistence-type>
         <prim-key-class>cmp20.ProductPK</prim-key-class>
         <reentrant>True</reentrant>
         <cmp-field>
            <description></description>
            <field-name>SerialNumber</field-name>
         </cmp-field>
         <cmp-field>
            <description></description>
            <field-name>Name</field-name>
         </cmp-field>
         <cmp-field>
            <description></description>
            <field-name>Description</field-name>
         </cmp-field>
         <cmp-field>
            <description></description>
            <field-name>Price</field-name>
         </cmp-field>
      </entity>
      <entity>
         <description></description>
         <ejb-name>Customer</ejb-name>
         <home>cmp20.CustomerHome</home>
         <remote>cmp20.Customer</remote>
         <ejb-class>cmp20.CustomerCMP</ejb-class>
         <persistence-type>Container</persistence-type>
         <prim-key-class>cmp20.CustomerPK</prim-key-class>
         <reentrant>True</reentrant>
         <cmp-field>
            <description></description>
            <field-name>Id</field-name>
         </cmp-field>
         <cmp-field>
            <description></description>
            <field-name>Name</field-name>
         </cmp-field>
         <cmp-field>
            <description></description>
            <field-name>CredidCard</field-name>
         </cmp-field>
      </entity>
   </enterprise-beans>
   <assembly-descriptor>
   </assembly-descriptor>
   <relationships>
      <ejb-relation>
         <ejb-relation-name>OrderBean.orderLines-OrderLine.order</ejb-relation-name>
         <ejb-relationship-role>
            <ejb-relationship-role-name>OrderBean has many 
OrderLines</ejb-relationship-role-name>
            <multiplicity>one</multiplicity>
            <role-source>
               <ejb-name>Order</ejb-name>
            </role-source>
            <cmr-field>
               <cmr-field-name>orderLines<cmr-field-name>
               <cmr-field-type>java.util.Collection<cmr-field-type>
            </cmr-field>
         </ejb-relationship-role>
         <ejb-relationship-role>
            <ejb-relationship-role-name>OrderLine belongs to one 
OrderBean</ejb-relationship-role-name>
            <multiplicity>many</multiplicity>
            <role-source>
               <dependent-name>OrderLine</dependent-name>
            </role-source>
            <cmr-field>
               <cmr-field-name>order<cmr-field-name>
            </cmr-field>
         </ejb-relationship-role>
      </ejb-relation>
      <ejb-relation>
         <ejb-relation-name>OrderBean.customer-CustomerBean.orders</ejb-relation-name>
         <ejb-relationship-role>
            <ejb-relationship-role-name>OrderBean belongs to one 
CustomerBean</ejb-relationship-role-name>
            <multiplicity>many</multiplicity>
            <role-source>
               <ejb-name>Order</ejb-name>
            </role-source>
            <cmr-field>
               <cmr-field-name>customer<cmr-field-name>
            </cmr-field>
         </ejb-relationship-role>
         <ejb-relationship-role>
            <ejb-relationship-role-name>CustomerBean has many 
OrderBeans</ejb-relationship-role-name>
            <multiplicity>one</multiplicity>
            <role-source>
               <ejb-name>Customer</ejb-name>
            </role-source>
            <cmr-field>
               <cmr-field-name>orders<cmr-field-name>
               <cmr-field-type>java.util.Collection<cmr-field-type>
            </cmr-field>
         </ejb-relationship-role>
      </ejb-relation>
      <ejb-relation>
         <ejb-relation-name>CustomerBean.deliveryAddress-Address</ejb-relation-name>
         <ejb-relationship-role>
            <ejb-relationship-role-name>CustomerBean has one 
Address</ejb-relationship-role-name>
            <multiplicity>one</multiplicity>
            <role-source>
               <ejb-name>Customer</ejb-name>
            </role-source>
            <cmr-field>
               <cmr-field-name>deliveryAddress<cmr-field-name>
            </cmr-field>
         </ejb-relationship-role>
         <ejb-relationship-role>
            <ejb-relationship-role-name>Address belongs to one 
CustomerBean</ejb-relationship-role-name>
            <multiplicity>one</multiplicity>
            <role-source>
               <dependent-name>Address</dependent-name>
            </role-source>
         </ejb-relationship-role>
      </ejb-relation>
      <ejb-relation>
         <ejb-relation-name>OrderLine.product-ProductBean</ejb-relation-name>
         <ejb-relationship-role>
            <ejb-relationship-role-name>OrderLine has one 
ProductBean</ejb-relationship-role-name>
            <multiplicity>one</multiplicity>
            <role-source>
               <dependent-name>OrderLine</dependent-name>
            </role-source>
            <cmr-field>
               <cmr-field-name>product<cmr-field-name>
            </cmr-field>
         </ejb-relationship-role>
         <ejb-relationship-role>
            <ejb-relationship-role-name>ProductBean belongs to one 
OrderLine</ejb-relationship-role-name>
            <multiplicity>one</multiplicity>
            <role-source>
               <ejb-name>Product</ejb-name>
            </role-source>
         </ejb-relationship-role>
      </ejb-relation>
      <ejb-relation>
         <ejb-relation-name>CustomerBean.billingAddress-Address</ejb-relation-name>
         <ejb-relationship-role>
            <ejb-relationship-role-name>CustomerBean has one 
Address</ejb-relationship-role-name>
            <multiplicity>one</multiplicity>
            <role-source>
               <ejb-name>Customer</ejb-name>
            </role-source>
            <cmr-field>
               <cmr-field-name>billingAddress<cmr-field-name>
            </cmr-field>
         </ejb-relationship-role>
         <ejb-relationship-role>
            <ejb-relationship-role-name>Address belongs to one 
CustomerBean</ejb-relationship-role-name>
            <multiplicity>one</multiplicity>
            <role-source>
               <dependent-name>Address</dependent-name>
            </role-source>
         </ejb-relationship-role>
      </ejb-relation>
   </relationships>
</ejb-jar>


--
--------------------------------------------------------------
To subscribe:        [EMAIL PROTECTED]
To unsubscribe:      [EMAIL PROTECTED]
Problems?:           [EMAIL PROTECTED]

Reply via email to