Author: aadamchik
Date: Wed Dec 22 18:31:31 2010
New Revision: 1052020

URL: http://svn.apache.org/viewvc?rev=1052020&view=rev
Log:
@AuditableChild

Added:
    
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/AuditableChild.java
Modified:
    cayenne/sandbox/cayenne-mixin/trunk/README.txt
    cayenne/sandbox/cayenne-mixin/trunk/pom.xml
    
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/AbstractAuditableHandler.java
    
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/Auditable.java

Modified: cayenne/sandbox/cayenne-mixin/trunk/README.txt
URL: 
http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-mixin/trunk/README.txt?rev=1052020&r1=1052019&r2=1052020&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-mixin/trunk/README.txt (original)
+++ cayenne/sandbox/cayenne-mixin/trunk/README.txt Wed Dec 22 18:31:31 2010
@@ -1,9 +1,11 @@
 TODO:
 
 1. A reverse of @MixinRelationship - injecting mixin records into objects 
annotated with some mixin annotation.
+2. Transactional auditable processing (with a mix of AuditableChild changes, 
multiple audit events are generated for the same object)
 
 IMPLEMENTED:
 
+5. @AuditableChild
 4. Changeset tracking functionality
 3. @MixinRelationship and MixinRelationshipFilter to batch-fault and inject 
related objects into mixin entity (e.g. Audit entity)
 2. @Auditable mixin with abstract handler allowing to store audit records in 
an arbitrary format.

Modified: cayenne/sandbox/cayenne-mixin/trunk/pom.xml
URL: 
http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-mixin/trunk/pom.xml?rev=1052020&r1=1052019&r2=1052020&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-mixin/trunk/pom.xml (original)
+++ cayenne/sandbox/cayenne-mixin/trunk/pom.xml Wed Dec 22 18:31:31 2010
@@ -8,7 +8,7 @@
                <version>3.1M1</version>
        </parent>
        <artifactId>cayenne-mixin</artifactId>
-       <version>3.1.0.8</version>
+       <version>3.1.0.11</version>
        <name>Library: cayenne-mixin</name>
        <packaging>jar</packaging>
        <properties>

Modified: 
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/AbstractAuditableHandler.java
URL: 
http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/AbstractAuditableHandler.java?rev=1052020&r1=1052019&r2=1052020&view=diff
==============================================================================
--- 
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/AbstractAuditableHandler.java
 (original)
+++ 
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/AbstractAuditableHandler.java
 Wed Dec 22 18:31:31 2010
@@ -18,34 +18,79 @@
  ****************************************************************/
 package org.apache.cayenne.mixin.audit;
 
