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));
}