11 Replies Latest reply on Sep 12, 2003 12:12 PM by ibruell

    Argh! Frustrated with CMR!

    dhartford

      Hey all,
      If you have a 1-N relationship between, say, an Organization bean that has many Gangsters. And, let's say you want to return a collection of value-objects of the Gangsters for use in Web/Thick-Client/what-have-you.

      I would think you would simply have something like:
      /*****************
      *CMR Relational Methods
      *****************/
      /**
      * @ejb.interface-method
      * view-type="local"
      *
      * @ejb.relation
      * name="Organization-Gangsters"
      * role-name="one-organization-has-many-gangsters"
      * cascade-delete="no"
      *
      * @ejb.value-object
      * aggregate = "com.mycompany.entity.interfaces.GangsterValue"
      * aggregate-name = "AllGangsters"
      * match = "*"
      * members = "com.mycompany.entity.interfaces.GangsterLocal"
      * members-name = "Gangsters"
      * relation = "external"
      * type = "Collection"
      * exclude="true"
      *
      * @jboss.relation-mapping style="foreign-key"
      *
      */
      public abstract java.util.Collection getGangsters();


      And then call Organization.getGansters(). But nooooo...you get the stupid-ass 'CMR can only be used in the transaction in which it was created' BS. Hello, how the heck are you supposed to do this then??

      p.s.
      Forgive my language and frustration, but it has been couple of weeks and waaay to much research and testing on this. And yes, I did read that the specs say something about CMR 'suppose' to act this way, well what about the real world damnit?

        • 1. Re: Argh! Frustrated with CMR!
          jamarkha

          The getGangsters() method you want to call to get value objects won't be returning value objects. The Collection you get will be of the local Gangster object, hence, the CMR warning.

          If you want to have a Collection of value objects, you'll have to iterate over the Collection of Gangster local objects, creating another Collection of Gangster value objects.

          • 2. Re: Argh! Frustrated with CMR!
            dhartford

            I have also tested OrganizationValue.getAllGangsterss() with the same result and the same silly error. This was suppose to handle returning Value-Objects.

            (Xdoclet will add an 's' to the end of the aggregate-name when creating the associated method).


            I have also tested iterating over the Collection of GangsterLocal objects and populating a collection with GangsterValue objects. You still get that silly error (unless you use UserTransaction which is very poor solution for this).

            Do you have an example that works?

            • 3. Re: Argh! Frustrated with CMR!
              dhartford

              Full Code:

              *****Organization Bean*****
              * @ejb:bean
              * type="CMP"
              * cmp-version="2.x"
              * name="Organization"
              * local-jndi-name="com.mycompany.Organization"
              * jndi-name="com.mycompany.OrganizationHome"
              * view-type="local"
              * primkey-field="mypk"
              * transaction-type="Container"
              * use-soft-locking = "true"
              *
              * @ejb.persistence table-name="Organization"
              *
              * @jboss:relation-table
              * table-name="Organization"
              * row-locking="false"
              *
              * @ejb:transaction
              * type="Required"
              * @ejb:util
              * generate="physical"
              *
              * @ejb.value-object
              * name="Organization"
              * match="*"
              *
              * @jboss:persistence
              * row-locking="false"
              * list-cache-max=50
              * fetch-size=50
              * create-table="true"
              * remove-table="false"
              * read-only="false"
              *
              * @jboss.method-attributes
              * pattern="get*"
              * read-only=true
              *
              * @jboss:tuned-updates "true"
              *
              * @jboss:container-configuration
              * name="Standard CMP 2.x EntityBean"
              *
              * @ejb:finder
              * signature="java.util.Collection findAll()"
              * result-type-mapping="Local"
              * method-intf="LocalHome"
              * query="SELECT OBJECT(o) FROM Organization o"

              public abstract class OrganizationBean implements javax.ejb.EntityBean {

              //==========================================
              // Business methods
              //==========================================

              /**
              * @ejb.interface-method
              * @ejb.transaction
              * type="Supports"
              */
              public abstract WorkingDbValue getWorkingDbValue( );

              /**
              * @ejb.interface-method
              */
              public abstract void setWorkingDbValue( WorkingDbValue data );



              /*****************
              *CMR Relational Methods
              *****************/
              /**
              * @ejb.interface-method
              * view-type="local"
              *
              * @ejb.relation
              * name="Organization-Gangsters"
              * role-name="one-organization-has-many-gangsters"
              * cascade-delete="no"
              *
              * @ejb.value-object
              * aggregate = "com.mycompany.GangsterValue"
              * aggregate-name = "AllGangsters"
              * match = "*"
              * members = "com.mycompany.GangsterLocal"
              * members-name = "Gangsters"
              * relation = "external"
              * type = "Collection"
              * exclude="true"
              *
              * @jboss.relation-mapping style="foreign-key"
              *
              */
              public abstract java.util.Collection getGangsters();

              /**
              * @ejb:interface-method view-type="local"
              */
              public abstract void setGangsters(java.util.Collection gangsters);





              *****Gangster Bean****
              * @ejb:bean
              * type="CMP"
              * cmp-version="2.x"
              * name="Gangster"
              * local-jndi-name="com.mycompany.GangsterLocalHome"
              * view-type="local"
              * primkey-field="mypk_incremented"
              * transaction-type="Container"
              * use-soft-locking = "true"
              *
              * @ejb:transaction
              * type="Required"
              * @ejb:util
              * generate="physical"
              *
              * @ejb.value-object
              * name="Gangster"
              * match="*"
              *
              * @ejb.persistence table-name="Gangster"
              *
              * @jboss:relation-table
              * table-name="Gangster"
              * row-locking="false"
              *
              * @jboss.method-attributes
              * pattern="get*"
              * read-only=true
              *
              * @jboss:persistence
              * row-locking="false"
              * list-cache-max=50
              * fetch-size=50
              * create-table="true"
              * remove-table="false"
              * read-only="false"
              *
              * @jboss:tuned-updates "true"
              *
              * @jboss:container-configuration
              * name="Standard CMP 2.x EntityBean "
              *
              * @ejb:finder
              * signature="java.util.Collection findAll()"
              * result-type-mapping="Local"
              * method-intf="LocalHome"
              * query="SELECT OBJECT(o) FROM Gangster o"
              *
              public abstract class GangsterBean implements javax.ejb.EntityBean {

              //==========================================
              // Business methods
              //==========================================

              /**
              * @ejb.interface-method
              * @ejb.transaction
              * type="Supports"
              */
              public abstract GangsterValue getGangsterValue( );

              /**
              * @ejb.interface-method
              */
              public abstract void setGangsterValue( GangsterValue data );

              /*****************
              *CMR Relational Methods
              *****************/
              /**
              * @ejb.interface-method
              * view-type="local"
              *
              * @ejb.relation
              * name="Organization-Gangsters"
              * role-name="many-Gangsters-has-one-Organization"
              * cascade-delete = "yes"
              *
              * @jboss.relation-mapping style = "foreign-key"
              *
              * @jboss:relation
              * fk-constraint="false"
              * related-pk-field="mypk"
              * fk-column="mypk"
              * @weblogic.column-map
              * key-column="mypk"
              * foreign-key-column="mypk"
              */
              public abstract OrganizationLocal getOrganization();

              /**
              * @ejb:interface-method view-type="local"
              */
              public abstract void setOrganization(OrganizationLocal organization);

              • 4. Re: Argh! Frustrated with CMR!
                dhartford

                oops...

                Replace WorkingDbValue with OrganizationValue, mis-transcribed =P

                • 5. Re: Argh! Frustrated with CMR!

                  Where is the code which created the Collection of ValueObjects ? It must be run in a SessionBean with transaction-type="Required".

                  • 6. Re: Argh! Frustrated with CMR!
                    dhartford

                    in the EJB, set exclude="false"

                    Session Bean Method:
                    /**
                    * @ejb:interface-method view-type="both"
                    * @ejb.transaction
                    * type="Required"
                    **/
                    public OrganizationValue myOrganizationVO(java.lang.String mypk){
                    try{
                    OrganizationLocalHome home = OrganizationUtil.getLocalHome();
                    OrganizationValue test = home.findByPrimaryKey(mypk).getOrganizationValue();

                    return test;

                    }catch (Exception ex){
                    throw new EJBException(ex.getMessage());
                    }
                    }

                    Pass through Struts Action and Form (common, not going to post). Then call from Struts jsp page:

                    <strutslogic:iterate name="organizationform" property="organization.gangsters" id="og">
                    <strutsbean:write name="og" property="mypk" />
                    <strutsbean:write name="og" property="mypk_increment" />
                    </strutslogic:iterate>

                    also tried:
                    <strutslogic:iterate name="organizationform" property="organization.allGangsterss" id="og">
                    <strutsbean:write name="og" property="mypk" />
                    <strutsbean:write name="og" property="mypk_increment" />
                    </strutslogic:iterate>


                    The allGangsterss is created as an aggregate from Xdoclet. It returns a com.mycompany.GangsterValue[] within the OrganizationValue object.

                    These all return the 'CMR collection may only be used within the transction in which it was created' in Jboss 3.2.0 and 3.2.2RC3.

                    • 7. Re: Argh! Frustrated with CMR!

                      You cannot transport a LocalObject to the client side. As said earlier, you have to Convert the Collection of LocalObjects into a Collection of ValueObjects or something else within the SessionBean.

                      Something like:

                      /**
                      * @ejb:interface-method view-type="both"
                      * @ejb.transaction
                      * type="Required"
                      **/
                      public Collection getAllGangster()
                      {
                      ArrayList al = new ArrayList();
                      try {
                      GangsterLocalHome home = GangsterUtil.getLocalHome();
                      Collection entities = home.findAllGangster();
                      Iterator iter = entities.iterator();
                      while(iter.hasNext())
                      {
                      al.add(((Gangster)iter.next).getGangsterValue());
                      }
                      } catch(Exception e) {}
                      return al;
                      }

                      • 8. Re: Argh! Frustrated with CMR!
                        dhartford

                        Actually, you can transport a LocalObject to the client side if the WAR is within the same VM, which is the case, but that is beside the point. One of the method calls above does return an com.mycompany.GangstersValue[] which is NOT local.

                        And I do have another method that I used for testing exactly like you have and that also returns the 'CMR collection' error.

                        • 9. Re: Argh! Frustrated with CMR!

                          FYI, you really should stay away from CMR because of the entity locks in causes.

                          At worst, onlyl use CMR for composition relationships, never aggregation.

                          • 10. Re: Argh! Frustrated with CMR!

                            O.K. at this point you are right, but you need the transaction in which you receive the collection and retrieve the valueobject from the entities.

                            • 11. Re: Argh! Frustrated with CMR!

                              O.K. at this point you are right, but you need the transaction in which you receive the collection and retrieve the valueobject from the entities.