Author: ppoddar
Date: Tue Jun 26 22:16:03 2012
New Revision: 1354266

URL: http://svn.apache.org/viewvc?rev=1354266&view=rev
Log:
OPENJPA-2030: Add a test for audit

Added:
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/AuditedEntry.java
   (with props)
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/InplaceAuditor.java
   (with props)
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/TestAudit.java
   (with props)
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/X.java
   (with props)
Modified:
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml

Added: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/AuditedEntry.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/AuditedEntry.java?rev=1354266&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/AuditedEntry.java
 (added)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/AuditedEntry.java
 Tue Jun 26 22:16:03 2012
@@ -0,0 +1,119 @@
+/*
+ * 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.openjpa.audit;
+
+import java.sql.Timestamp;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.apache.openjpa.enhance.PersistenceCapable;
+import org.apache.openjpa.kernel.Audited;
+import org.apache.openjpa.persistence.Type;
+
+/**
+ * An example of an immutable persistent entity that holds a reference to the 
entity being audited.
+ * <br>
+ * This entity holds the reference to the entity being audited in a 
<em>generic</em>
+ * sense i.e. it does not know the exact type of the audited entity, but 
merely that
+ * it is a {@link PersistenceCapable} instance.
+ * <br>
+ * OpenJPA supports such reference by annotating with the {@link #audited 
reference field} as 
+ * <tt>@Type(PersistenceCapable.class)</tt>.
+ * <br>
+ * The audit operation is also represented as a {@link #operation enumerated 
field}.
+ *    
+ * @author Pinaki Poddar
+ *
+ */
+@Entity
+public class AuditedEntry {
+       @Id
+       @GeneratedValue
+       private long id;
+       
+       @ManyToOne(cascade=CascadeType.MERGE)
+       @Type(PersistenceCapable.class)
+       private Object audited;
+       
+       @Enumerated(EnumType.STRING)
+       private AuditableOperation operation;
+       
+       @Temporal(TemporalType.TIMESTAMP)
+       private Timestamp ts;
+       
+       @ElementCollection
+       private List<String> updatedFields;
+       
+       /**
+        * Constructs using an {@link Audited audited} instance.
+        * <br>
+        * An audited instances are supplied to the {@link 
Auditor#audit(Broker, Collection, Collection, Collection)
+        * auditor} by OpenJPA runtime within the transaction just before it is 
going to commit.
+        * <br>
+        * An audited instance carries the managed instance being audited in 
two <em>separate</em> references.
+        * The {link {@link Audited#getManagedObject()} first reference} is to 
the actual persistence instance
+        * being audited. The {link {@link Audited#getOriginalObject() second 
reference} is a <em>transient</em>
+        * copy of the actual persistence instance but in a state as it were 
when it entered the managed context
+        * i.e. when it was persisted or loaded from the database.
+        * <br>
+        * The {@link Audited} instance also knows the fields that were 
updated.    
+        * @param a an audited instance.
+        */
+       public AuditedEntry(Audited a) {
+               audited = a.getManagedObject();
+               ts = new Timestamp(new Date().getTime());
+               operation = a.getType();
+               if (operation == AuditableOperation.UPDATE) {
+                       updatedFields = Arrays.asList(a.getUpdatedFields());
+               }
+               
+       }
+
+       public Object getAudited() {
+               return audited;
+       }
+
+       public AuditableOperation getOperation() {
+               return operation;
+       }
+
+       public Timestamp getTimestamp() {
+               return ts;
+       }
+
+       public long getId() {
+               return id;
+       }
+       
+       public List<String> getUpdatedFields() {
+               return updatedFields;
+       }
+}

Propchange: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/AuditedEntry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/InplaceAuditor.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/InplaceAuditor.java?rev=1354266&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/InplaceAuditor.java
 (added)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/InplaceAuditor.java
 Tue Jun 26 22:16:03 2012
