Callback mechanism for notifying CIFS when Stores are

created or purged, and when versions are created or purged.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4541 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Britt Park
2006-12-07 01:02:40 +00:00
parent 1ee6547fc4
commit c012545bfa
14 changed files with 687 additions and 163 deletions

View File

@@ -165,6 +165,14 @@
</property>
</bean>
<bean id="createStoreTxnListener" class="org.alfresco.repo.avm.CreateStoreTxnListener"/>
<bean id="purgeStoreTxnListener" class="org.alfresco.repo.avm.PurgeStoreTxnListener"/>
<bean id="createVersionTxnListener" class="org.alfresco.repo.avm.CreateVersionTxnListener"/>
<bean id="purgeVersionTxnListener" class="org.alfresco.repo.avm.PurgeVersionTxnListener"/>
<bean id="avmRepository" class="org.alfresco.repo.avm.AVMRepository">
<property name="nodeIssuer">
<ref bean="nodeIssuer"/>
@@ -178,6 +186,18 @@
<property name="contentStore">
<ref bean="fileContentStore"/>
</property>
<property name="createStoreTxnListener">
<ref bean="createStoreTxnListener"/>
</property>
<property name="purgeStoreTxnListener">
<ref bean="purgeStoreTxnListener"/>
</property>
<property name="createVersionTxnListener">
<ref bean="createVersionTxnListener"/>
</property>
<property name="purgeVersionTxnListener">
<ref bean="purgeVersionTxnListener"/>
</property>
</bean>
<!-- A Local implementation of the Remote AVM interface. -->

View File

@@ -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<Integer> createSnapshot(List<String> repositories)
{
List<Integer> result = new ArrayList<Integer>();
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);
}
}

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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<List<String>> fCreatedStores;
/**
* Callbacks to invoke on commit.
*/
private List<CreateStoreCallback> fCallbacks;
/**
* Default constructor.
*/
public CreateStoreTxnListener()
{
fCreatedStores = new ThreadLocal<List<String>>();
fCallbacks = new ArrayList<CreateStoreCallback>();
}
/* (non-Javadoc)
* @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterCommit()
*/
@Override
public void afterCommit()
{
List<String> 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<String> created = fCreatedStores.get();
if (created == null)
{
created = new ArrayList<String>();
fCreatedStores.set(created);
}
created.add(storeName);
}
/**
* Register a callback.
* @param cb The callback.
*/
public synchronized void addCallback(CreateStoreCallback cb)
{
fCallbacks.add(cb);
}
}

View File

@@ -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);
}

View File

@@ -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<List<Pair<String, Integer>>> fCreatedVersions;
/**
* Callbacks to invoke on commit.
*/
private List<CreateVersionCallback> fCallbacks;
/**
* Default constructor.
*/
public CreateVersionTxnListener()
{
fCreatedVersions = new ThreadLocal<List<Pair<String, Integer>>>();
fCallbacks = new ArrayList<CreateVersionCallback>();
}
/* (non-Javadoc)
* @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterCommit()
*/
@Override
public void afterCommit()
{
List<Pair<String, Integer>> created = fCreatedVersions.get();
for (Pair<String, Integer> 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<Pair<String, Integer>> created = fCreatedVersions.get();
if (created == null)
{
created = new ArrayList<Pair<String, Integer>>();
fCreatedVersions.set(created);
}
created.add(new Pair<String, Integer>(storeName, versionID));
}
/**
* Register a callback.
* @param cb The callback.
*/
public synchronized void addCallback(CreateVersionCallback cb)
{
fCallbacks.add(cb);
}
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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<List<String>> fPurgedStores;
/**
* Callbacks to invoke on commit.
*/
private List<PurgeStoreCallback> fCallbacks;
/**
* Default constructor.
*/
public PurgeStoreTxnListener()
{
fPurgedStores = new ThreadLocal<List<String>>();
fCallbacks = new ArrayList<PurgeStoreCallback>();
}
/* (non-Javadoc)
* @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterCommit()
*/
@Override
public void afterCommit()
{
List<String> 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<String> purged = fPurgedStores.get();
if (purged == null)
{
purged = new ArrayList<String>();
fPurgedStores.set(purged);
}
purged.add(storeName);
}
/**
* Register a callback.
* @param cb The callback.
*/
public synchronized void addCallback(PurgeStoreCallback cb)
{
fCallbacks.add(cb);
}
}

View File

@@ -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();
// }
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}

View File

@@ -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<List<Pair<String, Integer>>> fPurgedVersions;
/**
* Callbacks to invoke on commit.
*/
private List<PurgeVersionCallback> fCallbacks;
/**
* Default constructor.
*/
public PurgeVersionTxnListener()
{
fPurgedVersions = new ThreadLocal<List<Pair<String, Integer>>>();
fCallbacks = new ArrayList<PurgeVersionCallback>();
}
/* (non-Javadoc)
* @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterCommit()
*/
@Override
public void afterCommit()
{
List<Pair<String, Integer>> created = fPurgedVersions.get();
for (Pair<String, Integer> 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<Pair<String, Integer>> purged = fPurgedVersions.get();
if (purged == null)
{
purged = new ArrayList<Pair<String, Integer>>();
fPurgedVersions.set(purged);
}
purged.add(new Pair<String, Integer>(storeName, versionID));
}
/**
* Register a callback.
* @param cb The callback.
*/
public synchronized void addCallback(PurgeVersionCallback cb)
{
fCallbacks.add(cb);
}
}