You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by cl...@apache.org on 2008/09/22 21:00:54 UTC

svn commit: r697950 - in /jackrabbit/trunk/jackrabbit-ocm/src: main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/ test/java/org/apache/jackrabbit/ocm/manager/collectionconverter/ test/java/org/apache/jackrabbit/ocm/testmodel/collection/

Author: clombart
Date: Mon Sep 22 12:00:54 2008
New Revision: 697950

URL: http://svn.apache.org/viewvc?rev=697950&view=rev
Log:
Patch provided by Vincent Giguère for issue JCR-1645 ( Add support for Map of referenced beans). I made some modifications in the test content class Main otherwise it doesnt't compile. 

Added:
    jackrabbit/trunk/jackrabbit-ocm/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/BeanReferenceMapConverterImpl.java
    jackrabbit/trunk/jackrabbit-ocm/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/MapReferenceValueEncoder.java
    jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/manager/collectionconverter/BeanReferenceMapConverterImplTest.java
    jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/manager/collectionconverter/MapReferenceValueEncoderTest.java
Modified:
    jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/testmodel/collection/Main.java

Added: jackrabbit/trunk/jackrabbit-ocm/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/BeanReferenceMapConverterImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-ocm/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/BeanReferenceMapConverterImpl.java?rev=697950&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-ocm/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/BeanReferenceMapConverterImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-ocm/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/BeanReferenceMapConverterImpl.java Mon Sep 22 12:00:54 2008
@@ -0,0 +1,214 @@
+/*
+ * 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.jackrabbit.ocm.manager.collectionconverter.impl;
+
+
+import org.apache.jackrabbit.ocm.exception.JcrMappingException;
+import org.apache.jackrabbit.ocm.exception.ObjectContentManagerException;
+import org.apache.jackrabbit.ocm.manager.collectionconverter.ManageableMap;
+import org.apache.jackrabbit.ocm.manager.collectionconverter.ManageableObjects;
+import org.apache.jackrabbit.ocm.manager.collectionconverter.ManageableObjectsUtil;
+import org.apache.jackrabbit.ocm.manager.objectconverter.ObjectConverter;
+import org.apache.jackrabbit.ocm.mapper.Mapper;
+import org.apache.jackrabbit.ocm.mapper.model.ClassDescriptor;
+import org.apache.jackrabbit.ocm.mapper.model.CollectionDescriptor;
+import org.apache.jackrabbit.ocm.mapper.model.FieldDescriptor;
+import org.apache.jackrabbit.ocm.reflection.ReflectionUtils;
+
+import javax.jcr.*;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.version.VersionException;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Map converter used to map reference/uuid property by key into a java.util.Map.
+ * <p/>
+ * This implementation takes for granted that the keys to the map are of type java.lang.String.
+ * <p/>
+ * Further development will be required to fully support Map<Object, Object>.
+ *
+ * @author <a href="mailto:vincent.giguere@gmail.com">Vincent Giguere</a>
+ */
+public class BeanReferenceMapConverterImpl extends AbstractCollectionConverterImpl {
+
+
+    /**
+     * Constructor
+     *
+     * @param atomicTypeConverters
+     * @param objectConverter
+     * @param mapper
+     */
+    public BeanReferenceMapConverterImpl(Map atomicTypeConverters,
+                                         ObjectConverter objectConverter,
+                                         Mapper mapper) {
+        super(atomicTypeConverters, objectConverter, mapper);
+    }
+
+    protected void doInsertCollection(Session session,
+                                      Node parentNode,
+                                      CollectionDescriptor collectionDescriptor,
+                                      ManageableObjects objects) throws RepositoryException {
+
+        // For maps of bean references, only Maps are supported
+        if (!(objects instanceof ManageableMap)) {
+
+            throw new JcrMappingException("Impossible to retrieve the attribute "
+                    + collectionDescriptor.getFieldName() + " in the class "
+                    + collectionDescriptor.getClassDescriptor().getClassName()
+                    + " because it is not a map");
+        }
+
+
+        addUuidProperties(session, parentNode, collectionDescriptor, (ManageableMap) objects);
+    }
+
+
+    protected void doUpdateCollection(Session session,
+                                      Node parentNode,
+                                      CollectionDescriptor collectionDescriptor,
+                                      ManageableObjects objects) throws RepositoryException {
+
+    	// For maps of bean references, only Maps are supported
+        if (!(objects instanceof ManageableMap)) {
+
+            throw new JcrMappingException("Impossible to retrieve the attribute "
+                    + collectionDescriptor.getFieldName() + " in the class "
+                    + collectionDescriptor.getClassDescriptor().getClassName()
+                    + " because it is not a map");
+        }
+        String jcrName = getCollectionJcrName(collectionDescriptor);
+
+        // Delete existing values
+        if (parentNode.hasProperty(jcrName)) {
+            parentNode.setProperty(jcrName, (Value[]) null);
+        }
+
+        if (objects == null) {
+            return;
+        }
+
+        addUuidProperties(session, parentNode, collectionDescriptor, (ManageableMap) objects);
+
+    }
+
+    /**
+     * @see org.apache.jackrabbit.ocm.manager.collectionconverter.impl.AbstractCollectionConverterImpl#doGetCollection(javax.jcr.Session, javax.jcr.Node, org.apache.jackrabbit.ocm.mapper.model.CollectionDescriptor, Class)
+     */
+    protected ManageableObjects doGetCollection(Session session,
+                                                Node parentNode,
+                                                CollectionDescriptor collectionDescriptor,
+                                                Class collectionFieldClass) throws RepositoryException {
+
+
+        try {
+            String jcrName = getCollectionJcrName(collectionDescriptor);
+
+            if (!parentNode.hasProperty(jcrName)) {
+                return null;
+            }
+
+            Property property = parentNode.getProperty(jcrName);
+            Value[] values = property.getValues();
+
+            ManageableObjects objects = ManageableObjectsUtil.getManageableObjects(collectionFieldClass);
+
+            // For maps of bean references, only Maps are supported
+            if (!(objects instanceof ManageableMap)) {
+
+                throw new JcrMappingException("Impossible to retrieve the attribute "
+                        + collectionDescriptor.getFieldName() + " in the class "
+                        + collectionDescriptor.getClassDescriptor().getClassName()
+                        + " because it is not a map");
+            }
+
+            for (int i = 0; i < values.length; i++) {
+
+                String encoded = values[i].getString();
+                String key = MapReferenceValueEncoder.decodeKey(encoded);
+                String uuid = MapReferenceValueEncoder.decodeReference(encoded);
+
+
+                String path = session.getNodeByUUID(uuid).getPath();
+                Object object = objectConverter.getObject(session, path);
+                ((ManageableMap) objects).addObject(key, object);
+            }
+
+            return objects;
+        }
+        catch (Exception e) {
+            throw new ObjectContentManagerException("Cannot get the collection field : "
+                    + collectionDescriptor.getFieldName()
+                    + "for class " + collectionDescriptor.getClassDescriptor().getClassName(), e);
+        }
+    }
+
+    /**
+     * @see org.apache.jackrabbit.ocm.manager.collectionconverter.impl.AbstractCollectionConverterImpl#doIsNull(javax.jcr.Session, javax.jcr.Node, org.apache.jackrabbit.ocm.mapper.model.CollectionDescriptor, Class)
+     */
+    protected boolean doIsNull(Session session, Node parentNode, CollectionDescriptor collectionDescriptor, Class collectionFieldClass) throws RepositoryException {
+        String jcrName = getCollectionJcrName(collectionDescriptor);
+        return !parentNode.hasProperty(jcrName);
+    }
+
+    private void addUuidProperties(Session session, Node parentNode,
+                                   CollectionDescriptor collectionDescriptor,
+                                   ManageableMap manageableMap)
+            throws UnsupportedRepositoryOperationException, RepositoryException, VersionException, LockException, ConstraintViolationException {
+        try {
+            if (manageableMap == null) {
+                return;
+            }
+
+            String jcrName = getCollectionJcrName(collectionDescriptor);
+            Value[] values = new Value[manageableMap.getSize()];
+            ValueFactory valueFactory = session.getValueFactory();
+            Map map = (Map) manageableMap.getObjects(); 
+            Iterator keyIterator = map.keySet().iterator();
+            
+            for (int i = 0; i < manageableMap.getSize(); i++) {
+                String key = (String) keyIterator.next();
+                Object object = map.get(key);
+                if (object != null) {
+                    ClassDescriptor classDescriptor = mapper.getClassDescriptorByClass(object.getClass());
+
+                    FieldDescriptor fieldDescriptor = classDescriptor.getUuidFieldDescriptor();
+                    if (fieldDescriptor == null) {
+                        throw new JcrMappingException("The bean doesn't have an uuid - classdescriptor : "
+                                + classDescriptor.getClassName());
+                    }
+
+                    String uuid = (String) ReflectionUtils.getNestedProperty(object, fieldDescriptor.getFieldName());
+                    values[i] = valueFactory.createValue(MapReferenceValueEncoder.encodeKeyAndReference(key, uuid), PropertyType.STRING);
+                }
+            }
+
+            parentNode.setProperty(jcrName, values);
+
+        }
+        catch (Exception e) {
+            throw new ObjectContentManagerException("Cannot insert collection field : "
+                    + collectionDescriptor.getFieldName()
+                    + " of class "
+                    + collectionDescriptor.getClassDescriptor().getClassName(), e);
+        }
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit-ocm/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/MapReferenceValueEncoder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-ocm/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/MapReferenceValueEncoder.java?rev=697950&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-ocm/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/MapReferenceValueEncoder.java (added)
+++ jackrabbit/trunk/jackrabbit-ocm/src/main/java/org/apache/jackrabbit/ocm/manager/collectionconverter/impl/MapReferenceValueEncoder.java Mon Sep 22 12:00:54 2008
@@ -0,0 +1,42 @@
+/*
+ * 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.jackrabbit.ocm.manager.collectionconverter.impl;
+
+
+public class MapReferenceValueEncoder {
+
+    private final static String PREFIX="OCM:";
+    final static String KEY_TOKEN="MAPKEY:";
+    final static String REFERENCE_TOKEN="MAPVALUE:";
+
+    public static String decodeKey(String encoded)
+    {
+        String[] splitted = encoded.split(PREFIX);
+        return splitted[1].replaceAll(KEY_TOKEN, "");
+    }
+
+    public static String decodeReference(String encoded)
+    {
+        String[] splitted = encoded.split(PREFIX);
+        return splitted[2].replaceAll(REFERENCE_TOKEN, "");
+    }
+    
+    public static String encodeKeyAndReference(String key, String reference)
+    {
+        return PREFIX+KEY_TOKEN+key+PREFIX+REFERENCE_TOKEN+reference;
+    }
+}

Added: jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/manager/collectionconverter/BeanReferenceMapConverterImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/manager/collectionconverter/BeanReferenceMapConverterImplTest.java?rev=697950&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/manager/collectionconverter/BeanReferenceMapConverterImplTest.java (added)
+++ jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/manager/collectionconverter/BeanReferenceMapConverterImplTest.java Mon Sep 22 12:00:54 2008
@@ -0,0 +1,450 @@
+/*
+ * 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.jackrabbit.ocm.manager.collectionconverter;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.ocm.AnnotationTestBase;
+import org.apache.jackrabbit.ocm.RepositoryLifecycleTestSetup;
+import org.apache.jackrabbit.ocm.manager.ObjectContentManager;
+import org.apache.jackrabbit.ocm.testmodel.collection.Main;
+import org.apache.jackrabbit.ocm.testmodel.uuid.A;
+
+import javax.jcr.RepositoryException;
+
+
+/**
+ *
+ * This test validates that the BeanReferenceMapConverterImpl can be used to annotate java.util.Map
+ * that contain beans stored as references.
+ *
+ *
+ * Map converter used to map reference/uuid property by key into a java.util.Map.
+ *
+ *
+ * @author <a href="mailto:vincent.giguere@gmail.com">Vincent Giguère</a>
+ *
+ */
+public class BeanReferenceMapConverterImplTest extends AnnotationTestBase {
+    private final static Log log = LogFactory.getLog(BeanReferenceMapConverterImplTest.class);
+
+    /**
+     * <p>Defines the test case name for junit.</p>
+     *
+     * @param testName The test case name.
+     */
+    public BeanReferenceMapConverterImplTest(String testName) throws Exception {
+        super(testName);
+    }
+
+    public static Test suite() {
+        // All methods starting with "test" will be executed in the test suite.
+        return new RepositoryLifecycleTestSetup(
+                new TestSuite(BeanReferenceMapConverterImplTest.class));
+    }
+
+
+    public void test_map_of_referenced_nodes_is_persisted_and_reloaded_properly() throws RepositoryException {
+        ObjectContentManager ocm = getObjectContentManager();
+
+        this.getSession().getRootNode().addNode("test");
+        this.getSession().getRootNode().addNode("references");
+        this.getSession().save();
+
+        A firstA = new A();
+        A secondA = new A();
+        A thirdA = new A();
+
+        firstA.setPath("/references/a1");
+        secondA.setPath("/references/a2");
+        thirdA.setPath("/references/a3");
+
+        firstA.setStringData("the first");
+        secondA.setStringData("the second");
+        thirdA.setStringData("the third");
+
+        ocm.insert(firstA);
+        ocm.insert(secondA);
+        ocm.insert(thirdA);
+
+        assertNotNull(firstA.getPath());
+        assertNotNull(secondA.getPath());
+        assertNotNull(thirdA.getPath());
+
+        firstA = (A) ocm.getObject(firstA.getPath());
+        secondA = (A) ocm.getObject(secondA.getPath());
+        thirdA = (A) ocm.getObject(thirdA.getPath());
+
+        assertNotNull(firstA.getUuid());
+        assertNotNull(secondA.getUuid());
+        assertNotNull(thirdA.getUuid());
+
+
+        Main main = new Main();
+        main.setPath("/test/1");
+        main.getReferenceMap().put("keyFirst", firstA);
+        main.getReferenceMap().put("keySecond", secondA);
+        main.getReferenceMap().put("keyThird", thirdA);
+
+
+        ocm.insert(main);
+        main = (Main) ocm.getObject(main.getPath());
+
+        assertEquals("Referenced objects in store were not retrieved.", 3, main.getReferenceMap().size());
+        assertNotNull("Reference could not be retrieved by its original key", main.getReferenceMap().get("keyFirst"));
+        assertNotNull("Reference could not be retrieved by its original key", main.getReferenceMap().get("keySecond"));
+        assertNotNull("Reference could not be retrieved by its original key", main.getReferenceMap().get("keyThird"));
+
+
+        assertEquals("the first", main.getReferenceMap().get("keyFirst").getStringData());
+        assertEquals("the second", main.getReferenceMap().get("keySecond").getStringData());
+        assertEquals("the third", main.getReferenceMap().get("keyThird").getStringData());
+
+    }
+
+    public void test_map_can_persist_and_restore_same_node_reference_under_multiple_keys() throws RepositoryException {
+        ObjectContentManager ocm = getObjectContentManager();
+
+        this.getSession().getRootNode().addNode("test");
+        this.getSession().getRootNode().addNode("references");
+        this.getSession().save();
+
+        A firstA = new A();
+
+        firstA.setPath("/references/a1");
+
+        firstA.setStringData("the data");
+
+        ocm.insert(firstA);
+
+        assertNotNull(firstA.getPath());
+
+        firstA = (A) ocm.getObject(firstA.getPath());
+
+        assertNotNull(firstA.getUuid());
+
+        Main main = new Main();
+        main.setPath("/test/1");
+        main.getReferenceMap().put("keyFirst", firstA);
+        main.getReferenceMap().put("keySecond", firstA);
+        main.getReferenceMap().put("keyThird", firstA);
+
+
+        ocm.insert(main);
+        main = (Main) ocm.getObject(main.getPath());
+
+        assertEquals("Referenced objects in store were not retrieved.", 3, main.getReferenceMap().size());
+        assertNotNull("Reference could not be retrieved by its original key", main.getReferenceMap().get("keyFirst"));
+        assertNotNull("Reference could not be retrieved by its original key", main.getReferenceMap().get("keySecond"));
+        assertNotNull("Reference could not be retrieved by its original key", main.getReferenceMap().get("keyThird"));
+
+
+        assertEquals("the data", main.getReferenceMap().get("keyFirst").getStringData());
+        assertEquals("the data", main.getReferenceMap().get("keySecond").getStringData());
+        assertEquals("the data", main.getReferenceMap().get("keyThird").getStringData());
+
+
+    }
+
+
+    public void test_map_keys_are_stored_in_relation_to_referenced_node() throws RepositoryException {
+
+        /**
+         * Make sure that the key to the map is not part of the referenced node.
+         * In the child node realm, using the @Field(id=true) works, but not with referenced nodes, as they can be referenced by many nodes.
+         */
+
+        ObjectContentManager ocm = getObjectContentManager();
+
+        this.getSession().getRootNode().addNode("test");
+        this.getSession().getRootNode().addNode("references");
+        this.getSession().save();
+
+        A firstA = new A();
+        A secondA = new A();
+        A thirdA = new A();
+
+        firstA.setPath("/references/a1");
+        secondA.setPath("/references/a2");
+        thirdA.setPath("/references/a3");
+
+        firstA.setStringData("the first");
+        secondA.setStringData("the second");
+        thirdA.setStringData("the third");
+
+        ocm.insert(firstA);
+        ocm.insert(secondA);
+        ocm.insert(thirdA);
+
+        assertNotNull(firstA.getPath());
+        assertNotNull(secondA.getPath());
+        assertNotNull(thirdA.getPath());
+
+        firstA = (A) ocm.getObject(firstA.getPath());
+        secondA = (A) ocm.getObject(secondA.getPath());
+        thirdA = (A) ocm.getObject(thirdA.getPath());
+
+        assertNotNull(firstA.getUuid());
+        assertNotNull(secondA.getUuid());
+        assertNotNull(thirdA.getUuid());
+
+
+        Main main = new Main();
+        main.setPath("/test/1");
+        main.getReferenceMap().put("keyFirst", firstA);
+        main.getReferenceMap().put("keySecond", secondA);
+        main.getReferenceMap().put("keyThird", thirdA);
+
+
+        Main main2 = new Main();
+        main2.setPath("/test/2");
+        main2.getReferenceMap().put("AnotherkeyFirst", firstA);
+        main2.getReferenceMap().put("AnotherkeySecond", secondA);
+        main2.getReferenceMap().put("AnotherkeyThird", thirdA);
+
+
+        ocm.insert(main);
+        ocm.insert(main2);
+        main = (Main) ocm.getObject(main.getPath());
+        main2 = (Main) ocm.getObject(main2.getPath());
+
+        assertEquals("Referenced objects in store were not retrieved.", 3, main.getReferenceMap().size());
+        assertNotNull("Reference could not be retrieved by its original key", main.getReferenceMap().get("keyFirst"));
+        assertNotNull("Reference could not be retrieved by its original key", main.getReferenceMap().get("keySecond"));
+        assertNotNull("Reference could not be retrieved by its original key", main.getReferenceMap().get("keyThird"));
+
+
+        assertEquals("Referenced objects in store were not retrieved.", 3, main2.getReferenceMap().size());
+        assertNotNull("Reference could not be retrieved by its original key", main2.getReferenceMap().get("AnotherkeyFirst"));
+        assertNotNull("Reference could not be retrieved by its original key", main2.getReferenceMap().get("AnotherkeySecond"));
+        assertNotNull("Reference could not be retrieved by its original key", main2.getReferenceMap().get("AnotherkeyThird"));
+
+        assertEquals("the first", main.getReferenceMap().get("keyFirst").getStringData());
+        assertEquals("the second", main.getReferenceMap().get("keySecond").getStringData());
+        assertEquals("the third", main.getReferenceMap().get("keyThird").getStringData());
+
+        assertEquals("the first", main2.getReferenceMap().get("AnotherkeyFirst").getStringData());
+        assertEquals("the second", main2.getReferenceMap().get("AnotherkeySecond").getStringData());
+        assertEquals("the third", main2.getReferenceMap().get("AnotherkeyThird").getStringData());
+
+    }
+
+    public void test_converter_removes_deleted_nodes_when_updating() throws RepositoryException {
+
+        ObjectContentManager ocm = getObjectContentManager();
+
+        this.getSession().getRootNode().addNode("test");
+        this.getSession().getRootNode().addNode("references");
+        this.getSession().save();
+
+        A firstA = new A();
+        A secondA = new A();
+        A thirdA = new A();
+
+        firstA.setPath("/references/a1");
+        secondA.setPath("/references/a2");
+        thirdA.setPath("/references/a3");
+
+        firstA.setStringData("the first");
+        secondA.setStringData("the second");
+        thirdA.setStringData("the third");
+
+        ocm.insert(firstA);
+        ocm.insert(secondA);
+        ocm.insert(thirdA);
+
+        assertNotNull(firstA.getPath());
+        assertNotNull(secondA.getPath());
+        assertNotNull(thirdA.getPath());
+
+        firstA = (A) ocm.getObject(firstA.getPath());
+        secondA = (A) ocm.getObject(secondA.getPath());
+        thirdA = (A) ocm.getObject(thirdA.getPath());
+
+        assertNotNull(firstA.getUuid());
+        assertNotNull(secondA.getUuid());
+        assertNotNull(thirdA.getUuid());
+
+
+        Main main = new Main();
+        main.setPath("/test/1");
+        main.getReferenceMap().put("keyFirst", firstA);
+        main.getReferenceMap().put("keySecond", secondA);
+        main.getReferenceMap().put("keyThird", thirdA);
+
+
+        ocm.insert(main);
+        main = (Main) ocm.getObject(main.getPath());
+
+        assertEquals("DefaultMapConverterImpl failed to store or reload objects in map property: referencedMap", 3, main.getReferenceMap().size());
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyFirst"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keySecond"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyThird"));
+
+
+        assertEquals("DefaultMapConverterImpl failed to store objects in map", "the first", main.getReferenceMap().get("keyFirst").getStringData());
+        assertEquals("DefaultMapConverterImpl failed to store objects in map", "the second", main.getReferenceMap().get("keySecond").getStringData());
+        assertEquals("DefaultMapConverterImpl failed to store objects in map", "the third", main.getReferenceMap().get("keyThird").getStringData());
+
+
+        main.getReferenceMap().remove("keyFirst");
+        ocm.update(main);
+        main = (Main) ocm.getObject(main.getPath());
+        assertEquals("DefaultMapConverterImpl failed to store or reload objects in map property: referencedMap", 2, main.getReferenceMap().size());
+        assertNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyFirst"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keySecond"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyThird"));
+
+    }
+
+    public void test_converter_adds_new_nodes_when_updating()  throws RepositoryException {
+
+        ObjectContentManager ocm = getObjectContentManager();
+
+        this.getSession().getRootNode().addNode("test");
+        this.getSession().getRootNode().addNode("references");
+        this.getSession().save();
+
+        A firstA = new A();
+        A secondA = new A();
+        A thirdA = new A();
+
+        firstA.setPath("/references/a1");
+        secondA.setPath("/references/a2");
+        thirdA.setPath("/references/a3");
+
+        firstA.setStringData("the first");
+        secondA.setStringData("the second");
+        thirdA.setStringData("the third");
+
+        ocm.insert(firstA);
+        ocm.insert(secondA);
+        ocm.insert(thirdA);
+
+        assertNotNull(firstA.getPath());
+        assertNotNull(secondA.getPath());
+        assertNotNull(thirdA.getPath());
+
+        firstA = (A) ocm.getObject(firstA.getPath());
+        secondA = (A) ocm.getObject(secondA.getPath());
+        thirdA = (A) ocm.getObject(thirdA.getPath());
+
+        assertNotNull(firstA.getUuid());
+        assertNotNull(secondA.getUuid());
+        assertNotNull(thirdA.getUuid());
+
+
+        Main main = new Main();
+        main.setPath("/test/1");
+        main.getReferenceMap().put("keyFirst", firstA);
+        main.getReferenceMap().put("keySecond", secondA);
+        
+
+
+        ocm.insert(main);
+        main = (Main) ocm.getObject(main.getPath());
+
+        assertEquals("DefaultMapConverterImpl failed to store or reload objects in map property: referencedMap", 2, main.getReferenceMap().size());
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyFirst"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keySecond"));
+        assertNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyThird"));
+
+
+        main.getReferenceMap().put("keyThird", thirdA);
+        ocm.update(main);
+        main = (Main) ocm.getObject(main.getPath());
+        assertEquals("DefaultMapConverterImpl failed to store or reload objects in map property: referencedMap", 3, main.getReferenceMap().size());
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyFirst"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keySecond"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyThird"));
+    }
+
+    public void test_converter_can_add_and_remove_nodes_simultaneously_when_updating() throws RepositoryException {
+
+          ObjectContentManager ocm = getObjectContentManager();
+
+        this.getSession().getRootNode().addNode("test");
+        this.getSession().getRootNode().addNode("references");
+        this.getSession().save();
+
+        A firstA = new A();
+        A secondA = new A();
+        A thirdA = new A();
+        A fourthA = new A();
+
+        firstA.setPath("/references/a1");
+        secondA.setPath("/references/a2");
+        thirdA.setPath("/references/a3");
+        fourthA.setPath("/references/a4");
+
+        firstA.setStringData("the first");
+        secondA.setStringData("the second");
+        thirdA.setStringData("the third");
+
+        ocm.insert(firstA);
+        ocm.insert(secondA);
+        ocm.insert(thirdA);
+        ocm.insert(fourthA);
+
+        assertNotNull(firstA.getPath());
+        assertNotNull(secondA.getPath());
+        assertNotNull(thirdA.getPath());
+        assertNotNull(fourthA.getPath());
+
+        firstA = (A) ocm.getObject(firstA.getPath());
+        secondA = (A) ocm.getObject(secondA.getPath());
+        thirdA = (A) ocm.getObject(thirdA.getPath());
+        fourthA = (A) ocm.getObject(fourthA.getPath());
+
+        assertNotNull(firstA.getUuid());
+        assertNotNull(secondA.getUuid());
+        assertNotNull(thirdA.getUuid());
+        assertNotNull(fourthA.getUuid());
+
+
+        Main main = new Main();
+        main.setPath("/test/1");
+        main.getReferenceMap().put("keyFirst", firstA);
+        main.getReferenceMap().put("keySecond", secondA);
+        main.getReferenceMap().put("keyThird", thirdA);
+
+
+
+        ocm.insert(main);
+        main = (Main) ocm.getObject(main.getPath());
+
+        assertEquals("DefaultMapConverterImpl failed to store or reload objects in map property: referencedMap", 3, main.getReferenceMap().size());
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyFirst"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keySecond"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyThird"));
+        assertNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyFourth"));
+
+
+        main.getReferenceMap().put("keyFourth", fourthA);
+        main.getReferenceMap().remove("keyFirst");
+        ocm.update(main);
+        main = (Main) ocm.getObject(main.getPath());
+        
+        assertEquals("DefaultMapConverterImpl failed to store or reload objects in map property: referencedMap", 3, main.getReferenceMap().size());
+        assertNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyFirst"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keySecond"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyThird"));
+        assertNotNull("DefaultMapConverterImpl failed to store objects in map", main.getReferenceMap().get("keyFourth"));
+    }
+}

