You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2012/10/19 14:09:38 UTC

svn commit: r1400063 - in /cayenne/main/trunk/framework/cayenne-lifecycle/src: main/java/org/apache/cayenne/lifecycle/id/ test/java/org/apache/cayenne/lifecycle/id/

Author: aadamchik
Date: Fri Oct 19 12:09:37 2012
New Revision: 1400063

URL: http://svn.apache.org/viewvc?rev=1400063&view=rev
Log:
CAY-1748 IdCoder/EntityIdCoder improvements to work with ObjectIds, including temp ones

temp id to string

Modified:
    cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/id/EntityIdCoder.java
    cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/id/EntityIdCoderTest.java
    cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/id/IdCoderTest.java

Modified: cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/id/EntityIdCoder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/id/EntityIdCoder.java?rev=1400063&r1=1400062&r2=1400063&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/id/EntityIdCoder.java (original)
+++ cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/id/EntityIdCoder.java Fri Oct 19 12:09:37 2012
@@ -23,10 +23,10 @@ import java.net.URLDecoder;
 import java.net.URLEncoder;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.SortedMap;
 import java.util.StringTokenizer;
 import java.util.TreeMap;
-import java.util.Map.Entry;
 
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.ObjectId;
@@ -34,6 +34,7 @@ import org.apache.cayenne.dba.TypesMappi
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.util.IDUtil;
 import org.apache.cayenne.util.Util;
 
 /**
@@ -44,6 +45,8 @@ import org.apache.cayenne.util.Util;
 public class EntityIdCoder {
 
     static final String ID_SEPARATOR = ":";
+    static final String TEMP_ID_PREFIX = ".";
+    private static final int TEMP_PREFIX_LENGTH = TEMP_ID_PREFIX.length();
 
     private String entityName;
     private SortedMap<String, Converter> converters;
@@ -55,7 +58,13 @@ public class EntityIdCoder {
             throw new IllegalArgumentException("Invalid String id: " + id);
         }
 
-        return id.substring(0, separator);
+        String name = id.substring(0, separator);
+
+        if (name.startsWith(TEMP_ID_PREFIX)) {
+            name = name.substring(TEMP_PREFIX_LENGTH);
+        }
+
+        return name;
     }
 
     public EntityIdCoder(ObjEntity entity) {
@@ -97,15 +106,37 @@ public class EntityIdCoder {
      */
     public String toStringId(ObjectId id) {
 
+        // deal with temp that have attached replacement ID as permanent IDs...
+        // AuditableFilter, etc. all rely on the ability to find the temp object
+        // after the transaction end
+
+        // TODO: support encoding format for temp+replacement
         if (id.isTemporary() && !id.isReplacementIdAttached()) {
-            throw new IllegalArgumentException(
-                    "Can't create UUID for a temporary ObjectId");
+            return toTempIdString(id);
+        } else {
+            return toPermIdString(id);
         }
+    }
 
