From f0ad75d7fdfbe0deb4beb660e839123529082bc7 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Thu, 2 Oct 2008 20:41:18 +0000 Subject: [PATCH] OPENJPA-732 - Fixed BrokerImpl's fields of type Set to consistently use the correct implementation type of HashSet rather than ArrayList or LinkList. git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@701236 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/openjpa/kernel/BrokerImpl.java | 32 ++-- .../persistence/callbacks/Message.java | 112 +++++++++++ .../callbacks/MessageListenerImpl.java | 102 ++++++++++ .../callbacks/TestMessageListeners.java | 180 ++++++++++++++++++ .../test/resources/META-INF/listener-orm.xml | 3 + .../test/resources/META-INF/persistence.xml | 1 + 6 files changed, 414 insertions(+), 16 deletions(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/Message.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/MessageListenerImpl.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/TestMessageListeners.java diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java index 69cbb2afd..27fa3f7b6 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java @@ -1522,7 +1522,7 @@ public class BrokerImpl _savepoints = new LinkedMap(); } else { if (_savepointCache == null) - save.save(Collections.EMPTY_LIST); + save.save(Collections.EMPTY_SET); else { save.save(_savepointCache); _savepointCache.clear(); @@ -2190,7 +2190,7 @@ public class BrokerImpl if (hasTransactionalObjects()) transStates = _transCache; else - transStates = Collections.EMPTY_LIST; + transStates = Collections.EMPTY_SET; // fire after rollback/commit event Collection mobjs = null; @@ -2265,7 +2265,7 @@ public class BrokerImpl // now clear trans cache; keep cleared version rather than // null to avoid having to re-create the set later; more efficient - if (transStates != Collections.EMPTY_LIST) { + if (transStates != Collections.EMPTY_SET) { _transCache = (TransactionalCache) transStates; _transCache.clear(); } @@ -3310,7 +3310,7 @@ public class BrokerImpl Object obj; StateManagerImpl sm; ClassMetaData meta; - Collection sms = new ArrayList(objs.size()); + Collection sms = new HashSet(objs.size()); List exceps = null; for (Iterator itr = objs.iterator(); itr.hasNext();) { obj = itr.next(); @@ -3637,7 +3637,7 @@ public class BrokerImpl try { assertActiveTransaction(); - Collection sms = new ArrayList(objs.size()); + Collection sms = new HashSet(objs.size()); Object obj; StateManagerImpl sm; for (Iterator itr = objs.iterator(); itr.hasNext();) { @@ -3784,7 +3784,7 @@ public class BrokerImpl */ protected Collection getTransactionalStates() { if (!hasTransactionalObjects()) - return Collections.EMPTY_LIST; + return Collections.EMPTY_SET; return _transCache.copy(); } @@ -3803,7 +3803,7 @@ public class BrokerImpl */ protected Collection getDirtyStates() { if (!hasTransactionalObjects()) - return Collections.EMPTY_LIST; + return Collections.EMPTY_SET; return _transCache.copyDirty(); } @@ -3814,8 +3814,8 @@ public class BrokerImpl */ protected Collection getPendingTransactionalStates() { if (_pending == null) - return Collections.EMPTY_LIST; - return new ArrayList(_pending); + return Collections.EMPTY_SET; + return new HashSet(_pending); } /** @@ -4036,19 +4036,19 @@ public class BrokerImpl public Collection getPersistedTypes() { if (_persistedClss == null || _persistedClss.isEmpty()) - return Collections.EMPTY_LIST; + return Collections.EMPTY_SET; return Collections.unmodifiableCollection(_persistedClss); } public Collection getUpdatedTypes() { if (_updatedClss == null || _updatedClss.isEmpty()) - return Collections.EMPTY_LIST; + return Collections.EMPTY_SET; return Collections.unmodifiableCollection(_updatedClss); } public Collection getDeletedTypes() { if (_deletedClss == null || _deletedClss.isEmpty()) - return Collections.EMPTY_LIST; + return Collections.EMPTY_SET; return Collections.unmodifiableCollection(_deletedClss); } @@ -4503,12 +4503,12 @@ public class BrokerImpl */ public Collection copy() { if (isEmpty()) - return Collections.EMPTY_LIST; + return Collections.EMPTY_SET; // size may not be entirely accurate due to refs expiring, so // manually copy each object; doesn't matter this way if size too // big by some - List copy = new ArrayList(size()); + Set copy = new HashSet(size()); if (_dirty != null) for (Iterator itr = _dirty.iterator(); itr.hasNext();) copy.add(itr.next()); @@ -4523,8 +4523,8 @@ public class BrokerImpl */ public Collection copyDirty() { if (_dirty == null || _dirty.isEmpty()) - return Collections.EMPTY_LIST; - return new ArrayList(_dirty); + return Collections.EMPTY_SET; + return new HashSet(_dirty); } /** diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/Message.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/Message.java new file mode 100644 index 000000000..790218614 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/Message.java @@ -0,0 +1,112 @@ +/* + * 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.persistence.callbacks; + +import java.util.Date; + +import javax.persistence.Basic; +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.Id; +import javax.persistence.Version; + +/** + * A very simple persistent entity that holds a "message", has a "created" field + * that is initialized to the time at which the object was created, and an id + * field that is initialized to the current time. + */ +@Entity +@EntityListeners(value = MessageListenerImpl.class) +public class Message { + @Id + private long id = System.currentTimeMillis(); + + @Basic + private String message; + + @Basic + private Date created = null; + + @Basic + private Date updated = null; + + @Version + Integer version; + + public Message() { + } + + public Message(String msg) { + message = msg; + } + + public void setId(long val) { + id = val; + } + + public long getId() { + return id; + } + + public void setMessage(String msg) { + message = msg; + } + + public String getMessage() { + return message; + } + + public void setCreated(Date date) { + created = date; + } + + public Date getCreated() { + return created; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public Date getUpdated() { + return updated; + } + + public void setUpdated(Date updated) { + this.updated = updated; + } + + @Override + public boolean equals(Object o) { + if (o instanceof Message) { + Message other = (Message) o; + return other.getId() == this.getId(); + } + return false; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} \ No newline at end of file diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/MessageListenerImpl.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/MessageListenerImpl.java new file mode 100644 index 000000000..e9e098428 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/MessageListenerImpl.java @@ -0,0 +1,102 @@ +/* + * 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.persistence.callbacks; + +import java.util.Date; + +import javax.persistence.PrePersist; +import javax.persistence.PostPersist; +import javax.persistence.PostLoad; +import javax.persistence.PreUpdate; +import javax.persistence.PostUpdate; +import javax.persistence.PreRemove; +import javax.persistence.PostRemove; + +public class MessageListenerImpl { + + public static int prePersistCount; + public static int postPersistCount; + public static int preUpdateCount; + public static int postUpdateCount; + public static int preRemoveCount; + public static int postRemoveCount; + public static int postLoadCount; + + @PrePersist + public void prePersist(Object o) { + prePersistCount++; + + if (o instanceof Message) { + ((Message) o).setCreated(new Date()); + ((Message) o).setUpdated(new Date()); + } + } + + @PostPersist + public void postPersist(Object o) { + postPersistCount++; + } + + @PostLoad + public void postLoad(Object o) { + postLoadCount++; + } + + @PreUpdate + public void preUpdate(Object o) { + preUpdateCount++; + + if (o instanceof Message) { + ((Message) o).setUpdated(new Date()); + } + } + + @PostUpdate + public void postUpdate(Object o) { + postUpdateCount++; + } + + @PreRemove + public void preRemove(Object o) { + preRemoveCount++; + } + + @PostRemove + public void postRemove(Object o) { + postRemoveCount++; + } + + public static void resetCounters() { + prePersistCount = 0; + postPersistCount = 0; + preUpdateCount = 0; + postUpdateCount = 0; + preRemoveCount = 0; + postRemoveCount = 0; + postLoadCount = 0; + } + + public static String getStates() { + return "prePersistCount = " + prePersistCount + ", postPersistCount = " + + postPersistCount + ", preUpdateCount = " + preUpdateCount + + ", postUpdateCount = " + postUpdateCount + ", preRemoveCount = " + + preRemoveCount + ", postRemoveCount = " + postRemoveCount + + ", postLoadCount = " + postLoadCount; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/TestMessageListeners.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/TestMessageListeners.java new file mode 100644 index 000000000..d33c5ffa3 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/callbacks/TestMessageListeners.java @@ -0,0 +1,180 @@ +/* + * 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.persistence.callbacks; + +import javax.persistence.Query; + +import org.apache.openjpa.persistence.test.SingleEMFTestCase; +import org.apache.openjpa.persistence.OpenJPAEntityManager; + +public class TestMessageListeners extends SingleEMFTestCase { + + public void setUp() { + setUp(CLEAR_TABLES); + } + + @Override + protected String getPersistenceUnitName() { + return "listener-pu"; + } + + public void testUpdateInPrePersist() { + // Create a new EntityManager from the EntityManagerFactory. The + // EntityManager is the main object in the persistence API, and is + // used to create, delete, and query objects, as well as access + // the current transaction + OpenJPAEntityManager em = emf.createEntityManager(); + try { + // Begin a new local transaction so that we can persist a new entity + em.getTransaction().begin(); + + MessageListenerImpl.resetCounters(); + + // Create and persist a new Message entity + Message message = new Message("Hello Persistence!"); + assertNull("Test message's created field to be null.", message + .getCreated()); + assertNull("Test message's updated field to be null.", message + .getUpdated()); + + em.persist(message); + + // Pre-persist invoked, created and updated fields set + assertStatus(1, 0, 0, 0, 0, 0, 0); + assertNotNull("Test message's created field being set.", message + .getCreated()); + assertNotNull("Test message's updated field being set.", message + .getUpdated()); + + em.flush(); + // Post-persist invoked + assertStatus(1, 1, 0, 0, 0, 0, 0); + + em.clear(); + + // Perform a simple query to get the Message + Query q = em.createQuery("select m from Message m where m.id=" + + message.getId()); + Message m = (Message) q.getSingleResult(); + + assertEquals("Test first expected message.", "Hello Persistence!", + m.getMessage()); + assertNotNull("Test message's created field being set.", m + .getCreated()); + assertNotNull("Test message's updated field being set.", m + .getUpdated()); + + // query trigger a load because em is cleared. + assertStatus(1, 1, 0, 0, 0, 0, 1); + + em.getTransaction().commit(); + + // since data is flushed, commit data with no event fired. + assertStatus(1, 1, 0, 0, 0, 0, 1); + } finally { + if (em != null && em.getTransaction().isActive()) + em.getTransaction().rollback(); + if (em != null && em.isOpen()) + em.close(); + } + } + + public void testUpdateInPreUpdate() { + // Create a new EntityManager from the EntityManagerFactory. The + // EntityManager is the main object in the persistence API, and is + // used to create, delete, and query objects, as well as access + // the current transaction + OpenJPAEntityManager em = emf.createEntityManager(); + try { + // Begin a new local transaction so that we can persist a new entity + em.getTransaction().begin(); + + MessageListenerImpl.resetCounters(); + + // Create and persist a new Message entity + Message message = new Message("Hello Persistence!"); + assertNull("Test message's created field to be null.", message + .getCreated()); + assertNull("Test message's updated field to be null.", message + .getUpdated()); + + em.persist(message); + + // Pre-persist invoked, created and updated fields set + assertStatus(1, 0, 0, 0, 0, 0, 0); + assertNotNull("Test message's created field being set.", message + .getCreated()); + assertNotNull("Test message's updated field being set.", message + .getUpdated()); + + // Perform a simple query to get the Message + Query q = em.createQuery("select m from Message m where m.id=" + + message.getId()); + Message m = (Message) q.getSingleResult(); + assertEquals("Test first expected message.", "Hello Persistence!", + m.getMessage()); + assertNotNull("Test message's created field being set.", m + .getCreated()); + assertNotNull("Test message's updated field being set.", m + .getUpdated()); + + // Query cause flush to occur, hence fire the postPersist event + assertStatus(1, 1, 0, 0, 0, 0, 0); + + // Create and persist another new Message entity + message = new Message("Hello Persistence 2!"); + assertNull("Test message's created field to be null.", message + .getCreated()); + assertNull("Test message's updated field to be null.", message + .getUpdated()); + + em.persist(message); + + // Pre-persist invoked, created and updated fields set + assertStatus(2, 1, 0, 0, 0, 0, 0); + assertNotNull("Test message's created field being set.", message + .getCreated()); + assertNotNull("Test message's updated field being set.", message + .getUpdated()); + + em.getTransaction().commit(); + + // Complete the 2nd @postPersist and the @preUpdate caused by + // setters calls in @postPersist + assertStatus(2, 2, 1, 1, 0, 0, 0); + + } finally { + if (em != null && em.getTransaction().isActive()) + em.getTransaction().rollback(); + if (em != null && em.isOpen()) + em.close(); + } + } + + private void assertStatus(int prePersist, int postPersist, int preUpdate, + int postUpdate, int preRemove, int postRemove, int postLoad) { + assertEquals(prePersist, MessageListenerImpl.prePersistCount); + assertEquals(postPersist, MessageListenerImpl.postPersistCount); + assertEquals(preUpdate, MessageListenerImpl.preUpdateCount); + assertEquals(postUpdate, MessageListenerImpl.postUpdateCount); + assertEquals(preRemove, MessageListenerImpl.preRemoveCount); + assertEquals(postRemove, MessageListenerImpl.postRemoveCount); + assertEquals(postLoad, MessageListenerImpl.postLoadCount); + } +} diff --git a/openjpa-persistence-jdbc/src/test/resources/META-INF/listener-orm.xml b/openjpa-persistence-jdbc/src/test/resources/META-INF/listener-orm.xml index 1cf7f09f1..2cd94a6bb 100644 --- a/openjpa-persistence-jdbc/src/test/resources/META-INF/listener-orm.xml +++ b/openjpa-persistence-jdbc/src/test/resources/META-INF/listener-orm.xml @@ -34,4 +34,7 @@ + + + \ No newline at end of file diff --git a/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml b/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml index 307785db4..23afdc840 100644 --- a/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml +++ b/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml @@ -84,6 +84,7 @@ META-INF/listener-orm.xml org.apache.openjpa.persistence.callbacks.EntityListenerEntity org.apache.openjpa.persistence.callbacks.GlobalListenerEntity + org.apache.openjpa.persistence.callbacks.Message