@@ -0,0 +1,80 @@
+/*
+ * 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.openjpa.audit;
+
+import java.util.Collection;
+
+import org.apache.openjpa.kernel.Audited;
+import org.apache.openjpa.kernel.Broker;
+import org.apache.openjpa.lib.conf.Configuration;
+
+/**
+ * Example of an {@link Auditor auditor} that records the audit entries in the 
same database
+ * of the managed entities being audited.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class InplaceAuditor implements Auditor {
+
+       @Override
+       public void audit(Broker broker, Collection<Audited> newObjects, 
Collection<Audited> updates,
+                       Collection<Audited> deletes) {
+               recordAudits(broker, newObjects);
+               recordAudits(broker, updates);
+               recordAudits(broker, deletes);
+       }
+
+       @Override
+       public boolean isRollbackOnError() {
+               return false;
+       }
+       
+       /**
+        * Recording an audit is simply persisting an {@link AuditedEntry} with 
+        * the available {@link Broker persistence context}.
+        * @param broker
+        * @param audits
+        */
+       private void recordAudits(Broker broker, Collection<Audited> audits) {
+               for (Audited a : audits) {
+                       broker.persist(new AuditedEntry(a), null);
+               }
+       }
+
+       // -------------------------------------------------------------
+       // Configurable implementation that does nothing.
+       // -------------------------------------------------------------
+       @Override
+       public void setConfiguration(Configuration conf) {
+       }
+
+       @Override
+       public void startConfiguration() {
+       }
+
+       @Override
+       public void endConfiguration() {
+       }
+
+       @Override
+       public void close() throws Exception {
+       }
+
+}

Propchange: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/InplaceAuditor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/TestAudit.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/TestAudit.java?rev=1354266&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/TestAudit.java
 (added)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/TestAudit.java
 Tue Jun 26 22:16:03 2012
@@ -0,0 +1,150 @@
+/*
+ * 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.openjpa.audit;
+
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Persistence;
+
+import junit.framework.TestCase;
+
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
+
+/**
+ * A test for audit facility.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class TestAudit extends TestCase {
+       private static OpenJPAEntityManagerFactory emf;
+       private static Auditor auditor;
+       private static Object oid;
+
+       EntityManager em;
+       
+    public void setUp() {
+       if (emf == null) {
+               emf = 
OpenJPAPersistence.cast(Persistence.createEntityManagerFactory("audit"));
+               assertNotNull(emf);
+               auditor = emf.getConfiguration().getAuditorInstance();
+            em = emf.createEntityManager();
+               clearAuditedEntries();
+               oid = createManagedObject();
+       } else {
+               em = emf.createEntityManager();
+       }
+    }
+    
+    private Object createManagedObject() {
+       em.getTransaction().begin();
+       X x = new X();
+       x.setName("New Object");
+       x.setPrice(100);
+       em.persist(x);
+       em.getTransaction().commit();
+       
+       return emf.getPersistenceUnitUtil().getIdentifier(x);
+    }
+    
+    private void clearAuditedEntries() {
+       em.getTransaction().begin();
+       em.createQuery("delete from AuditedEntry a").executeUpdate();
+       em.getTransaction().commit();
+    }
+    
+    public void testAuditorIsConfigured() {
+       assertNotNull(auditor);
+    }
+    
+    public void testIsEntityAuditable() {
+       assertNotNull(X.class.getAnnotation(Auditable.class));
+    }
+    
+    public void testNewInstancesAreAudited() {
+       X x = em.find(X.class, oid);
+       assertNotNull(x);
+       
+       AuditedEntry entry = findLastAuditedEntry(AuditableOperation.CREATE);
+
+       assertNotNull(entry);
+       assertEquals(x, entry.getAudited());
+       assertEquals(AuditableOperation.CREATE, entry.getOperation());
+       assertEquals(X.class, entry.getAudited().getClass());
+       assertTrue(entry.getUpdatedFields().isEmpty());
+    }
+    
+    public void testUpdateOutsideTransactionAreAudited() {
+       X x = em.find(X.class, oid);
+       assertNotNull(x);
+       
+       x.setName("Updated Object outside transaction");
+       
+       em.getTransaction().begin();
+       x = em.merge(x);
+       em.getTransaction().commit();
+       
+       AuditedEntry entry = findLastAuditedEntry(AuditableOperation.UPDATE);
+       
+       assertNotNull(entry);
+       assertEquals(x, entry.getAudited());
+       assertEquals(AuditableOperation.UPDATE, entry.getOperation());
+       assertTrue(entry.getUpdatedFields().contains("name"));
+       assertFalse(entry.getUpdatedFields().contains("price"));
+    }
+    
+    public void testUpdateInsideTransactionAreAudited() {
+       X x = em.find(X.class, oid);
+       assertNotNull(x);
+       
+       
+       em.getTransaction().begin();
+       x.setPrice(x.getPrice()+100);
+       x = em.merge(x);
+       em.getTransaction().commit();
+       
+       AuditedEntry entry = findLastAuditedEntry(AuditableOperation.UPDATE);
+       
+       
+       assertNotNull(entry);
+       assertEquals(x, entry.getAudited());
+       assertEquals(AuditableOperation.UPDATE, entry.getOperation());
+       assertFalse(entry.getUpdatedFields().contains("name"));
+       assertTrue(entry.getUpdatedFields().contains("price"));
+    }
+    
+    /**
+     * Finds the latest audit entry of the given operation type.
+     * The <em>latest</em> is determined by a sort on identifier which is 
assumed to be monotonically ascending.
+     *  
+     */
+    AuditedEntry findLastAuditedEntry(AuditableOperation op) {
+       List<AuditedEntry> entry = 
+               em.createQuery("select a from AuditedEntry a where 
a.operation=:op order by a.id desc", AuditedEntry.class)
+                 .setMaxResults(1)
+                 .setParameter("op", op)
+                 .getResultList();
+       return entry.get(0);
+    }
+
+
+}