+import org.apache.cayenne.DataObject;
 import org.apache.cayenne.annotation.PostPersist;
 import org.apache.cayenne.annotation.PostRemove;
 import org.apache.cayenne.annotation.PostUpdate;
 
 /**
- * A superclass of application specific handlers of the {...@link Auditable} 
mixin
- * that provides basic needed callbacks.
+ * A superclass of application specific handlers of the {...@link Auditable} 
mixin that
+ * provides basic needed callbacks.
  */
 public abstract class AbstractAuditableHandler {
 
-       /**
-        * A worker method that creates audit records, as appropriate in a given
-        * application. Subclasses may insert audit records, log a message, etc.
-        */
-       protected abstract void audit(Object object, AuditableOperation 
operation);
-
-       @PostPersist(entityAnnotations = Auditable.class)
-       void insertAudit(Object object) {
-               audit(object, AuditableOperation.INSERT);
-       }
-
-       @PostRemove(entityAnnotations = Auditable.class)
-       void deleteAudit(Object object) {
-               audit(object, AuditableOperation.DELETE);
-       }
-
-       @PostUpdate(entityAnnotations = Auditable.class)
-       void updateAudit(Object object) {
-               audit(object, AuditableOperation.UPDATE);
-       }
+    /**
+     * A worker method that creates audit records, as appropriate in a given 
application.
+     * Subclasses may insert audit records, log a message, etc.
+     */
+    protected abstract void audit(
+            Object auditRoot,
+            Object auditSource,
+            AuditableOperation operation);
+
+    @PostPersist(entityAnnotations = Auditable.class)
+    void insertAudit(Object object) {
+        audit(object, object, AuditableOperation.INSERT);
+    }
+
+    @PostRemove(entityAnnotations = Auditable.class)
+    void deleteAudit(Object object) {
+        audit(object, object, AuditableOperation.DELETE);
+    }
+
+    @PostUpdate(entityAnnotations = Auditable.class)
+    void updateAudit(Object object) {
+        audit(object, object, AuditableOperation.UPDATE);
+    }
+
+    // only catching child updates... child insert/delete presumably causes an 
event on
+    // the owner object
+
+    @PostUpdate(entityAnnotations = AuditableChild.class)
+    void updateAuditChild(Object object) {
+
+        Object parent = getParent(object);
+
+        if (parent != null) {
+            audit(parent, object, AuditableOperation.UPDATE);
+        }
+        else {
+            // at least og this fact... shouldn't normally happen, but I can 
imagine
+            // certain combinations of object graphs, disconnected 
relationships, delete
+            // rules, etc. may cause this
+        }
+    }
+
+    protected Object getParent(Object object) {
+
+        if (object == null) {
+            throw new NullPointerException("Null object");
+        }
+
+        if (!(object instanceof DataObject)) {
+            throw new IllegalArgumentException("Object is not a DataObject: "
+                    + object.getClass().getName());
+        }
+
+        DataObject dataObject = (DataObject) object;
+
+        AuditableChild annotation = dataObject.getClass().getAnnotation(
+                AuditableChild.class);
+        if (annotation == null) {
+            throw new IllegalArgumentException("No 'AuditableChild' annotation 
found");
+        }
+
+        // support for nested paths
+        return dataObject.readNestedProperty(annotation.value());
+    }
 }

Modified: 
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/Auditable.java
URL: 
http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/Auditable.java?rev=1052020&r1=1052019&r2=1052020&view=diff
==============================================================================
--- 
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/Auditable.java
 (original)
+++ 
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/Auditable.java
 Wed Dec 22 18:31:31 2010
@@ -28,9 +28,9 @@ import java.lang.annotation.Target;
 import org.apache.cayenne.mixin.ref.Referenceable;
 
 /**
- * A built-in mixin annotation that adds auditable behavior to DataObjects. All
- * Auditable objects must be also tagged with {...@link Referenceable} 
annotation,
- * as audit records are based on UUIDs.
+ * A built-in annotation that adds auditable behavior to DataObjects. All 
Auditable
+ * objects must be also tagged with {...@link Referenceable} annotation, as 
audit records are
+ * based on UUIDs.
  */
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)

Added: 
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/AuditableChild.java
URL: 
http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/AuditableChild.java?rev=1052020&view=auto
==============================================================================
--- 
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/AuditableChild.java
 (added)
+++ 
cayenne/sandbox/cayenne-mixin/trunk/src/main/java/org/apache/cayenne/mixin/audit/AuditableChild.java
 Wed Dec 22 18:31:31 2010
@@ -0,0 +1,26 @@
+package org.apache.cayenne.mixin.audit;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A built-in annotation used to tag an object that is not auditable on its 
own, but whose
+ * changes should be tracked together with changes of another ("parent") 
object. This
+ * annotation allows to group changes in a closely related subtree of objects.
+ */
+...@target(ElementType.TYPE)
+...@retention(RetentionPolicy.RUNTIME)
+...@documented
+...@inherited
+public @interface AuditableChild {
+
+    /**
+     * Returns the name of a to-one relationship from an annotated object to 
the "parent"
+     * object that should be audited when annotated object is changed.
+     */
+    String value();
+}


Reply via email to