You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by da...@apache.org on 2006/12/13 05:08:40 UTC

svn commit: r486483 [1/2] - in /incubator/openejb/trunk/openejb3: container/openejb-core/src/main/java/org/apache/openejb/core/cmp/ container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/ itests/openejb-itests-beans/src/main/java/org/apac...

Author: dain
Date: Tue Dec 12 20:08:39 2006
New Revision: 486483

URL: http://svn.apache.org/viewvc?view=rev&rev=486483
Log:
Basic one-to-many work

Added:
    incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmpWrapper.java
    incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmpWrapperFactory.java
    incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetomany/ABean_JPA.java
    incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetomany/BBean_JPA.java
Modified:
    incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/CmpUtil.java
    incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmrFactoryImpl.java
    incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmrSet.java
    incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/JpaTest.java
    incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/MultiValuedCmrImpl.java
    incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/SingleValuedCmrImpl.java
    incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/CmrFactory.java
    incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/MultiValuedCmr.java
    incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetoone/ABean_JPA.java
    incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetoone/BBean_JPA.java
    incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/ejb-jar.xml
    incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/jpa.mapping.xml
    incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/openejb-jar.xml
    incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/HsqldbTestDatabase.java
    incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/AbstractCMRTest.java
    incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/CmrTestSuite.java
    incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/OneToManyTests.java
    incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/OneToOneTests.java

Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/CmpUtil.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/CmpUtil.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/CmpUtil.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/CmpUtil.java Tue Dec 12 20:08:39 2006
@@ -27,9 +27,19 @@
 import javax.ejb.EJBLocalObject;
 import javax.ejb.EntityBean;
 import javax.ejb.EJBLocalHome;