Propchange: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/TestAudit.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/X.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/X.java?rev=1354266&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/X.java
 (added)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/X.java
 Tue Jun 26 22:16:03 2012
@@ -0,0 +1,64 @@
+package org.apache.openjpa.audit;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+
+/**
+ * A simple persistent entity used to test audit facility.
+ * An entity is annotated with {@link Auditable} annotation to qualify for 
audit.
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+@Entity
+@Auditable
+public class X {
+       @Id
+       @GeneratedValue
+       private long id;
+       
+       private String name;
+       private int price;
+       
+       public String getName() {
+               return name;
+       }
+       public void setName(String name) {
+               this.name = name;
+       }
+       public int getPrice() {
+               return price;
+       }
+       public void setPrice(int price) {
+               this.price = price;
+       }
+       public long getId() {
+               return id;
+       }
+       @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = 1;
+               result = prime * result + (int) (id ^ (id >>> 32));
+               return result;
+       }
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj == null)
+                       return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               X other = (X) obj;
+               if (id != other.id)
+                       return false;
+               return true;
+       }
+       
+       public String toString() {
+               return "X[" + id + "]";
+       }
+}

Propchange: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/audit/X.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml?rev=1354266&r1=1354265&r2=1354266&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml
 (original)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml
 Tue Jun 26 22:16:03 2012
@@ -432,14 +432,16 @@
         </properties>
     </persistence-unit>
     
-    <persistence-unit name="query-result">
-        <mapping-file>META-INF/query-result-orm.xml</mapping-file>
-        <class>org.apache.openjpa.persistence.results.cls.ResultClsXml</class>
+    
+    <persistence-unit name="audit">
+        <class>org.apache.openjpa.audit.X</class>
+        <class>org.apache.openjpa.audit.AuditedEntry</class>
+        
         <properties>
-            <property name="openjpa.jdbc.SynchronizeMappings"
-                  value="buildSchema(ForeignKeys=true)"/>
+               <property name="openjpa.Auditor" 
value="org.apache.openjpa.audit.InplaceAuditor"/>
+            <property name="openjpa.jdbc.SynchronizeMappings" 
value="buildSchema(ForeignKeys=true)"/>
+            <property name="openjpa.DynamicEnhancementAgent"  value="false"/> 
         </properties>
     </persistence-unit>
-    
 
 </persistence>


Reply via email to