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/04/26 20:06:11 UTC

svn commit: r1331001 - in /cayenne/main/trunk/framework/cayenne-lifecycle/src: main/java/org/apache/cayenne/lifecycle/audit/ test/java/org/apache/cayenne/lifecycle/audit/ test/java/org/apache/cayenne/lifecycle/db/ test/java/org/apache/cayenne/lifecycle...

Author: aadamchik
Date: Thu Apr 26 18:06:10 2012
New Revision: 1331001

URL: http://svn.apache.org/viewvc?rev=1331001&view=rev
Log:
CAY-1698 ObjectIdRelationship support for AuditableChild

patch by Denis Koyro

Added:
    cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/db/AuditableChildUuid.java
    cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/db/auto/_AuditableChildUuid.java
Modified:
    cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/audit/AuditableChild.java
    cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/audit/AuditableFilter.java
    cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/audit/AuditableFilterTest.java
    cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/audit/AuditableFilter_InRuntime_Test.java
    cayenne/main/trunk/framework/cayenne-lifecycle/src/test/resources/lifecycle-map.map.xml

Modified: cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/audit/AuditableChild.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/audit/AuditableChild.java?rev=1331001&r1=1331000&r2=1331001&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/audit/AuditableChild.java (original)
+++ cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/audit/AuditableChild.java Thu Apr 26 18:06:10 2012
@@ -45,4 +45,6 @@ public @interface AuditableChild {
     String value();
     
     String[] ignoredProperties() default {};
+
+    String objectIdRelationship() default "";
 }

