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>