-        Map<String, Object> idValues = id.getIdSnapshot();
+    private String toTempIdString(ObjectId id) {
+        StringBuilder buffer = new StringBuilder();
+
+        buffer.append(TEMP_ID_PREFIX);
+
+        buffer.append(id.getEntityName());
+
+        buffer.append(ID_SEPARATOR);
 
+        for (byte b : id.getKey()) {
+            IDUtil.appendFormattedByte(buffer, b);
+        }
+        return buffer.toString();
+    }
+
+    private String toPermIdString(ObjectId id) {
         StringBuilder buffer = new StringBuilder();
         buffer.append(id.getEntityName());
+        Map<String, Object> idValues = id.getIdSnapshot();
 
         for (Entry<String, Converter> entry : converters.entrySet()) {
             Object value = idValues.get(entry.getKey());
@@ -117,6 +148,12 @@ public class EntityIdCoder {
 
     public ObjectId toObjectId(String stringId) {
 
+        if (stringId.startsWith(TEMP_ID_PREFIX)) {
+            String idValues = stringId.substring(entityName.length() + 1
+                    + TEMP_PREFIX_LENGTH);
+            return new ObjectId(entityName, decodeTemp(idValues));
+        }
+
         String idValues = stringId.substring(entityName.length() + 1);
 
         if (converters.size() == 1) {
@@ -138,7 +175,7 @@ public class EntityIdCoder {
         StringTokenizer toks = new StringTokenizer(idValues, ID_SEPARATOR);
 
         if (toks.countTokens() != converters.size()) {
-            throw new IllegalArgumentException("Invalid Strign ID for entity "
+            throw new IllegalArgumentException("Invalid String ID for entity "
                     + entityName + ": " + idValues);
         }
 
@@ -159,6 +196,23 @@ public class EntityIdCoder {
         return new ObjectId(entityName, idMap);
     }
 
+    private byte[] decodeTemp(String byteString) {
+
+        byte[] bytes = new byte[byteString.length() / 2];
+        for (int i = 0; i < bytes.length; i++) {
+            int index = i * 2;
+
+            // this is better than Byte.parseByte which can't parse values >=
+            // 128 as negative bytes
+            int c1 = byteString.charAt(index);
+            int c2 = byteString.charAt(index + 1);
+            bytes[i] = (byte) ((Character.digit(c1, 16) << 4) + Character
+                    .digit(c2, 16));
+        }
+
+        return bytes;
+    }
+
     private Converter create(Class<?> type) {
 
         if (type == null) {

Modified: cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/id/EntityIdCoderTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/id/EntityIdCoderTest.java?rev=1400063&r1=1400062&r2=1400063&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/id/EntityIdCoderTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/id/EntityIdCoderTest.java Fri Oct 19 12:09:37 2012
@@ -28,13 +28,47 @@ import java.util.Map;
 import junit.framework.TestCase;
 
 import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.lifecycle.id.EntityIdCoder;
+import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.ObjEntity;
 
 public class EntityIdCoderTest extends TestCase {
 
+    private ServerRuntime runtime;
+
+    @Override
+    protected void setUp() throws Exception {
+        runtime = new ServerRuntime("cayenne-lifecycle.xml");
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        runtime.shutdown();
+    }
+    
+    public void testGetEntityName() {
+        assertEquals("M", EntityIdCoder.getEntityName("M:N:K"));
+        assertEquals("M", EntityIdCoder.getEntityName(".M:N:K"));
+    }
+
+    public void testTempId() {
+
+        ObjEntity e1 = runtime.getChannel().getEntityResolver()
+                .getObjEntity("E1");
+        EntityIdCoder coder = new EntityIdCoder(e1);
+
+        byte[] key = new byte[] { 2, 2, 10, 100 };
+        ObjectId encoded = new ObjectId("E1", key);
+
+        String string = coder.toStringId(encoded);
+        assertEquals(".E1:02020A64", string);
+
+        ObjectId decoded = coder.toObjectId(string);
+        assertTrue(decoded.isTemporary());
+        assertEquals(encoded, decoded);
+    }
+
     public void testSingleIntPk() {
         DbEntity dbEntity = new DbEntity("X");
         DbAttribute pk = new DbAttribute("ID");

Modified: cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/id/IdCoderTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/id/IdCoderTest.java?rev=1400063&r1=1400062&r2=1400063&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/id/IdCoderTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/id/IdCoderTest.java Fri Oct 19 12:09:37 2012
@@ -52,25 +52,35 @@ public class IdCoderTest extends TestCas
         assertEquals("E1:5", handler.getStringId(new ObjectId("E1", "ID", 5)));
     }
 
-    public void testGetStringId_TempException() {
+    public void testGetStringId_Temp() {
         IdCoder handler = new IdCoder(runtime.getChannel().getEntityResolver());
 
+        byte[] key = new byte[] { 1, 2, 10, 100 };
+
         E1 e1 = new E1();
-        e1.setObjectId(new ObjectId("E1"));
+        e1.setObjectId(new ObjectId("E1", key));
 
-        try {
-            handler.getStringId(e1);
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
+        assertEquals(".E1:01020A64", handler.getStringId(e1));
+    }
+
+    public void testGetObjectId_Temp() {
+        IdCoder handler = new IdCoder(runtime.getChannel().getEntityResolver());
+
+        byte[] key = new byte[] { 1, (byte) 0xD7, 10, 100 };
+
+        ObjectId decoded = handler.getObjectId(".E1:01D70A64");
+        assertEquals(new ObjectId("E1", key), decoded);
     }
 
     public void testGetSringId_TempWithReplacement() {
         IdCoder handler = new IdCoder(runtime.getChannel().getEntityResolver());
 
+        byte[] key = new byte[] { 5, 2, 11, 99 };
+        ObjectId id = new ObjectId("E1", key);
+        id.getReplacementIdMap().put("ID", 6);
+
         E1 e1 = new E1();
-        e1.setObjectId(new ObjectId("E1"));
-        e1.getObjectId().getReplacementIdMap().put("ID", 6);
+        e1.setObjectId(id);
 
         assertEquals("E1:6", handler.getStringId(e1));
     }