+import java.lang.reflect.Field;
 
 public class CmpUtil {
-    public static EntityBean getEntityBean(CoreDeploymentInfo deploymentInfo, EJBLocalObject proxy) {
+    public static Object getPrimaryKey(CoreDeploymentInfo deploymentInfo, EntityBean entity){
+        if (entity == null) return null;
+
+        // build the primary key
+        KeyGenerator kg = deploymentInfo.getKeyGenerator();
+        Object primaryKey = kg.getPrimaryKey(entity);
+        return primaryKey;
+    }
+
+    public static EntityBean getEntityBean(EJBLocalObject proxy) {
         if (proxy == null) return null;
 
         EjbObjectProxyHandler handler = (EjbObjectProxyHandler) ProxyManager.getInvocationHandler(proxy);
@@ -45,8 +55,7 @@
         if (entity == null) return null;
 
         // build the primary key
-        KeyGenerator kg = deploymentInfo.getKeyGenerator();
-        Object primaryKey = kg.getPrimaryKey(entity);
+        Object primaryKey = getPrimaryKey(deploymentInfo, entity);
 
         // get the local interface
         Class localInterface = deploymentInfo.getLocalInterface();
@@ -67,5 +76,17 @@
         // create the proxy
         EJBLocalObject proxy = (EJBLocalObject) handler.createProxy(proxyInfo);
         return proxy;
+    }
+
+    public static CoreDeploymentInfo getDeploymentInfo(Class type) {
+        CoreDeploymentInfo deploymentInfo;
+        try {
+            Field deploymentInfoField = type.getField("deploymentInfo");
+            deploymentInfo = (CoreDeploymentInfo) deploymentInfoField.get(null);
+        } catch (Exception e) {
+            throw new IllegalArgumentException("EntityBean class " + type.getName() +
+                    " does not contain a deploymentInfo field.  Is this a generated CMP 2 entity implementation?");
+        }
+        return deploymentInfo;
     }
 }

Added: incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmpWrapper.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmpWrapper.java?view=auto&rev=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmpWrapper.java (added)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmpWrapper.java Tue Dec 12 20:08:39 2006
@@ -0,0 +1,55 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.core.cmp.jpa;
+
+import javax.ejb.EJBException;
+import java.lang.reflect.Method;
+
+public class CmpWrapper {
+    private final Object bean;
+    private final Class type;
+    private final Method addCmrMethod;
+    private final Method removeCmrMethod;
+
+    public CmpWrapper(Object bean, Method addCmrMethod, Method removeCmrMethod) {
+        this.bean = bean;
+        this.addCmrMethod = addCmrMethod;
+        this.removeCmrMethod = removeCmrMethod;
+        type = addCmrMethod.getDeclaringClass();
+    }
+
+    public Object addCmr(String property, Object pk, Object bean) {
+        if (property == null) throw new NullPointerException("property is null");
+        try {
+            Object oldValue = addCmrMethod.invoke(this.bean, property, pk, bean);
+            return oldValue;
+        } catch (Exception e) {
+            throw new EJBException("Error setting property " + property + " on entity bean of type " + type.getName());
+        }
+    }
+
+    public Object removeCmr(String property, Object pk, Object bean) {
+        if (property == null) throw new NullPointerException("property is null");
+        try {
+            Object oldValue = removeCmrMethod.invoke(this.bean, property, pk, bean);
+            return oldValue;
+        } catch (Exception e) {
+            throw new EJBException("Error setting property " + property + " on entity bean of type " + type.getName());
+        }
+    }
+}

Added: incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmpWrapperFactory.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmpWrapperFactory.java?view=auto&rev=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmpWrapperFactory.java (added)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmpWrapperFactory.java Tue Dec 12 20:08:39 2006
@@ -0,0 +1,44 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.core.cmp.jpa;
+
+import java.lang.reflect.Method;
+
+public class CmpWrapperFactory {
+    private final Method addCmrMethod;
+    private final Method removeCmrMethod;
+
+    public CmpWrapperFactory(Class relatedType) {
+        try {
+            addCmrMethod = relatedType.getMethod("OpenEJB_addCmr", String.class, Object.class, Object.class);
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException("EntityBean class " + relatedType.getName() +
+                    " does not contain the generated method OpenEJB_addCmr(String name, Object pk, Object bean) method");
+        }
+        try {
+            removeCmrMethod = relatedType.getMethod("OpenEJB_removeCmr", String.class, Object.class, Object.class);
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException("EntityBean class " + relatedType.getName() +
+                    " does not contain the generated method OpenEJB_removeCmr(String name, Object pk, Object bean) method");
+        }
+    }
+
+    public CmpWrapper createCmpEntityBean(Object bean) {
+        return new CmpWrapper(bean, addCmrMethod, removeCmrMethod);
+    }
+}

Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmrFactoryImpl.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmrFactoryImpl.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmrFactoryImpl.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmrFactoryImpl.java Tue Dec 12 20:08:39 2006
@@ -18,13 +18,18 @@
 package org.apache.openejb.core.cmp.jpa;
 
 import org.apache.openejb.test.entity.CmrFactory;
+import org.apache.openejb.test.entity.MultiValuedCmr;
 import org.apache.openejb.test.entity.SingleValuedCmr;
 
-import javax.ejb.EntityBean;
 import javax.ejb.EJBLocalObject;
+import javax.ejb.EntityBean;
 
 public class CmrFactoryImpl implements CmrFactory {
-    public <I extends EntityBean, P extends EJBLocalObject> SingleValuedCmr<I, P> createSingleValuedCmr(EntityBean source, String sourceProperty, Class<I> relatedType, String relatedProperty) {
-        return new SingleValuedCmrImpl<I, P>(source, sourceProperty, relatedType, relatedProperty);
+    public <Bean extends EntityBean, Proxy extends EJBLocalObject> SingleValuedCmr<Bean, Proxy> createSingleValuedCmr(EntityBean source, String sourceProperty, Class<Bean> relatedType, String relatedProperty) {
+        return new SingleValuedCmrImpl<Bean, Proxy>(source, sourceProperty, relatedType, relatedProperty);
+    }
+
+    public <Bean extends EntityBean, Proxy extends EJBLocalObject, PK> MultiValuedCmr<Bean, Proxy, PK> createMultiValuedCmr(EntityBean source, String sourceProperty, Class<Bean> relatedType, String property) {
+        return new MultiValuedCmrImpl<Bean, Proxy, PK>(source, sourceProperty, relatedType, property);
     }
 }

Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmrSet.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmrSet.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmrSet.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/CmrSet.java Tue Dec 12 20:08:39 2006
@@ -23,7 +23,6 @@
 import javax.ejb.EJBException;
 import javax.ejb.EJBLocalObject;
 import javax.ejb.EntityBean;
-import java.lang.reflect.Field;
 import java.util.AbstractSet;
 import java.util.Collection;
 import java.util.HashSet;
@@ -36,21 +35,32 @@
  * @version $Revision: 945 $ $Date: 2003-11-18 20:04:26 -0600 (Tue, 18 Nov 2003) $
  */
 public class CmrSet<Bean extends EntityBean, Proxy extends EJBLocalObject, PK> extends AbstractSet<Proxy> {
+    private final CoreDeploymentInfo sourceInfo;
     private final EntityBean source;
-//    private final CoreDeploymentInfo sourceInfo;
-    private final Field relatedField;
+    private final Class<? extends EntityBean> sourceType;
+    private final String sourceProperty;
+    private final CmpWrapperFactory sourceWrapperFactory;
     private final CoreDeploymentInfo relatedInfo;
-    private Map<PK, Bean> beans;
     private final Class<Bean> relatedType;
+    private final String relatedProperty;
+    private final CmpWrapperFactory relatedWrapperFactory;
+    private final Map<PK, Bean> relatedBeans;
 
-    public CmrSet(EntityBean source, Field relatedField, CoreDeploymentInfo relatedInfo, Map<PK, Bean> beans) {
+    public CmrSet(CoreDeploymentInfo sourceInfo, EntityBean source, String sourceProperty, CmpWrapperFactory sourceWrapperFactory, CoreDeploymentInfo relatedInfo, Class<Bean> relatedType, String relatedProperty, CmpWrapperFactory relatedWrapperFactory, Map<PK, Bean> relatedBeans) {
+        this.sourceInfo = sourceInfo;
         this.source = source;
-        this.relatedField = relatedField;
+        this.sourceProperty = sourceProperty;
+        this.sourceWrapperFactory = sourceWrapperFactory;
         this.relatedInfo = relatedInfo;
-        this.beans = beans;
-        relatedType = (Class<Bean>) relatedField.getDeclaringClass();
+        this.relatedType = relatedType;
+        this.relatedProperty = relatedProperty;
+        this.relatedWrapperFactory = relatedWrapperFactory;
+        this.relatedBeans = relatedBeans;
+        this.sourceType = source.getClass();
+
     }
-    // todo override equals and hash code
+
+    // todo should we support a close method?
 //    void invalidate() {
 //        context = null;
 //        slot = -1;
@@ -59,50 +69,66 @@
 //        relatedLocalInterface = null;
 //    }
 
+    public boolean isEmpty() {
+        return relatedBeans.isEmpty();
+    }
+
     public int size() {
-        return beans.size();
+        return relatedBeans.size();
     }
 
     public boolean contains(Object o) {
         if (relatedType.isInstance(o)) {
             PK primaryKey = getPrimaryKey(o);
-            return beans.containsKey(primaryKey);
+            return relatedBeans.containsKey(primaryKey);
         }
         return false;
     }
 
-    public void clear() {
-        beans.clear();
-    }
-
     public boolean add(Proxy proxy) {
-        PK primaryKey = getPrimaryKey(proxy);
-        Bean entity = getEntityBean(proxy);
-        boolean changed = beans.put(primaryKey, entity) != null;
+        Object sourcePk = getSourcePk();
+        PK newPk = getPrimaryKey(proxy);
+        Bean newBean = getEntityBean(proxy);
+        boolean changed = relatedBeans.put(newPk, newBean) == null;
         if (changed) {
-            // todo update related
+            // set the back reference in the new related bean
+            Object oldBackRef = getCmpWrapper(newBean).addCmr(relatedProperty, sourcePk, source);
+
+            // add the bean to our value map
+            relatedBeans.put(newPk, newBean);
+
+            // if the new related beas was related to another bean, we need
+            // to clear the back reference in that old bean
+            if (oldBackRef != null) {
+                getCmpWrapper(oldBackRef).removeCmr(sourceProperty, newPk, newBean);
+            }
         }
         return changed;
     }
 
     public boolean remove(Object o) {
-        Object primaryKey = getPrimaryKey(o);
-        boolean changed = beans.remove(primaryKey) != null;
-        if (changed) {
-            // todo update related
+        PK primaryKey = getPrimaryKey(o);
+        Bean oldBean = relatedBeans.remove(primaryKey);
+        if (oldBean != null) {
+            Object sourcePk = getSourcePk();
+            getCmpWrapper(oldBean).removeCmr(relatedProperty, sourcePk, source);
         }
-        return changed;
+        return oldBean != null;
     }
 
     public boolean retainAll(Collection<?> c) {
         Collection<PK> inputKeys = getPrimaryKeys(c);
 
         boolean changed = false;
-        for (Iterator<PK> iterator = beans.keySet().iterator(); iterator.hasNext();) {
-            PK primaryKey = iterator.next();
-            if (!inputKeys.contains(primaryKey)) {
+        Object sourcePk = getSourcePk();
+        for (Iterator<Map.Entry<PK, Bean>> iterator = relatedBeans.entrySet().iterator(); iterator.hasNext();) {
+            Map.Entry<PK, Bean> entry = iterator.next();
+            PK pk = entry.getKey();
+            Bean bean = entry.getValue();
+            if (!inputKeys.contains(pk)) {
+                changed = true;
                 iterator.remove();
-                // todo update related
+                getCmpWrapper(bean).removeCmr(relatedProperty, sourcePk, source);
             }
         }
         return changed;
@@ -110,20 +136,24 @@
 
     public Iterator<Proxy> iterator() {
         return new Iterator<Proxy>() {
+            private Bean currentEntity;
+            private Object sourcePk = getSourcePk();
+
             // todo we should drop the reference to the iterator when the set is invalidated
-            private Iterator<Bean> iterator = beans.values().iterator();
+            private Iterator<Bean> iterator = relatedBeans.values().iterator();
 
             public boolean hasNext() {
                 return iterator.hasNext();
             }
 
             public Proxy next() {
-                Bean entity = iterator.next();
-                return getEjbProxy(entity);
+                currentEntity = iterator.next();
+                return getEjbProxy(currentEntity);
             }
 
             public void remove() {
                 iterator.remove();
+                getCmpWrapper(currentEntity).removeCmr(relatedProperty, sourcePk, source);
             }
         };
     }
@@ -144,27 +174,34 @@
         return ejbProxy;
     }
 
-//    private I updateEntityBean(EJBLocalObject proxy) throws EJBException {
-//        if (proxy == null) return null;
-//
-//        I bean = getEntityBean(proxy);
-//        try {
-//            relatedField.set(bean, source);
-//        } catch (IllegalAccessException e) {
-//            throw new EJBException("Error setting " + relatedField.getName() + " on bean " + proxy.getPrimaryKey());
-//        }
-//        return bean;
-//    }
-
     private Bean getEntityBean(EJBLocalObject proxy) {
         if (proxy == null) return null;
 
-        Bean bean = (Bean) CmpUtil.getEntityBean(relatedInfo, proxy);
+        Bean bean = (Bean) CmpUtil.getEntityBean(proxy);
         return bean;
     }
 
     private PK getPrimaryKey(Object o) {
         Proxy proxy = (Proxy) o;
         return (PK) proxy.getPrimaryKey();
+    }
+
+    private Object getSourcePk() {
+        Object sourcePk = CmpUtil.getPrimaryKey(sourceInfo, source);
+        if (sourcePk == null) {
+            throw new IllegalStateException("CMR " + sourceProperty + " can not be modified on entity of type " +
+                    sourceInfo.getBeanClass().getName() + " because primary key has not been established yet.");
+        }
+        return sourcePk;
+    }
+
+    private CmpWrapper getCmpWrapper(Object object) {
+        if (object == null) return null;
+        if (sourceType.isInstance(object)) {
+            return sourceWrapperFactory.createCmpEntityBean(object);
+        } else if (relatedType.isInstance(object)) {
+            return relatedWrapperFactory.createCmpEntityBean(object);
+        }
+        throw new IllegalArgumentException("Unknown cmp bean type " + object.getClass().getName());
     }
 }

Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/JpaTest.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/JpaTest.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/JpaTest.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/JpaTest.java Tue Dec 12 20:08:39 2006
@@ -214,8 +214,8 @@
         beginTx();
         b = entityManager.find(BBean_JPA.class, 22);
         a = entityManager.find(ABean_JPA.class, 2);
-        a.OpenEJB_setCmr("b", b);
-        b.OpenEJB_setCmr("a", a);
+        a.OpenEJB_addCmr("b", 22, b);
+        b.OpenEJB_addCmr("a", 2, a);
         commitTx();
 
 //        dump();
@@ -224,9 +224,9 @@
         b = entityManager.find(BBean_JPA.class, 22);
         assertNotNull(b);
         assertEquals(new Integer(22), b.getField1());
-        a = (ABean_JPA) b.OpenEJB_getCmr("a");
-        assertNotNull(a);
-        assertEquals(new Integer(2), a.getField1());
+//        a = (ABean_JPA) b.OpenEJB_getCmr("a");
+//        assertNotNull(a);
+//        assertEquals(new Integer(2), a.getField1());
         commitTx();
     }
 

Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/MultiValuedCmrImpl.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/MultiValuedCmrImpl.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/MultiValuedCmrImpl.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/MultiValuedCmrImpl.java Tue Dec 12 20:08:39 2006
@@ -18,60 +18,96 @@
 package org.apache.openejb.core.cmp.jpa;
 
 import org.apache.openejb.core.CoreDeploymentInfo;
+import org.apache.openejb.core.cmp.CmpUtil;
 import org.apache.openejb.test.entity.MultiValuedCmr;
 
 import javax.ejb.EJBLocalObject;
 import javax.ejb.EntityBean;
-import java.lang.reflect.Field;
 import java.util.Map;
 import java.util.Set;
 
 public class MultiValuedCmrImpl<Bean extends EntityBean, Proxy extends EJBLocalObject, PK> implements MultiValuedCmr<Bean, Proxy, PK> {
+    private final CoreDeploymentInfo sourceInfo;
     private final EntityBean source;
-//    private final CoreDeploymentInfo sourceInfo;
-    private final Field relatedField;
+    private final Class<? extends EntityBean> sourceType;
+    private final String sourceProperty;
+    private final Class<Bean> relatedType;
+    private final String relatedProperty;
     private final CoreDeploymentInfo relatedInfo;
+    private final CmpWrapperFactory sourceWrapperFactory;
+    private final CmpWrapperFactory relatedWrapperFactory;
 
-    public MultiValuedCmrImpl(EntityBean source, Class<Bean> relatedType, String property) {
+    public MultiValuedCmrImpl(EntityBean source, String sourceProperty, Class<Bean> relatedType, String relatedProperty) {
         if (source == null) throw new NullPointerException("source is null");
+        if (sourceProperty == null) throw new NullPointerException("sourceProperty is null");
         if (relatedType == null) throw new NullPointerException("relatedType is null");
-        if (property == null) throw new NullPointerException("property is null");
-
+        if (relatedProperty == null) throw new NullPointerException("relatedProperty is null");
         this.source = source;
-        try {
-            relatedField = relatedType.getField(property);
-        } catch (NoSuchFieldException e) {
-            throw new IllegalArgumentException("Related type " + relatedType.getName() + " does not contain a property " + property);
-        }
-        if (!relatedField.getType().isAssignableFrom(source.getClass())) {
-            throw new IllegalArgumentException("Related type is " + relatedType.getName() + " but field " +
-                    property + " type is " + relatedField.getType().getName());
-        }
+        this.sourceProperty = sourceProperty;
+        this.relatedType = relatedType;
+        this.relatedProperty = relatedProperty;
+        this.sourceType = source.getClass();
 
-        try {
-            Field deploymentInfoField = relatedType.getField("deploymentInfo");
-            relatedInfo = (CoreDeploymentInfo) deploymentInfoField.get(null);
-        } catch (Exception e) {
-            throw new IllegalArgumentException("EntityBean class " + relatedType.getName() +
-                    " does not contain a deploymentInfo field.  Is this a generated CMP 2 entity implementation?");
-        }
-//
-//        try {
-//            Field deploymentInfoField = source.getClass().getField("deploymentInfo");
-//            sourceInfo = (CoreDeploymentInfo) deploymentInfoField.get(null);
-//        } catch (Exception e) {
-//            throw new IllegalArgumentException("EntityBean class " + source.getClass().getName() +
-//                    " does not contain a deploymentInfo field.  Is this a generated CMP 2 entity implementation?");
-//        }
+        this.sourceInfo = CmpUtil.getDeploymentInfo(source.getClass());
+        this.relatedInfo = CmpUtil.getDeploymentInfo(relatedType);
+
+        sourceWrapperFactory = new CmpWrapperFactory(sourceType);
+        relatedWrapperFactory = new CmpWrapperFactory(relatedType);
     }
 
     public Set<Proxy> get(Map<PK, Bean> others) {
         if (others == null) throw new NullPointerException("others is null");
-        Set<Proxy> cmrSet = new CmrSet<Bean, Proxy, PK>(source, relatedField, relatedInfo, others);
+        Set<Proxy> cmrSet = new CmrSet<Bean, Proxy, PK>(sourceInfo, source, sourceProperty, sourceWrapperFactory, relatedInfo, relatedType, relatedProperty, relatedWrapperFactory, others);
         return cmrSet;
     }
 
-    public Map<PK, Bean> set(Set<Proxy> others) {
-        return null;
+    public void set(Map<PK, Bean> relatedBeans, Set<Proxy> newProxies) {
+        Object sourcePk = getSourcePk();
+
+        // clear back reference in the old related beans
+        for (Bean oldBean : relatedBeans.values()) {
+            if (oldBean != null) {
+                getCmpWrapper(oldBean).removeCmr(relatedProperty, sourcePk, source);
+            }
+        }
+        relatedBeans.clear();
+
+        for (Proxy newProxy : newProxies) {
+            Bean newBean = (Bean) CmpUtil.getEntityBean(newProxy);
+            PK newPk = (PK) newProxy.getPrimaryKey();
+
+            if (newProxy != null) {
+                // set the back reference in the new related bean
+                Object oldBackRef = getCmpWrapper(newBean).addCmr(relatedProperty, sourcePk, source);
+
+                // add the bean to our value map
+                relatedBeans.put(newPk, newBean);
+
+                // if the new related beas was related to another bean, we need
+                // to clear the back reference in that old bean
+                if (oldBackRef != null) {
+                    getCmpWrapper(oldBackRef).removeCmr(sourceProperty, newPk, newBean);
+                }
+            }
+        }
+    }
+
+    private Object getSourcePk() {
+        Object sourcePk = CmpUtil.getPrimaryKey(sourceInfo, source);
+        if (sourcePk == null) {
+            throw new IllegalStateException("CMR " + sourceProperty + " can not be modified on entity of type " +
+                    sourceInfo.getBeanClass().getName() + " because primary key has not been established yet.");
+        }
+        return sourcePk;
+    }
+
+    private CmpWrapper getCmpWrapper(Object object) {
+        if (object == null) return null;
+        if (sourceType.isInstance(object)) {
+            return sourceWrapperFactory.createCmpEntityBean(object);
+        } else if (relatedType.isInstance(object)) {
+            return relatedWrapperFactory.createCmpEntityBean(object);
+        }
+        throw new IllegalArgumentException("Unknown cmp bean type " + object.getClass().getName());
     }
 }

Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/SingleValuedCmrImpl.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/SingleValuedCmrImpl.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/SingleValuedCmrImpl.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/SingleValuedCmrImpl.java Tue Dec 12 20:08:39 2006
@@ -24,10 +24,9 @@
 import javax.ejb.EJBException;
 import javax.ejb.EJBLocalObject;
 import javax.ejb.EntityBean;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
 
 public class SingleValuedCmrImpl<Bean extends EntityBean, Proxy extends EJBLocalObject> implements SingleValuedCmr<Bean, Proxy> {
+    private final CoreDeploymentInfo sourceInfo;
     private final EntityBean source;
     private final Class<? extends EntityBean> sourceType;
     private final String sourceProperty;
@@ -48,13 +47,8 @@
         this.relatedProperty = relatedProperty;
         this.sourceType = source.getClass();
 
-        try {
-            Field deploymentInfoField = relatedType.getField("deploymentInfo");
-            relatedInfo = (CoreDeploymentInfo) deploymentInfoField.get(null);
-        } catch (Exception e) {
-            throw new IllegalArgumentException("EntityBean class " + relatedType.getName() +
-                    " does not contain a deploymentInfo field.  Is this a generated CMP 2 entity implementation?");
-        }
+        this.sourceInfo = CmpUtil.getDeploymentInfo(source.getClass());
+        this.relatedInfo = CmpUtil.getDeploymentInfo(relatedType);
 
         sourceWrapperFactory = new CmpWrapperFactory(sourceType);
         relatedWrapperFactory = new CmpWrapperFactory(relatedType);
@@ -68,26 +62,36 @@
     }
 
     public Bean set(Bean oldBean, Proxy newValue) throws EJBException {
-        Bean newBean = (Bean) CmpUtil.getEntityBean(relatedInfo, newValue);
+        Object sourcePk = getSourcePk();
+        Bean newBean = (Bean) CmpUtil.getEntityBean(newValue);
 
         // clear back reference in the old related bean
         if (oldBean != null) {
-            getCmpWrapper(oldBean).setCmr(relatedProperty, null);
+            getCmpWrapper(oldBean).removeCmr(relatedProperty, sourcePk, source);
         }
 
         if (newValue != null) {
             // set the back reference in the new related bean
-            Object oldSource = getCmpWrapper(newBean).setCmr(relatedProperty, source);
+            Object oldBackRef = getCmpWrapper(newBean).addCmr(relatedProperty, sourcePk, source);
 
             // if the new related beas was related to another bean, we need
             // to clear the back reference in that old bean
-            if (oldSource != null) {
-                getCmpWrapper(oldSource).setCmr(sourceProperty, null);
+            if (oldBackRef != null) {
+                getCmpWrapper(oldBackRef).removeCmr(sourceProperty, newValue.getPrimaryKey(), newBean);
             }
         }
         return newBean;
     }
 
+    private Object getSourcePk() {
+        Object sourcePk = CmpUtil.getPrimaryKey(sourceInfo, source);
+        if (sourcePk == null) {
+            throw new IllegalStateException("CMR " + sourceProperty + " can not be modified on entity of type " +
+                    sourceInfo.getBeanClass().getName() + " because primary key has not been established yet.");
+        }
+        return sourcePk;
+    }
+
     private CmpWrapper getCmpWrapper(Object object) {
         if (object == null) return null;
         if (sourceType.isInstance(object)) {
@@ -98,62 +102,4 @@
         throw new IllegalArgumentException("Unknown cmp bean type " + object.getClass().getName());
     }
 
-    public static class CmpWrapperFactory {
-        private final Method getValueMethod;
-        private final Method setValueMethod;
-
-        public CmpWrapperFactory(Class relatedType) {
-            try {
-                setValueMethod = relatedType.getMethod("OpenEJB_setCmr", String.class, Object.class);
-            } catch (NoSuchMethodException e) {
-                throw new IllegalArgumentException("EntityBean class " + relatedType.getName() +
-                        " does not contain the generated method OpenEJB_setCmr(String name, Object bean) method");
-            }
-            try {
-                getValueMethod = relatedType.getMethod("OpenEJB_getCmr", String.class);
-            } catch (NoSuchMethodException e) {
-                throw new IllegalArgumentException("EntityBean class " + relatedType.getName() +
-                        " does not contain the generated method OpenEJB_getCmr(String name) method");
-            }
-        }
-
-        public CmpWrapper createCmpEntityBean(Object bean) {
-            return new CmpWrapper(bean, getValueMethod, setValueMethod);
-        }
-    }
-
-
-    public static class CmpWrapper {
-        private final Object bean;
-        private final Class type;
-        private final Method getValueMethod;
-        private final Method setValueMethod;
-
-        public CmpWrapper(Object bean, Method getValueMethod, Method setValueMethod) {
-            this.bean = bean;
-            this.getValueMethod = getValueMethod;
-            this.setValueMethod = setValueMethod;
-            type = getValueMethod.getDeclaringClass();
-        }
-
-        public Object getCmr(String property) {
-            if (property == null) throw new NullPointerException("property is null");
-            try {
-                Object value = getValueMethod.invoke(bean, property);
-                return value;
-            } catch (Exception e) {
-                throw new EJBException("Error getting property " + property + " value from entity bean of type " + type.getName());
-            }
-        }
-
-        public Object setCmr(String property, Object value) {
-            if (property == null) throw new NullPointerException("property is null");
-            try {
-                Object oldValue = setValueMethod.invoke(bean, property, value);
-                return oldValue;
-            } catch (Exception e) {
-                throw new EJBException("Error setting property " + property + " on entity bean of type " + type.getName());
-            }
-        }
-    }
 }

Modified: incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/CmrFactory.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/CmrFactory.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/CmrFactory.java (original)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/CmrFactory.java Tue Dec 12 20:08:39 2006
@@ -30,7 +30,11 @@
                 return cmrFactory;
             } catch (Exception e) {
                 return new CmrFactory() {
-                    public <I extends EntityBean, P extends EJBLocalObject> SingleValuedCmr<I, P> createSingleValuedCmr(EntityBean source, String sourceProperty, Class<I> relatedType, String property) {
+                    public <Bean extends EntityBean, Proxy extends EJBLocalObject> SingleValuedCmr<Bean, Proxy> createSingleValuedCmr(EntityBean source, String sourceProperty, Class<Bean> relatedType, String property) {
+                        return null;
+                    }
+
+                    public <Bean extends EntityBean, Proxy extends EJBLocalObject, PK> MultiValuedCmr<Bean, Proxy, PK> createMultiValuedCmr(EntityBean source, String sourceProperty, Class<Bean> relatedType, String property) {
                         return null;
                     }
                 };
@@ -38,5 +42,7 @@
         }
     }.call();
 
-    public <I extends EntityBean, P extends EJBLocalObject> SingleValuedCmr<I, P> createSingleValuedCmr(EntityBean source, String sourceProperty, Class<I> relatedType, String property);
+    <Bean extends EntityBean, Proxy extends EJBLocalObject> SingleValuedCmr<Bean, Proxy> createSingleValuedCmr(EntityBean source, String sourceProperty, Class<Bean> relatedType, String property);
+
+    <Bean extends EntityBean, Proxy extends EJBLocalObject, PK> MultiValuedCmr<Bean, Proxy, PK> createMultiValuedCmr(EntityBean source, String sourceProperty, Class<Bean> relatedType, String property);
 }

Modified: incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/MultiValuedCmr.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/MultiValuedCmr.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/MultiValuedCmr.java (original)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/MultiValuedCmr.java Tue Dec 12 20:08:39 2006
@@ -17,14 +17,13 @@
  */
 package org.apache.openejb.test.entity;
 
-import javax.ejb.EntityBean;
 import javax.ejb.EJBLocalObject;
-import javax.ejb.EJBException;
+import javax.ejb.EntityBean;
 import java.util.Map;
 import java.util.Set;
 
 public interface MultiValuedCmr<Bean extends EntityBean, Proxy extends EJBLocalObject, PK> {
     Set<Proxy> get(Map<PK, Bean> others);
 
-    Map<PK, Bean> set(Set<Proxy> others);
+    void set(Map<PK, Bean> oldValue, Set<Proxy> newValue);
 }

Added: incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetomany/ABean_JPA.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetomany/ABean_JPA.java?view=auto&rev=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetomany/ABean_JPA.java (added)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetomany/ABean_JPA.java Tue Dec 12 20:08:39 2006
@@ -0,0 +1,88 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.test.entity.cmr.onetomany;
+
+import org.apache.openejb.test.entity.MultiValuedCmr;
+import org.apache.openejb.test.entity.CmrFactory;
+
+import java.util.Set;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Collections;
+
+public class ABean_JPA extends ABean {
+    public static Object deploymentInfo;
+    public Integer field1;
+    private String field2;
+    private Map<Integer,BBean_JPA> b = new HashMap<Integer, BBean_JPA>();
+    private MultiValuedCmr<BBean_JPA, BLocal, Integer> bCmr = CmrFactory.cmrFactory.createMultiValuedCmr(this, "b", BBean_JPA.class, "a");
+
+    public Integer getField1() {
+        return field1;
+    }
+
+    public void setField1(Integer field1) {
+        this.field1 = field1;
+    }
+
+    public String getField2() {
+        return field2;
+    }
+
+    public void setField2(String field2) {
+        this.field2 = field2;
+    }
+
+    public static Object getDeploymentInfo() {
+        return deploymentInfo;
+    }
+
+    public static void setDeploymentInfo(Object deploymentInfo) {
+        ABean_JPA.deploymentInfo = deploymentInfo;
+    }
+
+    public Set<BLocal> getB() {
+        return bCmr.get(b);
+    }
+
+    public void setB(Set<BLocal> b) {
+        bCmr.set(this.b, b);
+    }
+
+    public void OpenEJB_deleted() {
+        bCmr.set(b, Collections.<BLocal>emptySet());
+    }
+
+    public Object OpenEJB_addCmr(String name, Object pk, Object bean) {
+        Object oldValue = null;
+        if ("b".equals(name)) {
+            b.put((Integer)pk, (BBean_JPA) bean);
+        } else {
+            throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
+        }
+        return oldValue;
+    }
+
+    public void OpenEJB_removeCmr(String name, Object pk, Object value) {
+        if ("b".equals(name)) {
+            b.remove(pk);
+        } else {
+            throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
+        }
+    }
+}

Added: incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetomany/BBean_JPA.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetomany/BBean_JPA.java?view=auto&rev=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetomany/BBean_JPA.java (added)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetomany/BBean_JPA.java Tue Dec 12 20:08:39 2006
@@ -0,0 +1,94 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.test.entity.cmr.onetomany;
+
+import org.apache.openejb.test.entity.SingleValuedCmr;
+import org.apache.openejb.test.entity.CmrFactory;
+
+public class BBean_JPA extends BBean {
+    public static Object deploymentInfo;
+    public Integer field1;
+    private String field2;
+    private Integer field3;
+    private String field4;
+    private ABean_JPA a;
+    private SingleValuedCmr<ABean_JPA, ALocal> aCmr = CmrFactory.cmrFactory.createSingleValuedCmr(this, "a", ABean_JPA.class, "b");
+
+    public Integer getField1() {
+        return field1;
+    }
+
+    public void setField1(Integer field1) {
+        this.field1 = field1;
+    }
+
+    public String getField2() {
+        return field2;
+    }
+
+    public void setField2(String field2) {
+        this.field2 = field2;
+    }
+
+    public Integer getField3() {
+        return field3;
+    }
+
+    public void setField3(Integer field3) {
+        this.field3 = field3;
+    }
+
+    public String getField4() {
+        return field4;
+    }
+
+    public void setField4(String field4) {
+        this.field4 = field4;
+    }
+
+    public ALocal getA() {
+        return aCmr.get(a);
+    }
+
+    public void OpenEJB_deleted() {
+        a = aCmr.set(a, null);
+    }
+
+    public void setA(ALocal a) {
+        this.a = aCmr.set(this.a, a);
+    }
+
+    public Object OpenEJB_addCmr(String name, Object pk, Object bean) {
+        Object oldValue;
+        if ("a".equals(name)) {
+            oldValue = a;
+            a = (ABean_JPA) bean;
+        } else {
+            throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
+        }
+        return oldValue;
+    }
+
+    public void OpenEJB_removeCmr(String name, Object pk, Object bean) {
+        if ("a".equals(name)) {
+            a = null;
+        } else {
+            throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
+        }
+    }
+}

Modified: incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetoone/ABean_JPA.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetoone/ABean_JPA.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetoone/ABean_JPA.java (original)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetoone/ABean_JPA.java Tue Dec 12 20:08:39 2006
@@ -55,22 +55,22 @@
         b = bCmr.set(b, null);
     }
 
-    public Object OpenEJB_getCmr(String name) {
+    public Object OpenEJB_addCmr(String name, Object pk, Object bean) {
+        Object oldValue;
         if ("b".equals(name)) {
-            return b;
+            oldValue = b;
+            b = (BBean_JPA) bean;
         } else {
             throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
         }
+        return oldValue;
     }
 
-    public Object OpenEJB_setCmr(String name, Object bean) {
-        Object oldValue;
+    public void OpenEJB_removeCmr(String name, Object pk, Object bean) {
         if ("b".equals(name)) {
-            oldValue = b;
-            b = (BBean_JPA) bean;
+            b = null;
         } else {
             throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
         }
-        return oldValue;
     }
 }

Modified: incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetoone/BBean_JPA.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetoone/BBean_JPA.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetoone/BBean_JPA.java (original)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/java/org/apache/openejb/test/entity/cmr/onetoone/BBean_JPA.java Tue Dec 12 20:08:39 2006
@@ -28,8 +28,6 @@
     private String field4;
     private ABean_JPA a;
     private SingleValuedCmr<ABean_JPA, ALocal> aCmr = CmrFactory.cmrFactory.createSingleValuedCmr(this, "a", ABean_JPA.class, "b");
-//    private Map<Integer,ABean_JPA> others;
-//    private MultiValuedCmr<ABean_JPA, ALocal, Integer> othersCmr = null;
 
     public Integer getField1() {
         return field1;
@@ -75,31 +73,22 @@
         this.a = aCmr.set(this.a, a);
     }
 
-//    public Set<ALocal> getOthers() {
-//        if (others == null) others = new HashMap<Integer,ABean_JPA>();
-//        return othersCmr.get(others);
-//    }
-//
-//    public void setOthers(Set<ALocal> others) {
-//        this.others = othersCmr.set(others);
-//    }
-
-    public Object OpenEJB_getCmr(String name) {
+    public Object OpenEJB_addCmr(String name, Object pk, Object bean) {
+        Object oldValue;
         if ("a".equals(name)) {
-            return a;
+            oldValue = a;
+            a = (ABean_JPA) bean;
         } else {
             throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
         }
+        return oldValue;
     }
 
-    public Object OpenEJB_setCmr(String name, Object bean) {
-        Object oldValue;
+    public void OpenEJB_removeCmr(String name, Object pk, Object bean) {
         if ("a".equals(name)) {
-            oldValue = a;
-            a = (ABean_JPA) bean;
+            a = null;
         } else {
             throw new IllegalArgumentException("Unknown cmr field " + name + " on entity bean of type " + getClass().getName());
         }
-        return oldValue;
     }
 }

Modified: incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/ejb-jar.xml
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/ejb-jar.xml?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/ejb-jar.xml (original)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/ejb-jar.xml Tue Dec 12 20:08:39 2006
@@ -573,6 +573,69 @@
             </query>
         </entity>
 
+      <entity>
+          <ejb-name>OneToManyA</ejb-name>
+          <local-home>org.apache.openejb.test.entity.cmr.onetomany.ALocalHome</local-home>
+          <local>org.apache.openejb.test.entity.cmr.onetomany.ALocal</local>
+          <ejb-class>org.apache.openejb.test.entity.cmr.onetomany.ABean_JPA</ejb-class>
+          <persistence-type>Container</persistence-type>
+          <prim-key-class>java.lang.Integer</prim-key-class>
+          <reentrant>false</reentrant>
+          <cmp-version>2.x</cmp-version>
+          <abstract-schema-name>OneToOneA</abstract-schema-name>
+          <cmp-field>
+              <field-name>field1</field-name>
+          </cmp-field>
+          <cmp-field>
+              <field-name>field2</field-name>
+          </cmp-field>
+          <primkey-field>field1</primkey-field>
+          <query>
+              <!-- CompondPK one-to-one shares the local home interface so we need to declare this useless finder -->
+              <query-method>
+                  <method-name>findByPrimaryKey</method-name>
+                  <method-params>
+                      <method-param>org.apache.openejb.deployment.entity.cmr.CompoundPK</method-param>
+                  </method-params>
+              </query-method>
+              <ejb-ql>SELECT OBJECT(A) FROM OneToManyA A</ejb-ql>
+          </query>
+      </entity>
+      <entity>
+          <ejb-name>OneToManyB</ejb-name>
+          <local-home>org.apache.openejb.test.entity.cmr.onetomany.BLocalHome</local-home>
+          <local>org.apache.openejb.test.entity.cmr.onetomany.BLocal</local>
+          <ejb-class>org.apache.openejb.test.entity.cmr.onetomany.BBean_JPA</ejb-class>
+          <persistence-type>Container</persistence-type>
+          <prim-key-class>java.lang.Integer</prim-key-class>
+          <reentrant>false</reentrant>
+          <cmp-version>2.x</cmp-version>
+          <abstract-schema-name>OneToOneB</abstract-schema-name>
+          <cmp-field>
+              <field-name>field1</field-name>
+          </cmp-field>
+          <cmp-field>
+              <field-name>field2</field-name>
+          </cmp-field>
+          <cmp-field>
+              <field-name>field3</field-name>
+          </cmp-field>
+          <cmp-field>
+              <field-name>field4</field-name>
+          </cmp-field>
+          <primkey-field>field1</primkey-field>
+          <query>
+              <!-- CompondPK one-to-one shares the local home interface so we need to declare this useless finder -->
+              <query-method>
+                  <method-name>findByPrimaryKey</method-name>
+                  <method-params>
+                      <method-param>org.apache.openejb.deployment.entity.cmr.CompoundPK</method-param>
+                  </method-params>
+              </query-method>
+              <ejb-ql>SELECT OBJECT(B) FROM OneToManyB B</ejb-ql>
+          </query>
+      </entity>
+
         <entity>
             <ejb-name>OneOwningSideBean</ejb-name>
             <local-home>org.apache.openejb.test.entity.cmr.cmrmapping.OneOwningSideLocalHome</local-home>
@@ -1735,9 +1798,7 @@
 
     <relationships>
         <ejb-relation>
-            <ejb-relation-name>relation</ejb-relation-name>
             <ejb-relationship-role>
-                <ejb-relationship-role-name>OneToOneASide</ejb-relationship-role-name>
                 <multiplicity>One</multiplicity>
                 <cascade-delete/>
                 <relationship-role-source>
@@ -1748,7 +1809,6 @@
                 </cmr-field>
             </ejb-relationship-role>
             <ejb-relationship-role>
-                <ejb-relationship-role-name>OneToOneBSide</ejb-relationship-role-name>
                 <multiplicity>One</multiplicity>
                 <relationship-role-source>
                     <ejb-name>OneToOneB</ejb-name>
@@ -1762,6 +1822,26 @@
             <ejb-relationship-role>
                 <multiplicity>One</multiplicity>
                 <relationship-role-source>
+                    <ejb-name>OneToManyA</ejb-name>
+                </relationship-role-source>
+                <cmr-field>
+                    <cmr-field-name>b</cmr-field-name>
+                </cmr-field>
+            </ejb-relationship-role>
+            <ejb-relationship-role>
+                <multiplicity>Many</multiplicity>
+                <relationship-role-source>
+                    <ejb-name>OneToManyB</ejb-name>
+                </relationship-role-source>
+                <cmr-field>
+                    <cmr-field-name>a</cmr-field-name>
+                </cmr-field>
+            </ejb-relationship-role>
+        </ejb-relation>
+        <ejb-relation>
+            <ejb-relationship-role>
+                <multiplicity>One</multiplicity>
+                <relationship-role-source>
                     <ejb-name>OneOwningSideBean</ejb-name>
                 </relationship-role-source>
                 <cmr-field>
@@ -1894,6 +1974,20 @@
         <container-transaction>
             <method>
                 <ejb-name>OneToOneB</ejb-name>
+                <method-name>*</method-name>
+            </method>
+            <trans-attribute>Required</trans-attribute>
+        </container-transaction>
+        <container-transaction>
+            <method>
+                <ejb-name>OneToManyA</ejb-name>
+                <method-name>*</method-name>
+            </method>
+            <trans-attribute>Required</trans-attribute>
+        </container-transaction>
+        <container-transaction>
+            <method>
+                <ejb-name>OneToManyB</ejb-name>
                 <method-name>*</method-name>
             </method>
             <trans-attribute>Required</trans-attribute>

Modified: incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/jpa.mapping.xml
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/jpa.mapping.xml?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/jpa.mapping.xml (original)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/jpa.mapping.xml Tue Dec 12 20:08:39 2006
@@ -293,4 +293,51 @@
       </one-to-one>
     </attributes>
   </entity>
+
+  <!--
+  ########################################################
+  ########################################################
+  ######  CMR  One To Many ###############################
+  ########################################################
+  ########################################################
+  -->
+
+  <entity name="OneToManyA" class="org.apache.openejb.test.entity.cmr.onetomany.ABean_JPA">
+    <table name="OneToManyA"/>
+    <attributes>
+      <id name="field1">
+        <column name="A1"/>
+      </id>
+      <basic name="field2">
+        <column name="A2"/>
+      </basic>
+      <one-to-many name="b" mapped-by="a">
+        <map-key name="field1"/>
+      </one-to-many>
+    </attributes>
+  </entity>
+
+  <entity name="OneToManyB" class="org.apache.openejb.test.entity.cmr.onetomany.BBean_JPA">
+    <table name="OneToManyB"/>
+    <attributes>
+      <id name="field1">
+        <column name="B1"/>
+      </id>
+      <basic name="field2">
+        <column name="B2"/>
+      </basic>
+      <basic name="field3">
+        <column name="B3"/>
+      </basic>
+      <basic name="field4">
+        <column name="B4"/>
+      </basic>
+      <many-to-one name="a">
+        <join-column name="FKA1"/>
+        <cascade>
+          <cascade-all/>
+        </cascade>
+      </many-to-one>
+    </attributes>
+  </entity>
 </entity-mappings>

Modified: incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/openejb-jar.xml
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/openejb-jar.xml?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/openejb-jar.xml (original)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-beans/src/main/resources/META-INF/openejb-jar.xml Tue Dec 12 20:08:39 2006
@@ -127,6 +127,8 @@
   <!-- CMR Test Beans -->
 	<ejb-deployment ejb-name="OneToOneA" deployment-id="client/tests/entity/cmr/oneToOne/AHome" container-id="Default CMP Container"/>
 	<ejb-deployment ejb-name="OneToOneB" deployment-id="client/tests/entity/cmr/oneToOne/BHome" container-id="Default CMP Container"/>
+  <ejb-deployment ejb-name="OneToManyA" deployment-id="client/tests/entity/cmr/oneToMany/AHome" container-id="Default CMP Container"/>
+  <ejb-deployment ejb-name="OneToManyB" deployment-id="client/tests/entity/cmr/oneToMany/BHome" container-id="Default CMP Container"/>
 	<ejb-deployment ejb-name="OneOwningSideBean" deployment-id="client/tests/entity/cmp2/OneOwningSideBean/EJBHome" container-id="Default CMP Container"/>
 	<ejb-deployment ejb-name="OneInverseSideBean" deployment-id="client/tests/entity/cmp2/OneInverseSideBean/EJBHome" container-id="Default CMP Container"/>
 	<ejb-deployment ejb-name="ManyOwningSideBean" deployment-id="client/tests/entity/cmp2/ManyOwningSideBean/EJBHome" container-id="Default CMP Container"/>

Modified: incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/HsqldbTestDatabase.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/HsqldbTestDatabase.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/HsqldbTestDatabase.java (original)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/HsqldbTestDatabase.java Tue Dec 12 20:08:39 2006
@@ -43,6 +43,12 @@
     private static final String CREATE_ONE_TO_ONE_B = "CREATE TABLE OneToOneB(B1 INTEGER, B2 VARCHAR(50), B3 INTEGER, B4 VARCHAR(50), FKA1 INTEGER)";
     private static final String DROP_ONE_TO_ONE_B = "DROP TABLE OneToOneB";
 
+    // OneToMany
+    private static final String CREATE_ONE_TO_MANY_A = "CREATE TABLE OneToManyA(A1 INTEGER, A2 VARCHAR(50))";
+    private static final String DROP_ONE_TO_MANY_A = "DROP TABLE OneToManyA";
+    private static final String CREATE_ONE_TO_MANY_B = "CREATE TABLE OneToManyB(B1 INTEGER, B2 VARCHAR(50), B3 INTEGER, B4 VARCHAR(50), FKA1 INTEGER)";
+    private static final String DROP_ONE_TO_MANY_B = "DROP TABLE OneToManyB";
+
     // CmrMapping
     private static final String CREATE_ONE_OWNING = "CREATE TABLE oneowning (col_id INTEGER, col_field1 INTEGER)";
     private static final String DROP_ONE_OWNING = "DROP TABLE oneowning";
@@ -60,6 +66,8 @@
         createTable(_createEntity, _dropEntity);
         createTable(CREATE_ONE_TO_ONE_A, DROP_ONE_TO_ONE_A);
         createTable(CREATE_ONE_TO_ONE_B, DROP_ONE_TO_ONE_B);
+        createTable(CREATE_ONE_TO_MANY_A, DROP_ONE_TO_MANY_A);
+        createTable(CREATE_ONE_TO_MANY_B, DROP_ONE_TO_MANY_B);
         createTable(CREATE_ONE_OWNING, DROP_ONE_OWNING);
         createTable(CREATE_ONE_INVERSE, DROP_ONE_INVERSE);
         createTable(CREATE_MANY_OWNING, DROP_MANY_OWNING);
@@ -69,6 +77,8 @@
         dropTable(_dropEntity);
         dropTable(DROP_ONE_TO_ONE_A);
         dropTable(DROP_ONE_TO_ONE_B);
+        dropTable(DROP_ONE_TO_MANY_A);
+        dropTable(DROP_ONE_TO_MANY_B);
         dropTable(DROP_ONE_OWNING);
         dropTable(DROP_ONE_INVERSE);
         dropTable(DROP_MANY_OWNING);

Modified: incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/AbstractCMRTest.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/AbstractCMRTest.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/AbstractCMRTest.java (original)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/AbstractCMRTest.java Tue Dec 12 20:08:39 2006
@@ -27,6 +27,11 @@
 import javax.naming.InitialContext;
 import javax.naming.Context;
 import java.util.Properties;
+import java.sql.SQLException;
+import java.sql.Connection;
+import java.sql.Statement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
 
 import org.apache.openejb.test.TestManager;
 
@@ -71,6 +76,59 @@
         InitialContext jndiContext = new InitialContext( );
         transactionManager = (TransactionManager) jndiContext.lookup("java:openejb/TransactionManager");
         ds = (DataSource) jndiContext.lookup("java:openejb/connector/Default JDBC Database");
+    }
+
+    protected static void dumpTable(DataSource ds, String table) throws SQLException {
+        Connection connection = null;
+        Statement statement = null;
+        ResultSet resultSet = null;
+        try {
+            connection = ds.getConnection();
+            statement = connection.createStatement();
+            resultSet = statement.executeQuery("SELECT * FROM " + table);
+            ResultSetMetaData setMetaData = resultSet.getMetaData();
+            int columnCount = setMetaData.getColumnCount();
+            while(resultSet.next()) {
+                StringBuilder row = new StringBuilder();
+                for (int i = 1; i <= columnCount; i++) {
+                    if (i > 1) {
+                        row.append(", ");
+                    }
+                    String name = setMetaData.getColumnName(i);
+                    Object value = resultSet.getObject(i);
+                    row.append(name).append("=").append(value);
+                }
+                System.out.println(row);
+            }
+        } finally {
+            close(resultSet);
+            close(statement);
+            close(connection);
+        }
+    }
+
+    protected static void close(ResultSet resultSet) {
+        if (resultSet == null) return;
+        try {
+            resultSet.close();
+        } catch (SQLException e) {
+        }
+    }
+
+    protected static void close(Statement statement) {
+        if (statement == null) return;
+        try {
+            statement.close();
+        } catch (SQLException e) {
+        }
+    }
+
+    protected static void close(Connection connection) {
+        if (connection == null) return;
+        try {
+            connection.close();
+        } catch (SQLException e) {
+        }
     }
 }
 

Modified: incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/CmrTestSuite.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/CmrTestSuite.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/CmrTestSuite.java (original)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/CmrTestSuite.java Tue Dec 12 20:08:39 2006
@@ -28,7 +28,7 @@
     public CmrTestSuite() {
         super();
         this.addTest(new OneToOneTests());
-//        this.addTest(new OneToManyTests());
+        this.addTest(new OneToManyTests());
 //        this.addTest(new ManyToManyTests());
 //        this.addTest(new OneToOneCompoundPKTests());
 //        this.addTest(new OneToManyCompoundPKTests());

Modified: incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/OneToManyTests.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/OneToManyTests.java?view=diff&rev=486483&r1=486482&r2=486483
==============================================================================
--- incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/OneToManyTests.java (original)
+++ incubator/openejb/trunk/openejb3/itests/openejb-itests-client/src/main/java/org/apache/openejb/test/entity/cmr/OneToManyTests.java Tue Dec 12 20:08:39 2006
@@ -16,28 +16,26 @@
  */
 package org.apache.openejb.test.entity.cmr;
 
+import org.apache.openejb.test.entity.cmr.onetomany.ALocal;
+import org.apache.openejb.test.entity.cmr.onetomany.ALocalHome;
+import org.apache.openejb.test.entity.cmr.onetomany.BLocal;
+import org.apache.openejb.test.entity.cmr.onetomany.BLocalHome;
+
+import javax.ejb.FinderException;
+import javax.ejb.CreateException;
 import java.sql.Connection;
 import java.sql.ResultSet;
-import java.sql.SQLException;
 import java.sql.Statement;
+import java.sql.SQLException;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Set;
 
-import org.apache.openejb.test.entity.cmr.onetomany.ALocalHome;
-import org.apache.openejb.test.entity.cmr.onetomany.ALocal;
-import org.apache.openejb.test.entity.cmr.onetomany.BLocalHome;
-import org.apache.openejb.test.entity.cmr.onetomany.BLocal;
-
 /**
- *
  * @version $Revision: 451417 $ $Date: 2006-09-29 13:13:22 -0700 (Fri, 29 Sep 2006) $
  */
 public class OneToManyTests extends AbstractCMRTest {
     private ALocalHome ahome;
-    private ALocal a;
     private BLocalHome bhome;
-    private BLocal b;
 
     public OneToManyTests() {
         super("OneToMany.");
@@ -46,289 +44,320 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        ahome = (ALocalHome) initialContext.lookup("client/tests/entity/cmr/oneToMany/ALocalHome");
-        bhome = (BLocalHome) initialContext.lookup("client/tests/entity/cmr/oneToMany/BLocalHome");
+        ahome = (ALocalHome) initialContext.lookup("client/tests/entity/cmr/oneToMany/AHomeLocal");
+        bhome = (BLocalHome) initialContext.lookup("client/tests/entity/cmr/oneToMany/BHomeLocal");
     }
 
-    public void testAGetBExistingAB() throws Exception {
+    public void test00_AGetBExistingAB() throws Exception {
+        resetDB();
         beginTransaction();
-        ALocal a = ahome.findByPrimaryKey(new Integer(1));
-        Set bSet = a.getB();
-        assertEquals(2, bSet.size());
-        for (Iterator iter = bSet.iterator(); iter.hasNext();) {
-            BLocal b = (BLocal) iter.next();
-            if ( b.getField1().equals(new Integer(11)) ) {
-                assertEquals("value11", b.getField2());
-            } else if ( b.getField1().equals(new Integer(22)) ) {
-                assertEquals("value22", b.getField2());
-            } else {
-                fail();
+        try {
+            ALocal a = findA(1);
+            Set bSet = a.getB();
+            assertEquals(2, bSet.size());
+            for (Object value : bSet) {
+                BLocal b = (BLocal) value;
+                if (b.getField1().equals(new Integer(11))) {
+                    assertEquals("value11", b.getField2());
+                } else if (b.getField1().equals(new Integer(22))) {
+                    assertEquals("value22", b.getField2());
+                } else {
+                    fail();
+                }
             }
+        } finally {
+            completeTransaction();
         }
-        completeTransaction();
     }
 
-    public void testBGetAExistingAB() throws Exception {
+    public void test01_BGetAExistingAB() throws Exception {
+        resetDB();
         beginTransaction();
-        BLocal b = bhome.findByPrimaryKey(new Integer(11));
-        ALocal a = b.getA();
-        assertNotNull(a);
-        assertEquals(new Integer(1), a.getField1());
-        assertEquals("value1", a.getField2());
-
-        b = bhome.findByPrimaryKey(new Integer(22));
-        a = b.getA();
-        assertNotNull(a);
-        assertEquals(new Integer(1), a.getField1());
-        assertEquals("value1", a.getField2());
-        completeTransaction();
+        try {
+            BLocal b = findB(11);
+            ALocal a = b.getA();
+            assertNotNull(a);
+            assertEquals(new Integer(1), a.getField1());
+            assertEquals("value1", a.getField2());
+
+            b = findB(22);
+            a = b.getA();
+            assertNotNull(a);
+            assertEquals(new Integer(1), a.getField1());
+            assertEquals("value1", a.getField2());
+        } finally {
+            completeTransaction();
+        }
     }
 
-    private void assertStateDropExisting() throws Exception {
-        Connection c = ds.getConnection();
-        Statement s = c.createStatement();
-        ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM B WHERE fka1 = 1");
-        assertTrue(rs.next());
-        assertEquals(0, rs.getInt(1));
-        rs.close();
-        s.close();
-        c.close();
+    public void testASetBDropExisting() throws Exception {
+        resetDB();
+        beginTransaction();
+        try {
+            ALocal a = findA(1);
+            a.setB(new HashSet<BLocal>());
+        } finally {
+            completeTransaction();
+        }
+        assertUnlinked(1);
     }
 
-    /**
-     * TODO Disabled due to an Axion bug. It has been tested with another
-     * DB DataSource successfully.
-     */
-    public void XtestASetBDropExisting() throws Exception {
+    public void testBSetADropExisting() throws Exception {
+        resetDB();
         beginTransaction();
-        ALocal a = ahome.findByPrimaryKey(new Integer(1));
-        a.setB(new HashSet<BLocal>());
-        completeTransaction();
+        try {
+            BLocal b = findB(11);
+            b.setA(null);
+            b = findB(22);
+            b.setA(null);
+        } finally {
+            completeTransaction();
+        }
 
-        assertStateDropExisting();
+        assertUnlinked(1);
     }
 
-    /**
-     * TODO Disabled due to an Axion bug. It has been tested with another
-     * DB DataSource successfully.
-     */
-    public void XtestBSetADropExisting() throws Exception {
+
+    public void testASetBNewAB() throws Exception {
+        resetDB();
         beginTransaction();
-        BLocal b = bhome.findByPrimaryKey(new Integer(11));
-        b.setA(null);
-        b = bhome.findByPrimaryKey(new Integer(22));
-        b.setA(null);
-        completeTransaction();
+        try {
+            ALocal a = findA(2);
+            BLocal b = findB(22);
+            Set<BLocal> bSet = new HashSet<BLocal>();
+            bSet.add(b);
+            a.setB(bSet);
+        } finally {
+            completeTransaction();
+        }
 
-        assertStateDropExisting();
+        assertLinked(2, 22);
     }
 
-    private void prepareNewAB() throws Exception {
+    public void testBSetANewAB() throws Exception {
+        resetDB();
         beginTransaction();
-        a = ahome.create(new Integer(2));
-        a.setField2("value2");
-        b = bhome.create(new Integer(22));
-        b.setField2("value22");
+        try {
+            ALocal a = findA(2);
+            BLocal b = findB(22);
+            b.setA(a);
+        } finally {
+            completeTransaction();
+        }
+        assertLinked(2, 22);
     }
 
-    private void assertStateNewAB() throws Exception {
-        Connection c = ds.getConnection();
-        Statement s = c.createStatement();
-        ResultSet rs = s.executeQuery("SELECT a2 FROM A WHERE a1 = 2");
-        assertTrue(rs.next());
-        assertEquals("value2", rs.getString(1));
-        rs.close();
+    public void testASetBExistingBNewA() throws Exception {
+        resetDB();
+        beginTransaction();
+        try {
+            ALocal a = findA(2);
+            BLocal b = findB(11);
+            Set<BLocal> bSet = a.getB();
+            bSet.add(b);
+        } finally {
+            completeTransaction();
+        }
 
-        rs = s.executeQuery("SELECT b1, b2 FROM B WHERE fka1 = 2");
-        assertTrue(rs.next());
-        assertEquals(22, rs.getInt(1));
-        assertEquals("value22", rs.getString(2));
-        rs.close();
-        s.close();
-        c.close();
+        assertLinked(2, 11);
     }
 
-    public void testASetBNewAB() throws Exception {
-        prepareNewAB();
-        Set<BLocal> bSet = new HashSet<BLocal>();
-        bSet.add(b);
-        a.setB(bSet);
-        completeTransaction();
+    public void testBSetAExistingBNewA() throws Exception {
+        resetDB();
+        beginTransaction();
+        try {
+            ALocal a = findA(2);
+            BLocal b = findB(11);
+            b.setA(a);
+        } finally {
+            completeTransaction();
+        }
 
-        assertStateNewAB();
+        assertLinked(2, 11);
     }
 
-    public void testBSetANewAB() throws Exception {
-        prepareNewAB();
-        b.setA(a);
-        completeTransaction();
-
-        assertStateNewAB();
+    public void testASetBExistingANewB() throws Exception {
+        resetDB();
+        beginTransaction();
+        try {
+            ALocal a = findA(1);
+            BLocal b = createB(33);
+            Set<BLocal> bSet = a.getB();
+            bSet.add(b);
+        } finally {
+            completeTransaction();
+        }
+        assertLinked(1, 11, 22, 33);
     }
 
-    private void prepareExistingBNewA() throws Exception {
+    public void testBSetAExistingANewB() throws Exception {
+        resetDB();
         beginTransaction();
-        a = ahome.create(new Integer(2));
-        a.setField2("value2");
-        b = bhome.findByPrimaryKey(new Integer(11));
+        try {
+            ALocal a = findA(1);
+            BLocal b = createB(33);
+            b.setA(a);
+        } finally {
+            completeTransaction();
+        }
+
+        assertLinked(1, 11, 22, 33);
     }
 
-    private void assertStateExistingBNewA() throws Exception {
+    public void testRemoveRelationships() throws Exception {
+        resetDB();
+        beginTransaction();
+        try {
+            ALocal a = findA(1);
+            a.remove();
+        } finally {
+            completeTransaction();
+        }
+
         Connection c = ds.getConnection();
         Statement s = c.createStatement();
-        ResultSet rs = s.executeQuery("SELECT a2 FROM A WHERE a1 = 2");
+        ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM OneToManyB");
         assertTrue(rs.next());
-        assertEquals("value2", rs.getString(1));
+        assertEquals(2, rs.getInt(1));
         rs.close();
-
-        rs = s.executeQuery("SELECT b1, b2 FROM B WHERE fka1 = 2");
+        rs = s.executeQuery("SELECT COUNT(*) FROM OneToManyB WHERE fka1 = 1");
         assertTrue(rs.next());
-        assertEquals(11, rs.getInt(1));
-        assertEquals("value11", rs.getString(2));
+        assertEquals(0, rs.getInt(1));
         rs.close();
         s.close();
         c.close();
     }
 
-    public void testASetBExistingBNewA() throws Exception {
-        prepareExistingBNewA();
-        Set<BLocal> bSet = a.getB();
-        bSet.add(b);
-        completeTransaction();
+    // uncomment when cmp to cmr is supported
+    public void TODO_testCMPMappedToForeignKeyColumn() throws Exception {
+        resetDB();
+        beginTransaction();
+        try {
+            BLocal b = findB(11);
 
-        assertStateExistingBNewA();
+            Integer field3 = b.getField3();
+            assertEquals(b.getA().getPrimaryKey(), field3);
+        } finally {
+            completeTransaction();
+        }
     }
 
-    public void testBSetAExistingBNewA() throws Exception {
-        prepareExistingBNewA();
-        b.setA(a);
-        completeTransaction();
+    // uncomment when cmp to cmr is supported
+    public void TODO_testSetCMPMappedToForeignKeyColumn() throws Exception {
+        resetDB();
+        beginTransaction();
+        try {
+            BLocal b = findB(11);
 
-        assertStateExistingBNewA();
-    }
+            b.setField3(new Integer(2));
 
-    private void prepareExistingANewB() throws Exception {
-        beginTransaction();
-        a = ahome.findByPrimaryKey(new Integer(1));
-        b = bhome.create(new Integer(33));
-        b.setField2("value33");
+            ALocal a = b.getA();
+            assertEquals(new Integer(2), a.getField1());
+            assertEquals("value2", a.getField2());
+        } finally {
+            completeTransaction();
+        }
     }
 
-    private void assertStateExistingANewB() throws Exception {
+    // todo cascade delete isn't working
+    public void TODO_testCascadeDelete() throws Exception {
+        resetDB();
+
+        beginTransaction();
+        try {
+            ALocal a = findA(1);
+            a.remove();
+        } finally {
+            completeTransaction();
+        }
+        System.out.println();
         Connection c = ds.getConnection();
         Statement s = c.createStatement();
-        ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM B WHERE fka1 = 1");
+        ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM OneToManyB");
         assertTrue(rs.next());
-        assertEquals(3, rs.getInt(1));
-
-        rs = s.executeQuery("SELECT COUNT(*) FROM B WHERE fka1 = 1 AND b1 = 33 AND b2 = 'value33'");
-        assertTrue(rs.next());
-        assertEquals(1, rs.getInt(1));
+        assertEquals(0, rs.getInt(1));
         rs.close();
         s.close();
         c.close();
     }
 
-    public void testASetBExistingANewB() throws Exception {
-        prepareExistingANewB();
-        Set<BLocal> bSet = a.getB();
-        bSet.add(b);
-        completeTransaction();
+//    private ALocal createA(int aPk) throws CreateException {
+//        ALocal a = ahome.create(new Integer(aPk));
+//        a.setField2("value" + aPk);
+//        return a;
+//    }
 
-        assertStateExistingANewB();
+    private ALocal findA(int aPk) throws FinderException {
+        return ahome.findByPrimaryKey(new Integer(aPk));
     }
 
-    public void testBSetAExistingANewB() throws Exception {
-        prepareExistingANewB();
-        b.setA(a);
-        completeTransaction();
-
-        assertStateExistingANewB();
-    }
-
-    /**
-     * TODO Disabled due to an Axion bug. It has been tested with another
-     * DB DataSource successfully.
-     */
-    public void XtestRemoveRelationships() throws Exception {
-        beginTransaction();
-        ALocal a = ahome.findByPrimaryKey(new Integer(1));
-        a.remove();
-        completeTransaction();
+    private BLocal createB(int bPk) throws CreateException {
+        BLocal b = bhome.create(new Integer(bPk));
+        b.setField2("value" + bPk);
+        return b;
+    }
+    private BLocal findB(int bPk) throws FinderException {
+        return bhome.findByPrimaryKey(new Integer(bPk));
+    }
 
+    private void assertLinked(int aPk, int... bPks) throws Exception {
         Connection c = ds.getConnection();
         Statement s = c.createStatement();
-        ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM B");
+        ResultSet rs = s.executeQuery("SELECT a2 FROM OneToManyA WHERE a1 = " + aPk);
         assertTrue(rs.next());
-        assertEquals(2, rs.getInt(1));
-        rs.close();
-        rs = s.executeQuery("SELECT COUNT(*) FROM B WHERE fka1 = 1");
+        assertEquals("value" + aPk, rs.getString("a2"));
+        close(rs);
+
+        // assert that there we are looking for the same number of linked beans
+        rs = s.executeQuery("SELECT COUNT(*) FROM OneToManyB WHERE fka1 = 1");
         assertTrue(rs.next());
-        assertEquals(0, rs.getInt(1));
+        assertEquals(bPks.length, rs.getInt(1));
         rs.close();
-        s.close();
-        c.close();
-    }
-
-    public void testCMPMappedToForeignKeyColumn() throws Exception {
-        beginTransaction();
-        BLocal b = bhome.findByPrimaryKey(new Integer(11));
-
-        Integer field3 = b.getField3();
-        assertEquals(b.getA().getPrimaryKey(), field3);
-        completeTransaction();
-    }
-
-    public void testSetCMPMappedToForeignKeyColumn() throws Exception {
-        beginTransaction();
-        BLocal b = bhome.findByPrimaryKey(new Integer(11));
-
-        b.setField3(new Integer(2));
-
-        ALocal a = b.getA();
-        assertEquals(new Integer(2), a.getField1());
-        assertEquals("value2", a.getField2());
 
-        completeTransaction();
+        // assert each of the listed b pks is linked to a
+        for (int bPk : bPks) {
+            rs = s.executeQuery("SELECT b2, fka1 FROM OneToManyB WHERE b1 = " + bPk);
+            assertTrue(rs.next());
+            assertEquals("value" + bPk, rs.getString("b2"));
+            assertEquals(aPk, rs.getInt("fka1"));
+            close(rs);
+        }
+        close(s);
+        close(c);
     }
 
-    public void testCascadeDelete() throws Exception {
-        beginTransaction();
-        ALocal a = ahome.findByPrimaryKey(new Integer(1));
-        a.remove();
-        completeTransaction();
-
+    private void assertUnlinked(int aPk) throws Exception {
         Connection c = ds.getConnection();
         Statement s = c.createStatement();
-        ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM B");
+        ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM OneToManyB WHERE fka1 = " + aPk);
         assertTrue(rs.next());
         assertEquals(0, rs.getInt(1));
-        rs.close();
-        s.close();
-        c.close();
+        close(rs);
+        close(s);
+        close(c);
     }
 
-    protected void buildDBSchema(Connection c) throws Exception {
-        Statement s = c.createStatement();
+    private void resetDB() throws Exception {
+        Connection connection = ds.getConnection();
+        Statement statement = null;
         try {
-            s.execute("DROP TABLE A");
-        } catch (SQLException e) {
-            // ignore
-        }
-        try {
-            s.execute("DROP TABLE B");
-        } catch (SQLException e) {
-            // ignore
-        }
+            statement = connection.createStatement();
 
-        s.execute("CREATE TABLE A(A1 INTEGER, A2 VARCHAR(50))");
-        s.execute("CREATE TABLE B(B1 INTEGER, B2 VARCHAR(50), FKA1 INTEGER)");
+            statement.execute("DELETE FROM OneToManyA");
+            statement.execute("DELETE FROM OneToManyB");
 
-        s.execute("INSERT INTO A(A1, A2) VALUES(1, 'value1')");
-        s.execute("INSERT INTO A(A1, A2) VALUES(2, 'value2')");
-        s.execute("INSERT INTO B(B1, B2, FKA1) VALUES(11, 'value11', 1)");
-        s.execute("INSERT INTO B(B1, B2, FKA1) VALUES(22, 'value22', 1)");
-        s.close();
-        c.close();
+            statement.execute("INSERT INTO OneToManyA(A1, A2) VALUES(1, 'value1')");
+            statement.execute("INSERT INTO OneToManyA(A1, A2) VALUES(2, 'value2')");
+            statement.execute("INSERT INTO OneToManyB(B1, B2, FKA1) VALUES(11, 'value11', 1)");
+            statement.execute("INSERT INTO OneToManyB(B1, B2, FKA1) VALUES(22, 'value22', 1)");
+        } finally {
+            close(statement);
+            close(connection);
+        }
+    }
+
+    private void dump() throws SQLException {
+        dumpTable(ds, "OneToManyA");
+        dumpTable(ds, "OneToManyb");
     }
 }