Added: jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/manager/collectionconverter/MapReferenceValueEncoderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/manager/collectionconverter/MapReferenceValueEncoderTest.java?rev=697950&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/manager/collectionconverter/MapReferenceValueEncoderTest.java (added)
+++ jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/manager/collectionconverter/MapReferenceValueEncoderTest.java Mon Sep 22 12:00:54 2008
@@ -0,0 +1,60 @@
+/*
+ * 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.jackrabbit.ocm.manager.collectionconverter;
+
+import org.apache.jackrabbit.ocm.manager.collectionconverter.impl.MapReferenceValueEncoder;
+import static junit.framework.Assert.assertEquals;import static junit.framework.Assert.assertTrue;
+import junit.framework.TestCase;
+
+/**
+ * TODO: JAVADOC
+ * <p/>
+ * Created by Vincent Giguere
+ * Date: Jun 9, 2008
+ * Time: 3:08:28 PM
+ */
+public class MapReferenceValueEncoderTest extends TestCase{
+
+
+    public void testEncode_key_and_reference()
+    {
+        String key = "value1";
+        String reference = "aReference";
+        assertTrue(MapReferenceValueEncoder.encodeKeyAndReference(key, reference).contains(key));
+        assertTrue(MapReferenceValueEncoder.encodeKeyAndReference(key, reference).contains(reference));
+
+    }
+
+    
+    public void testDecode_key()
+    {
+        String key = "value1";
+        String reference = "aReference";
+        assertEquals(key , MapReferenceValueEncoder.decodeKey(MapReferenceValueEncoder.encodeKeyAndReference(key, reference)));
+    }
+
+
+    public void testDecode_reference()
+    {
+        String key = "value1";
+        String reference = "aReference";
+        assertEquals(reference , MapReferenceValueEncoder.decodeReference(MapReferenceValueEncoder.encodeKeyAndReference(key, reference)));
+    }
+
+
+}

