diff --git a/config/alfresco/action-services-context.xml b/config/alfresco/action-services-context.xml
index 8dcfa3395a..779f01c5bd 100644
--- a/config/alfresco/action-services-context.xml
+++ b/config/alfresco/action-services-context.xml
@@ -427,4 +427,13 @@
+
+
+
+
+
+ false
+
+
+
diff --git a/config/alfresco/messages/action-config.properties b/config/alfresco/messages/action-config.properties
index 2c2b3dead3..de34139cdb 100644
--- a/config/alfresco/messages/action-config.properties
+++ b/config/alfresco/messages/action-config.properties
@@ -94,6 +94,10 @@ simple-avm-promote.title=Simple Sandbox Promotion
simple-avm-promote.description=This promotes any newer nodes in the matched item to the specified target sandbox.
simple-avm-promote.target-store.display-label=The name of the target AVM store.
+avm-revert-store.title=Revert a Single Node in a store.
+avm-revert-store.description=This reverts all nodes including and below the argument node to a previous version.
+avm-revert-store.version.display-lable=The version to revert to.
+
start-avm-workflow.title=Start a WCM Workflow
start-avm-workflow.description=Starts a workflow expecting an AVM workflow package
start-avm-workflow.store-name.display-label=Store name for start task
diff --git a/source/java/org/alfresco/repo/avm/actions/AVMRevertStoreAction.java b/source/java/org/alfresco/repo/avm/actions/AVMRevertStoreAction.java
new file mode 100644
index 0000000000..dc01608507
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/actions/AVMRevertStoreAction.java
@@ -0,0 +1,74 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm.actions;
+
+import java.util.List;
+
+import org.alfresco.repo.action.ParameterDefinitionImpl;
+import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
+import org.alfresco.repo.avm.AVMNodeConverter;
+import org.alfresco.service.cmr.action.Action;
+import org.alfresco.service.cmr.action.ParameterDefinition;
+import org.alfresco.service.cmr.avmsync.AVMDifference;
+import org.alfresco.service.cmr.avmsync.AVMSyncService;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.util.Pair;
+import org.apache.log4j.Logger;
+
+/**
+ * Reverts a node and everything underneath it to a specified version.
+ * @author britt
+ */
+public class AVMRevertStoreAction extends ActionExecuterAbstractBase
+{
+ private static Logger fgLogger = Logger.getLogger(AVMRevertStoreAction.class);
+
+ public static final String NAME = "avm-revert-store";
+ public static final String PARAM_VERSION = "version";
+
+ /**
+ * The AVM Synchronization Service.
+ */
+ private AVMSyncService fSyncService;
+
+ /**
+ * Set the Sync Service.
+ */
+ public void setAvmSyncService(AVMSyncService service)
+ {
+ fSyncService = service;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
+ */
+ @Override
+ protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
+ {
+ // All this does is an override submit from the older version
+ // to head of the store implied in the path.
+ Pair pathVersion =
+ AVMNodeConverter.ToAVMVersionPath(actionedUponNodeRef);
+ int revertVersion = (Integer)action.getParameterValue(PARAM_VERSION);
+ List diffs =
+ fSyncService.compare(revertVersion, pathVersion.getSecond(),
+ -1, pathVersion.getSecond());
+ String message = "Reverted to Version " + revertVersion + ".";
+ fSyncService.update(diffs, false, false, true, true, message, message);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List)
+ */
+ @Override
+ protected void addParameterDefinitions(List paramList)
+ {
+ paramList.add(
+ new ParameterDefinitionImpl(PARAM_VERSION,
+ DataTypeDefinition.INT,
+ true,
+ getParamDisplayLabel(PARAM_VERSION)));
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/util/VersionPathStuffer.java b/source/java/org/alfresco/repo/avm/util/VersionPathStuffer.java
new file mode 100644
index 0000000000..d960063038
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/util/VersionPathStuffer.java
@@ -0,0 +1,69 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm.util;
+
+import org.alfresco.repo.avm.AVMNodeConverter;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.util.Pair;
+
+/**
+ * A utility to build a (possibly long) String representation of
+ * a collection of AVM path,versions. The path,versions can be recovered
+ * by VersionPathUnStuffer.
+ * @author britt
+ */
+public class VersionPathStuffer
+{
+ /**
+ * The internal buffer.
+ */
+ private StringBuilder fBuilder;
+
+ /**
+ * Whether any paths have been added yet.
+ */
+ private boolean fAnyAdded;
+
+ /**
+ * Make up one.
+ */
+ public VersionPathStuffer()
+ {
+ fBuilder = new StringBuilder();
+ fAnyAdded = false;
+ }
+
+ /**
+ * Add a version path expressed by the version and path.
+ */
+ public void add(int version, String path)
+ {
+ if (fAnyAdded)
+ {
+ fBuilder.append(';');
+ }
+ fBuilder.append(path);
+ fBuilder.append('@');
+ fBuilder.append(version);
+ fAnyAdded = true;
+ }
+
+ /**
+ * Add a version path expressed as a NodeRef.
+ */
+ public void add(NodeRef nodeRef)
+ {
+ Pair versionPath =
+ AVMNodeConverter.ToAVMVersionPath(nodeRef);
+ add(versionPath.getFirst(), versionPath.getSecond());
+ }
+
+ /**
+ * Get the stuffed String version of the Version/Paths contained in this.
+ */
+ public String toString()
+ {
+ return fBuilder.toString();
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/util/VersionPathTest.java b/source/java/org/alfresco/repo/avm/util/VersionPathTest.java
new file mode 100644
index 0000000000..43c363e440
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/util/VersionPathTest.java
@@ -0,0 +1,44 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm.util;
+
+import java.util.List;
+
+import org.alfresco.repo.avm.AVMNodeConverter;
+import org.alfresco.util.Pair;
+
+import junit.framework.TestCase;
+
+/**
+ * Test out stuffing and unstuffing Version/Paths
+ * @author britt
+ */
+public class VersionPathTest extends TestCase
+{
+ public void testVersionPath()
+ {
+ VersionPathStuffer stuffer = new VersionPathStuffer();
+ stuffer.add(-1, "figs:/bottom/top");
+ stuffer.add(1, "piggy:/back/ride");
+ stuffer.add(2, "main:/boring/path/to/nowhere");
+ String stuffed = stuffer.toString();
+ VersionPathUnstuffer unstuffer = new VersionPathUnstuffer(stuffed);
+ List> items = unstuffer.getVersionPaths();
+ assertEquals(3, items.size());
+ assertEquals(-1, (int)items.get(0).getFirst());
+ assertEquals("figs:/bottom/top", items.get(0).getSecond());
+ assertEquals(1, (int)items.get(1).getFirst());
+ assertEquals("piggy:/back/ride", items.get(1).getSecond());
+ assertEquals(2, (int)items.get(2).getFirst());
+ assertEquals("main:/boring/path/to/nowhere", items.get(2).getSecond());
+ stuffer = new VersionPathStuffer();
+ for (Pair item : items)
+ {
+ stuffer.add(AVMNodeConverter.ToNodeRef(item.getFirst(), item.getSecond()));
+ }
+ String stuffed2 = stuffer.toString();
+ assertEquals(stuffed, stuffed2);
+ System.out.println(stuffed2);
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/util/VersionPathUnstuffer.java b/source/java/org/alfresco/repo/avm/util/VersionPathUnstuffer.java
new file mode 100644
index 0000000000..0f9bf7ff63
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/util/VersionPathUnstuffer.java
@@ -0,0 +1,62 @@
+/**
+ *
+ */
+package org.alfresco.repo.avm.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.alfresco.repo.avm.AVMNodeConverter;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.util.Pair;
+
+/**
+ * Takes a String representation of a list of Version/Paths (created
+ * by VersionPathStuffer) and gives you back a list of Version/Paths
+ * @author britt
+ */
+public class VersionPathUnstuffer
+{
+ /**
+ * The unpacked version paths.
+ */
+ private List> fVersionPaths;
+
+ /**
+ * Construct one and in the process unstuff the String.
+ */
+ public VersionPathUnstuffer(String stuffed)
+ {
+ fVersionPaths = new ArrayList>();
+ String[] versionPaths = stuffed.split(";");
+ for (String path : versionPaths)
+ {
+ String [] pathVersion = path.split("@");
+ Pair item =
+ new Pair(new Integer(pathVersion[1]),
+ pathVersion[0]);
+ fVersionPaths.add(item);
+ }
+ }
+
+ /**
+ * Get the raw list of Version/Paths.
+ */
+ public List> getVersionPaths()
+ {
+ return fVersionPaths;
+ }
+
+ /**
+ * Get the Version/Paths as NodeRefs.
+ */
+ public List getNodeRefs()
+ {
+ List result = new ArrayList();
+ for (Pair item : fVersionPaths)
+ {
+ result.add(AVMNodeConverter.ToNodeRef(item.getFirst(), item.getSecond()));
+ }
+ return result;
+ }
+}