diff --git a/config/alfresco/avm-services-context.xml b/config/alfresco/avm-services-context.xml
index ec6f032d1a..99ac4cdce0 100644
--- a/config/alfresco/avm-services-context.xml
+++ b/config/alfresco/avm-services-context.xml
@@ -165,6 +165,14 @@
+
+
+
+
+
+
+
+
@@ -178,6 +186,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/java/org/alfresco/repo/avm/AVMRepository.java b/source/java/org/alfresco/repo/avm/AVMRepository.java
index 453f7caaa3..40c4872e76 100644
--- a/source/java/org/alfresco/repo/avm/AVMRepository.java
+++ b/source/java/org/alfresco/repo/avm/AVMRepository.java
@@ -30,6 +30,7 @@ import java.util.SortedMap;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.domain.DbAccessControlList;
import org.alfresco.repo.domain.PropertyValue;
+import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.cmr.avm.AVMBadArgumentException;
import org.alfresco.service.cmr.avm.AVMCycleException;
import org.alfresco.service.cmr.avm.AVMException;
@@ -86,6 +87,28 @@ public class AVMRepository
*/
private LookupCache fLookupCache;
+ // A bunch of TransactionListeners that do work for this.
+
+ /**
+ * One for create store.
+ */
+ private CreateStoreTxnListener fCreateStoreTxnListener;
+
+ /**
+ * One for purge store.
+ */
+ private PurgeStoreTxnListener fPurgeStoreTxnListener;
+
+ /**
+ * One for create version.
+ */
+ private CreateVersionTxnListener fCreateVersionTxnListener;
+
+ /**
+ * One for purge version.
+ */
+ private PurgeVersionTxnListener fPurgeVersionTxnListener;
+
/**
* Create a new one.
*/
@@ -130,6 +153,26 @@ public class AVMRepository
fLookupCache = cache;
}
+ public void setCreateStoreTxnListener(CreateStoreTxnListener listener)
+ {
+ fCreateStoreTxnListener = listener;
+ }
+
+ public void setPurgeStoreTxnListener(PurgeStoreTxnListener listener)
+ {
+ fPurgeStoreTxnListener = listener;
+ }
+
+ public void setCreateVersionTxnListener(CreateVersionTxnListener listener)
+ {
+ fCreateVersionTxnListener = listener;
+ }
+
+ public void setPurgeVersionTxnListener(PurgeVersionTxnListener listener)
+ {
+ fPurgeVersionTxnListener = listener;
+ }
+
/**
* Create a file.
* @param path The path to the containing directory.
@@ -311,6 +354,7 @@ public class AVMRepository
*/
public void createAVMStore(String name)
{
+ AlfrescoTransactionSupport.bindListener(fCreateStoreTxnListener);
if (getAVMStoreByName(name) != null)
{
throw new AVMExistsException("AVMStore exists: " + name);
@@ -320,6 +364,7 @@ public class AVMRepository
AVMStore rep = new AVMStoreImpl(this, name);
// Special handling for AVMStore creation.
rep.getRoot().setStoreNew(null);
+ fCreateStoreTxnListener.storeCreated(name);
}
/**
@@ -672,27 +717,6 @@ public class AVMRepository
}
}
- /**
- * Snapshot the given repositories.
- * @param repositories The list of AVMStore name to snapshot.
- * @return A List of version ids for each newly snapshotted AVMStore.
- */
- public List createSnapshot(List repositories)
- {
- List result = new ArrayList();
- for (String repName : repositories)
- {
- AVMStore store = getAVMStoreByName(repName);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onSnapshot(repName);
- result.add(store.createSnapshot(null, null));
- }
- return result;
- }
-
/**
* Create a snapshot of a single AVMStore.
* @param store The name of the repository.
@@ -702,6 +726,7 @@ public class AVMRepository
*/
public int createSnapshot(String storeName, String tag, String description)
{
+ AlfrescoTransactionSupport.bindListener(fCreateVersionTxnListener);
AVMStore store = getAVMStoreByName(storeName);
if (store == null)
{
@@ -709,6 +734,7 @@ public class AVMRepository
}
fLookupCache.onSnapshot(storeName);
int result = store.createSnapshot(tag, description);
+ fCreateVersionTxnListener.versionCreated(storeName, result);
return result;
}
@@ -745,6 +771,7 @@ public class AVMRepository
@SuppressWarnings("unchecked")
public void purgeAVMStore(String name)
{
+ AlfrescoTransactionSupport.bindListener(fPurgeStoreTxnListener);
AVMStore store = getAVMStoreByName(name);
if (store == null)
{
@@ -769,6 +796,7 @@ public class AVMRepository
AVMDAOs.Instance().fAVMStorePropertyDAO.delete(store);
AVMDAOs.Instance().fAVMStoreDAO.delete(store);
AVMDAOs.Instance().fAVMStoreDAO.invalidateCache();
+ fPurgeStoreTxnListener.storePurged(name);
}
/**
@@ -778,6 +806,7 @@ public class AVMRepository
*/
public void purgeVersion(String name, int version)
{
+ AlfrescoTransactionSupport.bindListener(fPurgeVersionTxnListener);
AVMStore store = getAVMStoreByName(name);
if (store == null)
{
@@ -785,6 +814,7 @@ public class AVMRepository
}
fLookupCache.onDelete(name);
store.purgeVersion(version);
+ fPurgeVersionTxnListener.versionPurged(name, version);
}
/**
@@ -2279,6 +2309,8 @@ public class AVMRepository
*/
public void renameStore(String sourceName, String destName)
{
+ AlfrescoTransactionSupport.bindListener(fPurgeStoreTxnListener);
+ AlfrescoTransactionSupport.bindListener(fCreateStoreTxnListener);
AVMStore store = getAVMStoreByName(sourceName);
if (store == null)
{
@@ -2295,5 +2327,7 @@ public class AVMRepository
store.setName(destName);
fLookupCache.onDelete(sourceName);
AVMDAOs.Instance().fAVMStoreDAO.invalidateCache();
+ fPurgeStoreTxnListener.storePurged(sourceName);
+ fCreateStoreTxnListener.storeCreated(destName);
}
}
diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java b/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java
index 9ee5ba0cd3..ef8054ea13 100644
--- a/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java
+++ b/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java
@@ -75,6 +75,46 @@ public class AVMServiceTestBase extends TestCase
fService = (AVMService)fContext.getBean("AVMService");
fReaper = (OrphanReaper)fContext.getBean("orphanReaper");
fSyncService = (AVMSyncService)fContext.getBean("AVMSyncService");
+ CreateStoreTxnListener cstl = (CreateStoreTxnListener)fContext.getBean("createStoreTxnListener");
+ cstl.addCallback(
+ new CreateStoreCallback()
+ {
+ public void storeCreated(String name)
+ {
+ System.err.println("Store created: " + name);
+ }
+ }
+ );
+ PurgeStoreTxnListener pstl = (PurgeStoreTxnListener)fContext.getBean("purgeStoreTxnListener");
+ pstl.addCallback(
+ new PurgeStoreCallback()
+ {
+ public void storePurged(String name)
+ {
+ System.err.println("Store purged: " + name);
+ }
+ }
+ );
+ CreateVersionTxnListener cvtl = (CreateVersionTxnListener)fContext.getBean("createVersionTxnListener");
+ cvtl.addCallback(
+ new CreateVersionCallback()
+ {
+ public void versionCreated(String name, int versionID)
+ {
+ System.err.println("Version created: " + name + " " + versionID);
+ }
+ }
+ );
+ PurgeVersionTxnListener pvtl = (PurgeVersionTxnListener)fContext.getBean("purgeVersionTxnListener");
+ pvtl.addCallback(
+ new PurgeVersionCallback()
+ {
+ public void versionPurged(String name, int versionID)
+ {
+ System.err.println("Version purged: " + name + " " + versionID);
+ }
+ }
+ );
}
fService.createAVMStore("main");
fStartTime = System.currentTimeMillis();
diff --git a/source/java/org/alfresco/repo/avm/CreateStoreCallback.java b/source/java/org/alfresco/repo/avm/CreateStoreCallback.java
new file mode 100644
index 0000000000..872210e6b5
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/CreateStoreCallback.java
@@ -0,0 +1,18 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm;
+
+/**
+ * Interface for listeners to new store events.
+ * @author britt
+ */
+public interface CreateStoreCallback
+{
+ /**
+ * A new store has been created.
+ * @param storeName The name of the new store.
+ */
+ public void storeCreated(String storeName);
+}
+
diff --git a/source/java/org/alfresco/repo/avm/CreateStoreTxnListener.java b/source/java/org/alfresco/repo/avm/CreateStoreTxnListener.java
new file mode 100644
index 0000000000..a11d060fdb
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/CreateStoreTxnListener.java
@@ -0,0 +1,89 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.alfresco.repo.transaction.TransactionListenerAdapter;
+
+/**
+ * Transaction listener for firing create store events.
+ * @author britt
+ */
+public class CreateStoreTxnListener extends TransactionListenerAdapter
+{
+ /**
+ * Storage for stores created in a transaction.
+ */
+ private ThreadLocal> fCreatedStores;
+
+ /**
+ * Callbacks to invoke on commit.
+ */
+ private List fCallbacks;
+
+ /**
+ * Default constructor.
+ */
+ public CreateStoreTxnListener()
+ {
+ fCreatedStores = new ThreadLocal>();
+ fCallbacks = new ArrayList();
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterCommit()
+ */
+ @Override
+ public void afterCommit()
+ {
+ List created = fCreatedStores.get();
+ for (String name : created)
+ {
+ synchronized (this)
+ {
+ for (CreateStoreCallback cb : fCallbacks)
+ {
+ cb.storeCreated(name);
+ }
+ }
+ }
+ fCreatedStores.set(null);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterRollback()
+ */
+ @Override
+ public void afterRollback()
+ {
+ fCreatedStores.set(null);
+ }
+
+ /**
+ * During the transaction somebody is responsible for
+ * calling this.
+ * @param storeName The name of the store that has been created.
+ */
+ public void storeCreated(String storeName)
+ {
+ List created = fCreatedStores.get();
+ if (created == null)
+ {
+ created = new ArrayList();
+ fCreatedStores.set(created);
+ }
+ created.add(storeName);
+ }
+
+ /**
+ * Register a callback.
+ * @param cb The callback.
+ */
+ public synchronized void addCallback(CreateStoreCallback cb)
+ {
+ fCallbacks.add(cb);
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/CreateVersionCallback.java b/source/java/org/alfresco/repo/avm/CreateVersionCallback.java
new file mode 100644
index 0000000000..388637dc29
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/CreateVersionCallback.java
@@ -0,0 +1,18 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm;
+
+/**
+ * Callback interface for those interested in new version creation.
+ * @author britt
+ */
+public interface CreateVersionCallback
+{
+ /**
+ * A version of a store has been purged.
+ * @param storeName The name of the store in which a new version has been created.
+ * @param versionID The version id of the new version.
+ */
+ public void versionCreated(String storeName, int versionID);
+}
diff --git a/source/java/org/alfresco/repo/avm/CreateVersionTxnListener.java b/source/java/org/alfresco/repo/avm/CreateVersionTxnListener.java
new file mode 100644
index 0000000000..9841d78e77
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/CreateVersionTxnListener.java
@@ -0,0 +1,91 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.alfresco.repo.transaction.TransactionListenerAdapter;
+import org.alfresco.util.Pair;
+
+/**
+ * Transaction listener that fires create version events.
+ * @author britt
+ */
+public class CreateVersionTxnListener extends TransactionListenerAdapter
+{
+ /**
+ * Storage for versions created in a transaction.
+ */
+ private ThreadLocal>> fCreatedVersions;
+
+ /**
+ * Callbacks to invoke on commit.
+ */
+ private List fCallbacks;
+
+ /**
+ * Default constructor.
+ */
+ public CreateVersionTxnListener()
+ {
+ fCreatedVersions = new ThreadLocal>>();
+ fCallbacks = new ArrayList();
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterCommit()
+ */
+ @Override
+ public void afterCommit()
+ {
+ List> created = fCreatedVersions.get();
+ for (Pair version : created)
+ {
+ synchronized (this)
+ {
+ for (CreateVersionCallback cb : fCallbacks)
+ {
+ cb.versionCreated(version.getFirst(), version.getSecond());
+ }
+ }
+ }
+ fCreatedVersions.set(null);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterRollback()
+ */
+ @Override
+ public void afterRollback()
+ {
+ fCreatedVersions.set(null);
+ }
+
+ /**
+ * During the transaction somebody is responsible for
+ * calling this.
+ * @param storeName The name of the store that just created a new version
+ * @param versionID The id of the new version.
+ */
+ public void versionCreated(String storeName, int versionID)
+ {
+ List> created = fCreatedVersions.get();
+ if (created == null)
+ {
+ created = new ArrayList>();
+ fCreatedVersions.set(created);
+ }
+ created.add(new Pair(storeName, versionID));
+ }
+
+ /**
+ * Register a callback.
+ * @param cb The callback.
+ */
+ public synchronized void addCallback(CreateVersionCallback cb)
+ {
+ fCallbacks.add(cb);
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/OrphanReaper.java b/source/java/org/alfresco/repo/avm/OrphanReaper.java
index ee7cf96b9b..221ef0a228 100644
--- a/source/java/org/alfresco/repo/avm/OrphanReaper.java
+++ b/source/java/org/alfresco/repo/avm/OrphanReaper.java
@@ -20,7 +20,6 @@ package org.alfresco.repo.avm;
import java.util.LinkedList;
import java.util.List;
-import org.alfresco.repo.avm.util.RawServices;
import org.alfresco.repo.domain.DbAccessControlList;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.service.transaction.TransactionService;
diff --git a/source/java/org/alfresco/repo/avm/PurgeStoreCallback.java b/source/java/org/alfresco/repo/avm/PurgeStoreCallback.java
new file mode 100644
index 0000000000..fac487ef4c
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/PurgeStoreCallback.java
@@ -0,0 +1,17 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm;
+
+/**
+ * Callback interface for those interested in store purges.
+ * @author britt
+ */
+public interface PurgeStoreCallback
+{
+ /**
+ * A store has been purged.
+ * @param storeName The name of the purged store.
+ */
+ public void storePurged(String storeName);
+}
diff --git a/source/java/org/alfresco/repo/avm/PurgeStoreTxnListener.java b/source/java/org/alfresco/repo/avm/PurgeStoreTxnListener.java
new file mode 100644
index 0000000000..1a657e2ffe
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/PurgeStoreTxnListener.java
@@ -0,0 +1,89 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.alfresco.repo.transaction.TransactionListenerAdapter;
+
+/**
+ * Transaction listener for firing purge store events.
+ * @author britt
+ */
+public class PurgeStoreTxnListener extends TransactionListenerAdapter
+{
+ /**
+ * Storage for stores purged in a transaction.
+ */
+ private ThreadLocal> fPurgedStores;
+
+ /**
+ * Callbacks to invoke on commit.
+ */
+ private List fCallbacks;
+
+ /**
+ * Default constructor.
+ */
+ public PurgeStoreTxnListener()
+ {
+ fPurgedStores = new ThreadLocal>();
+ fCallbacks = new ArrayList();
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterCommit()
+ */
+ @Override
+ public void afterCommit()
+ {
+ List created = fPurgedStores.get();
+ for (String name : created)
+ {
+ synchronized (this)
+ {
+ for (PurgeStoreCallback cb : fCallbacks)
+ {
+ cb.storePurged(name);
+ }
+ }
+ }
+ fPurgedStores.set(null);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterRollback()
+ */
+ @Override
+ public void afterRollback()
+ {
+ fPurgedStores.set(null);
+ }
+
+ /**
+ * During the transaction somebody is responsible for
+ * calling this.
+ * @param storeName The name of the store that has been purged.
+ */
+ public void storePurged(String storeName)
+ {
+ List purged = fPurgedStores.get();
+ if (purged == null)
+ {
+ purged = new ArrayList();
+ fPurgedStores.set(purged);
+ }
+ purged.add(storeName);
+ }
+
+ /**
+ * Register a callback.
+ * @param cb The callback.
+ */
+ public synchronized void addCallback(PurgeStoreCallback cb)
+ {
+ fCallbacks.add(cb);
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/PurgeTest.java b/source/java/org/alfresco/repo/avm/PurgeTest.java
deleted file mode 100644
index 9d607eafd7..0000000000
--- a/source/java/org/alfresco/repo/avm/PurgeTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2006 Alfresco, Inc.
- *
- * Licensed under the Mozilla Public License version 1.1
- * with a permitted attribution clause. You may obtain a
- * copy of the License at
- *
- * http://www.alfresco.org/legal/license.txt
- *
- * 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.alfresco.repo.avm;
-
-import org.alfresco.repo.avm.util.BulkLoader;
-
-/**
- * Test the purge thread.
- * @author britt
- */
-public class PurgeTest extends AVMServiceTestBase
-{
- /**
- * Test purging a version.
- */
- public void testPurgeVersion()
- {
-// try
-// {
-// setupBasicTree();
-// BulkLoader loader = new BulkLoader();
-// loader.setAvmService(fService);
-// long start = System.currentTimeMillis();
-// loader.recursiveLoad("source/web", "main:/");
-// System.err.println("Load time: " + (System.currentTimeMillis() - start) + "ms");
-// fService.createSnapshot("main", null, null);
-// System.err.println("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
-// fService.purgeVersion(2, "main");
-// fReaper.activate();
-// while (fReaper.isActive())
-// {
-// try
-// {
-// Thread.sleep(2000);
-// }
-// catch (InterruptedException e)
-// {
-// // Do nothing.
-// }
-// }
-// }
-// catch (Exception e)
-// {
-// e.printStackTrace(System.err);
-// fail();
-// }
- }
-
- /**
- * Test purging a version that's not the latest.
- */
- public void testPurgeOlderVersion()
- {
-// try
-// {
-// setupBasicTree();
-// BulkLoader loader = new BulkLoader();
-// loader.setAvmService(fService);
-// long start = System.currentTimeMillis();
-// loader.recursiveLoad("source", "main:/");
-// System.err.println("Load time: " + (System.currentTimeMillis() - start) + "ms");
-// fService.createSnapshot("main", null, null);
-// System.err.println("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
-// fService.removeNode("main:/source/java/org/alfresco", "repo");
-// fService.createSnapshot("main", null, null);
-// fService.purgeVersion(2, "main");
-// fReaper.activate();
-// while (fReaper.isActive())
-// {
-// try
-// {
-// Thread.sleep(2000);
-// }
-// catch (InterruptedException e)
-// {
-// // Do nothing.
-// }
-// }
-// }
-// catch (Exception e)
-// {
-// e.printStackTrace(System.err);
-// fail();
-// }
- }
-
- /**
- * Test purging an entire store.
- */
- public void testPurgeStore()
- {
-// try
-// {
-// setupBasicTree();
-// BulkLoader loader = new BulkLoader();
-// loader.setAvmService(fService);
-// long start = System.currentTimeMillis();
-// loader.recursiveLoad("source", "main:/");
-// System.err.println("Load time: " + (System.currentTimeMillis() - start) + "ms");
-// fService.createSnapshot("main", null, null);
-// System.err.println("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
-// fService.createLayeredDirectory("main:/source", "main:/", "layer");
-// fService.removeNode("main:/layer/java/org/alfresco", "repo");
-// fService.createFile("main:/layer/java/org/alfresco", "goofy").close();
-// fService.createSnapshot("main", null, null);
-// fService.purgeAVMStore("main");
-// fReaper.activate();
-// while (fReaper.isActive())
-// {
-// try
-// {
-// Thread.sleep(2000);
-// }
-// catch (InterruptedException e)
-// {
-// // Do nothing.
-// }
-// }
-// }
-// catch (Exception e)
-// {
-// e.printStackTrace(System.err);
-// fail();
-// }
- }
-}
diff --git a/source/java/org/alfresco/repo/avm/PurgeTestP.java b/source/java/org/alfresco/repo/avm/PurgeTestP.java
new file mode 100644
index 0000000000..eefecb1357
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/PurgeTestP.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2006 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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.alfresco.repo.avm;
+
+import org.alfresco.repo.avm.util.BulkLoader;
+
+/**
+ * Test the purge thread.
+ * @author britt
+ */
+public class PurgeTestP extends AVMServiceTestBase
+{
+ /**
+ * Test purging a version.
+ */
+ public void testPurgeVersion()
+ {
+ try
+ {
+ setupBasicTree();
+ BulkLoader loader = new BulkLoader();
+ loader.setAvmService(fService);
+ long start = System.currentTimeMillis();
+ loader.recursiveLoad("source/web", "main:/");
+ System.err.println("Load time: " + (System.currentTimeMillis() - start) + "ms");
+ fService.createSnapshot("main", null, null);
+ System.err.println("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
+ fService.purgeVersion(2, "main");
+ fReaper.activate();
+ while (fReaper.isActive())
+ {
+ try
+ {
+ Thread.sleep(2000);
+ }
+ catch (InterruptedException e)
+ {
+ // Do nothing.
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(System.err);
+ fail();
+ }
+ }
+
+ /**
+ * Test purging a version that's not the latest.
+ */
+ public void testPurgeOlderVersion()
+ {
+ try
+ {
+ setupBasicTree();
+ BulkLoader loader = new BulkLoader();
+ loader.setAvmService(fService);
+ long start = System.currentTimeMillis();
+ loader.recursiveLoad("source", "main:/");
+ System.err.println("Load time: " + (System.currentTimeMillis() - start) + "ms");
+ fService.createSnapshot("main", null, null);
+ System.err.println("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
+ fService.removeNode("main:/source/java/org/alfresco", "repo");
+ fService.createSnapshot("main", null, null);
+ fService.purgeVersion(2, "main");
+ fReaper.activate();
+ while (fReaper.isActive())
+ {
+ try
+ {
+ Thread.sleep(2000);
+ }
+ catch (InterruptedException e)
+ {
+ // Do nothing.
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(System.err);
+ fail();
+ }
+ }
+
+ /**
+ * Test purging an entire store.
+ */
+ public void testPurgeStore()
+ {
+ try
+ {
+ setupBasicTree();
+ BulkLoader loader = new BulkLoader();
+ loader.setAvmService(fService);
+ long start = System.currentTimeMillis();
+ loader.recursiveLoad("source", "main:/");
+ System.err.println("Load time: " + (System.currentTimeMillis() - start) + "ms");
+ fService.createSnapshot("main", null, null);
+ System.err.println("Load time + snapshot: " + (System.currentTimeMillis() - start) + "ms");
+ fService.createLayeredDirectory("main:/source", "main:/", "layer");
+ fService.removeNode("main:/layer/java/org/alfresco", "repo");
+ fService.createFile("main:/layer/java/org/alfresco", "goofy").close();
+ fService.createSnapshot("main", null, null);
+ fService.purgeAVMStore("main");
+ fReaper.activate();
+ while (fReaper.isActive())
+ {
+ try
+ {
+ Thread.sleep(2000);
+ }
+ catch (InterruptedException e)
+ {
+ // Do nothing.
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(System.err);
+ fail();
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/PurgeVersionCallback.java b/source/java/org/alfresco/repo/avm/PurgeVersionCallback.java
new file mode 100644
index 0000000000..bda8a81800
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/PurgeVersionCallback.java
@@ -0,0 +1,18 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm;
+
+/**
+ * A Callback interface for those interested in versions being purged.
+ * @author britt
+ */
+public interface PurgeVersionCallback
+{
+ /**
+ * A version was purged from a store.
+ * @param storeName The name of the store from which a version was purged.
+ * @param versionID The id of the purged version.
+ */
+ public void versionPurged(String storeName, int versionID);
+}
diff --git a/source/java/org/alfresco/repo/avm/PurgeVersionTxnListener.java b/source/java/org/alfresco/repo/avm/PurgeVersionTxnListener.java
new file mode 100644
index 0000000000..2bf2c30db0
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/PurgeVersionTxnListener.java
@@ -0,0 +1,91 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.alfresco.repo.transaction.TransactionListenerAdapter;
+import org.alfresco.util.Pair;
+
+/**
+ * Transaction listener that fires purge version events.
+ * @author britt
+ */
+public class PurgeVersionTxnListener extends TransactionListenerAdapter
+{
+ /**
+ * Storage for versions purged in a transaction.
+ */
+ private ThreadLocal>> fPurgedVersions;
+
+ /**
+ * Callbacks to invoke on commit.
+ */
+ private List fCallbacks;
+
+ /**
+ * Default constructor.
+ */
+ public PurgeVersionTxnListener()
+ {
+ fPurgedVersions = new ThreadLocal>>();
+ fCallbacks = new ArrayList();
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterCommit()
+ */
+ @Override
+ public void afterCommit()
+ {
+ List> created = fPurgedVersions.get();
+ for (Pair version : created)
+ {
+ synchronized (this)
+ {
+ for (PurgeVersionCallback cb : fCallbacks)
+ {
+ cb.versionPurged(version.getFirst(), version.getSecond());
+ }
+ }
+ }
+ fPurgedVersions.set(null);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterRollback()
+ */
+ @Override
+ public void afterRollback()
+ {
+ fPurgedVersions.set(null);
+ }
+
+ /**
+ * During the transaction somebody is responsible for
+ * calling this.
+ * @param storeName The name of the store that just created a new version
+ * @param versionID The id of the new version.
+ */
+ public void versionPurged(String storeName, int versionID)
+ {
+ List> purged = fPurgedVersions.get();
+ if (purged == null)
+ {
+ purged = new ArrayList>();
+ fPurgedVersions.set(purged);
+ }
+ purged.add(new Pair(storeName, versionID));
+ }
+
+ /**
+ * Register a callback.
+ * @param cb The callback.
+ */
+ public synchronized void addCallback(PurgeVersionCallback cb)
+ {
+ fCallbacks.add(cb);
+ }
+}