Modified: cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/audit/AuditableFilter.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/audit/AuditableFilter.java?rev=1331001&r1=1331000&r2=1331001&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/audit/AuditableFilter.java (original)
+++ cayenne/main/trunk/framework/cayenne-lifecycle/src/main/java/org/apache/cayenne/lifecycle/audit/AuditableFilter.java Thu Apr 26 18:06:10 2012
@@ -36,6 +36,7 @@ import org.apache.cayenne.lifecycle.chan
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.query.Query;
+import org.apache.commons.lang.StringUtils;
 
 /**
  * A {@link DataChannelFilter} that enables audit of entities annotated with
@@ -182,7 +183,19 @@ public class AuditableFilter implements 
             throw new IllegalArgumentException("No 'AuditableChild' annotation found");
         }
 
-        return dataObject.readNestedProperty(annotation.value());
+        String propertyPath = StringUtils.isNotEmpty(annotation.value())
+                              ? annotation.value()
+
+                              : objectIdRelationshipName(annotation.objectIdRelationship());
+        return dataObject.readNestedProperty(propertyPath);
+    }
+
+    /**
+     * It's a temporary clone method of  {@link org.apache.cayenne.lifecycle.relationship.ObjectIdRelationshipHandler#objectIdRelationshipName(String)}
+     * //todo Needs to be encapsulated to some separate class to avoid a code duplication
+     */
+    private String objectIdRelationshipName(String uuidPropertyName) {
+        return "cay:related:" + uuidPropertyName;
     }
 
     protected boolean isAuditableUpdate(Object object, boolean child) {

Modified: cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/audit/AuditableFilterTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/audit/AuditableFilterTest.java?rev=1331001&r1=1331000&r2=1331001&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/audit/AuditableFilterTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/audit/AuditableFilterTest.java Thu Apr 26 18:06:10 2012
@@ -18,28 +18,35 @@
  ****************************************************************/
 package org.apache.cayenne.lifecycle.audit;
 
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 import junit.framework.TestCase;
-
 import org.apache.cayenne.CayenneDataObject;
 import org.apache.cayenne.DataChannel;
 import org.apache.cayenne.DataChannelFilterChain;
 import org.apache.cayenne.DataObject;
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.graph.GraphDiff;
+import org.apache.cayenne.lifecycle.db.Auditable1;
+import org.apache.cayenne.lifecycle.db.AuditableChildUuid;
+import org.apache.cayenne.lifecycle.id.IdCoder;
+import org.apache.cayenne.lifecycle.relationship.ObjectIdRelationshipFilter;
+import org.apache.cayenne.lifecycle.relationship.ObjectIdRelationshipHandler;
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.ObjEntity;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 public class AuditableFilterTest extends TestCase {
 
     private AuditableProcessor processor;
     private EntityResolver resolver;
+    private ServerRuntime runtime;
 
     @Override
     protected void setUp() throws Exception {
@@ -48,6 +55,17 @@ public class AuditableFilterTest extends
         
         ObjEntity objectEntity = new ObjEntity("CayenneDataObject");
         when(resolver.lookupObjEntity(any(Object.class))).thenReturn(objectEntity);
+
+        runtime = new ServerRuntime("cayenne-lifecycle.xml");
+        // a filter is required to invalidate root objects after commit
+        ObjectIdRelationshipFilter filter = new ObjectIdRelationshipFilter();
+        runtime.getDataDomain().addFilter(filter);
+        runtime.getDataDomain().getEntityResolver().getCallbackRegistry().addListener(filter);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        runtime.shutdown();
     }
 
     public void testInsertAudit() {
@@ -94,6 +112,23 @@ public class AuditableFilterTest extends
         verify(processor).audit(auditedParent, AuditableOperation.UPDATE);
     }
 
+    public void testUpdateAuditChildByObjectIdRelationship() {
+
+        ObjectContext context = runtime.getContext();
+        Auditable1 auditedParent = context.newObject(Auditable1.class);
+        AuditableChildUuid audited = context.newObject(AuditableChildUuid.class);
+
+        IdCoder refHandler = new IdCoder(context.getEntityResolver());
+        ObjectIdRelationshipHandler handler = new ObjectIdRelationshipHandler(refHandler);
+        handler.relate(audited, auditedParent);
+        context.commitChanges();
+
+        AuditableFilter filter = new AuditableFilter(resolver, processor);
+        filter.updateAuditChild(audited);
+        filter.postSync();
+        verify(processor).audit(auditedParent, AuditableOperation.UPDATE);
+    }
+
     public void testOnSyncPassThrough() {
 
         AuditableFilter filter = new AuditableFilter(resolver, processor);

Modified: cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/audit/AuditableFilter_InRuntime_Test.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/audit/AuditableFilter_InRuntime_Test.java?rev=1331001&r1=1331000&r2=1331001&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/audit/AuditableFilter_InRuntime_Test.java (original)
+++ cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/audit/AuditableFilter_InRuntime_Test.java Thu Apr 26 18:06:10 2012
@@ -35,6 +35,9 @@ import org.apache.cayenne.lifecycle.db.A
 import org.apache.cayenne.lifecycle.db.AuditableChild1;
 import org.apache.cayenne.lifecycle.db.AuditableChild2;
 import org.apache.cayenne.lifecycle.db.AuditableChild3;
+import org.apache.cayenne.lifecycle.db.AuditableChildUuid;
+import org.apache.cayenne.lifecycle.id.IdCoder;
+import org.apache.cayenne.lifecycle.relationship.ObjectIdRelationshipHandler;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 
@@ -48,6 +51,7 @@ public class AuditableFilter_InRuntime_T
 
     private TableHelper auditable2;
     private TableHelper auditableChild3;
+    private TableHelper auditableChildUuid;
 
     @Override
     protected void setUp() throws Exception {
@@ -80,12 +84,20 @@ public class AuditableFilter_InRuntime_T
                 "CHAR_PROPERTY1",
                 "CHAR_PROPERTY2");
 
+        auditableChildUuid = new TableHelper(dbHelper, "AUDITABLE_CHILD_UUID").setColumns(
+                "ID",
+                "UUID",
+                "CHAR_PROPERTY1",
+                "CHAR_PROPERTY2");
+
         auditableChild1.deleteAll();
         auditableChild2.deleteAll();
         auditable1.deleteAll();
 
         auditableChild3.deleteAll();
         auditable2.deleteAll();
+
+        auditableChildUuid.deleteAll();
     }
 
     public void testAudit_IgnoreRuntimeRelationships() throws Exception {
@@ -244,6 +256,41 @@ public class AuditableFilter_InRuntime_T
         assertEquals(1, processor.size);
     }
 
+    public void testAuditableChild_objectIdRelationship() throws Exception {
+        auditable1.insert(1, "xx");
+        auditableChildUuid.insert(1, "Auditable1:1", "xxx", "yyy");
+
+        DataDomain domain = runtime.getDataDomain();
+        Processor processor = new Processor();
+
+        AuditableFilter filter = new AuditableFilter(domain.getEntityResolver(), processor);
+        domain.addFilter(filter);
+        domain.getEntityResolver().getCallbackRegistry().addListener(filter);
+
+        // prerequisite for BaseAuditableProcessor use
+        ChangeSetFilter changeSetFilter = new ChangeSetFilter();
+        domain.addFilter(changeSetFilter);
+        domain.getEntityResolver().getCallbackRegistry().addListener(changeSetFilter);
+
+        ObjectContext context = runtime.getContext();
+        AuditableChildUuid ac = Cayenne.objectForPK(context, AuditableChildUuid.class, 1);
+        Auditable1 a1 = Cayenne.objectForPK(context, Auditable1.class, 1);
+        IdCoder refHandler = new IdCoder(domain.getEntityResolver());
+        ObjectIdRelationshipHandler handler = new ObjectIdRelationshipHandler(refHandler);
+        handler.relate(ac, a1);
+
+        ac.setCharProperty1("xxxx");
+        context.commitChanges();
+        assertEquals(1, processor.size);
+        Collection<Object> auditables = processor.audited.get(AuditableOperation.UPDATE);
+        assertSame(a1, auditables.toArray()[0]);
+
+        ac.setCharProperty2("yyyy");
+        context.commitChanges();
+        assertEquals(2, processor.size);
+        assertSame(a1, auditables.toArray()[1]);
+    }
+
     private final class Processor implements AuditableProcessor {
 
         Map<AuditableOperation, Collection<Object>> audited;

Added: cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/db/AuditableChildUuid.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/db/AuditableChildUuid.java?rev=1331001&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/db/AuditableChildUuid.java (added)
+++ cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/db/AuditableChildUuid.java Thu Apr 26 18:06:10 2012
@@ -0,0 +1,10 @@
+package org.apache.cayenne.lifecycle.db;
+
+import org.apache.cayenne.lifecycle.audit.AuditableChild;
+import org.apache.cayenne.lifecycle.db.auto._AuditableChildUuid;
+import org.apache.cayenne.lifecycle.relationship.ObjectIdRelationship;
+
+@ObjectIdRelationship(_AuditableChildUuid.UUID_PROPERTY)
+@AuditableChild(value = "", objectIdRelationship = _AuditableChildUuid.UUID_PROPERTY)
+public class AuditableChildUuid extends _AuditableChildUuid {
+}

Added: cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/db/auto/_AuditableChildUuid.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/db/auto/_AuditableChildUuid.java?rev=1331001&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/db/auto/_AuditableChildUuid.java (added)
+++ cayenne/main/trunk/framework/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/db/auto/_AuditableChildUuid.java Thu Apr 26 18:06:10 2012
@@ -0,0 +1,40 @@
+package org.apache.cayenne.lifecycle.db.auto;
+
+import org.apache.cayenne.CayenneDataObject;
+
+/**
+ * Class _AuditableChildUuid was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class _AuditableChildUuid extends CayenneDataObject {
+
+    public static final String CHAR_PROPERTY1_PROPERTY = "charProperty1";
+    public static final String CHAR_PROPERTY2_PROPERTY = "charProperty2";
+    public static final String UUID_PROPERTY = "uuid";
+
+    public static final String ID_PK_COLUMN = "ID";
+
+    public void setCharProperty1(String charProperty1) {
+        writeProperty("charProperty1", charProperty1);
+    }
+    public String getCharProperty1() {
+        return (String)readProperty("charProperty1");
+    }
+
+    public void setCharProperty2(String charProperty2) {
+        writeProperty("charProperty2", charProperty2);
+    }
+    public String getCharProperty2() {
+        return (String)readProperty("charProperty2");
+    }
+
+    public void setUuid(String uuid) {
+        writeProperty("uuid", uuid);
+    }
+    public String getUuid() {
+        return (String)readProperty("uuid");
+    }
+
+}

Modified: cayenne/main/trunk/framework/cayenne-lifecycle/src/test/resources/lifecycle-map.map.xml
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-lifecycle/src/test/resources/lifecycle-map.map.xml?rev=1331001&r1=1331000&r2=1331001&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-lifecycle/src/test/resources/lifecycle-map.map.xml (original)
+++ cayenne/main/trunk/framework/cayenne-lifecycle/src/test/resources/lifecycle-map.map.xml Thu Apr 26 18:06:10 2012
@@ -29,6 +29,12 @@
 		<db-attribute name="CHAR_PROPERTY2" type="VARCHAR" length="200"/>
 		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
 	</db-entity>
+	<db-entity name="AUDITABLE_CHILD_UUID">
+		<db-attribute name="CHAR_PROPERTY1" type="VARCHAR" length="200"/>
+		<db-attribute name="CHAR_PROPERTY2" type="VARCHAR" length="200"/>
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="UUID" type="VARCHAR" length="200"/>
+	</db-entity>
 	<db-entity name="E1">
 		<db-attribute name="ID" type="BIGINT" isPrimaryKey="true" isMandatory="true"/>
 	</db-entity>
@@ -63,6 +69,11 @@
 		<obj-attribute name="charProperty1" type="java.lang.String" db-attribute-path="CHAR_PROPERTY1"/>
 		<obj-attribute name="charProperty2" type="java.lang.String" db-attribute-path="CHAR_PROPERTY2"/>
 	</obj-entity>
+	<obj-entity name="AuditableChildUuid" className="org.apache.cayenne.lifecycle.db.AuditableChildUuid" dbEntityName="AUDITABLE_CHILD_UUID">
+		<obj-attribute name="charProperty1" type="java.lang.String" db-attribute-path="CHAR_PROPERTY1"/>
+		<obj-attribute name="charProperty2" type="java.lang.String" db-attribute-path="CHAR_PROPERTY2"/>
+		<obj-attribute name="uuid" type="java.lang.String" db-attribute-path="UUID"/>
+	</obj-entity>
 	<obj-entity name="E1" className="org.apache.cayenne.lifecycle.db.E1" dbEntityName="E1">
 	</obj-entity>
 	<obj-entity name="E2" className="org.apache.cayenne.lifecycle.db.E2" dbEntityName="E2">