Modified: jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/testmodel/collection/Main.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/testmodel/collection/Main.java?rev=697950&r1=697949&r2=697950&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/testmodel/collection/Main.java (original)
+++ jackrabbit/trunk/jackrabbit-ocm/src/test/java/org/apache/jackrabbit/ocm/testmodel/collection/Main.java Mon Sep 22 12:00:54 2008
@@ -16,12 +16,15 @@
  */
 package org.apache.jackrabbit.ocm.testmodel.collection;
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.jackrabbit.ocm.manager.collectionconverter.impl.BeanReferenceMapConverterImpl;
 import org.apache.jackrabbit.ocm.mapper.impl.annotation.Collection;
 import org.apache.jackrabbit.ocm.mapper.impl.annotation.Field;
 import org.apache.jackrabbit.ocm.mapper.impl.annotation.Node;
+import org.apache.jackrabbit.ocm.testmodel.uuid.A;
 
 
 /**
@@ -39,6 +42,9 @@
     private HashMapElement hashMapElement;
 
     @Collection private Map<String, Element> map;
+    
+    @Collection(collectionConverter=BeanReferenceMapConverterImpl.class)
+    private Map<String, A> referenceMap = new HashMap<String, A>();
 
 
     // 3 ways to implements a collection :
@@ -122,6 +128,14 @@
 	public void setCustomList(CustomList customList) {
 		this.customList = customList;
 	}
+	public Map<String, A> getReferenceMap() {
+		return referenceMap;
+	}
+	public void setReferenceMap(Map<String, A> referenceMap) {
+		this.referenceMap = referenceMap;
+	}
+	
+	
 
 
 }