diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-actions.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-actions.post.desc.xml
new file mode 100644
index 0000000000..00a47a3da6
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-actions.post.desc.xml
@@ -0,0 +1,11 @@
+
+ Start a new Action Executing
+
+ Starts the execution of a new action, and returns its running details
+
+ /api/running-actions?nodeRef={nodeRef?}
+
+ admin
+
+ none
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-actions.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-actions.post.json.ftl
new file mode 100644
index 0000000000..b9d0a17efb
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-actions.post.json.ftl
@@ -0,0 +1,2 @@
+<#import "running-action.lib.ftl" as actionLib />
+<@actionLib.runningActionJSON action=runningAction />
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-replication-actions.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-replication-actions.post.desc.xml
new file mode 100644
index 0000000000..8952e774b2
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-replication-actions.post.desc.xml
@@ -0,0 +1,11 @@
+
+ Start a new Replication Action Executing
+
+ Starts the execution of a replication action, and returns its running details
+
+ /api/running-replication-actions?name={name?}
+
+ admin
+
+ none
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-replication-actions.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-replication-actions.post.json.ftl
new file mode 100644
index 0000000000..b9d0a17efb
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-replication-actions.post.json.ftl
@@ -0,0 +1,2 @@
+<#import "running-action.lib.ftl" as actionLib />
+<@actionLib.runningActionJSON action=runningAction />
diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml
index ffaaf836d7..e6dc96dbb9 100644
--- a/config/alfresco/web-scripts-application-context.xml
+++ b/config/alfresco/web-scripts-application-context.xml
@@ -907,6 +907,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/java/org/alfresco/repo/web/scripts/action/AbstractActionWebscript.java b/source/java/org/alfresco/repo/web/scripts/action/AbstractActionWebscript.java
index 522d628044..aff73c2beb 100644
--- a/source/java/org/alfresco/repo/web/scripts/action/AbstractActionWebscript.java
+++ b/source/java/org/alfresco/repo/web/scripts/action/AbstractActionWebscript.java
@@ -21,9 +21,12 @@ package org.alfresco.repo.web.scripts.action;
import java.util.Map;
import java.util.NoSuchElementException;
+import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.ActionTrackingServiceImpl;
import org.alfresco.repo.action.RuntimeActionService;
+import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
+import org.alfresco.service.cmr.action.ActionStatus;
import org.alfresco.service.cmr.action.ActionTrackingService;
import org.alfresco.service.cmr.action.ExecutionSummary;
import org.alfresco.service.cmr.repository.NodeService;
@@ -78,7 +81,7 @@ public abstract class AbstractActionWebscript extends DeclarativeWebScript
WebScriptRequest req,
Status status, Cache cache
);
-
+
/**
* Takes a running action ID, and returns an
@@ -91,6 +94,25 @@ public abstract class AbstractActionWebscript extends DeclarativeWebScript
return WrappedActionTrackingService.getSummaryFromKey(key);
}
+ /**
+ * Returns the ExecutionSummary for the given action if it
+ * is currently executing, or null if it isn't
+ */
+ public static ExecutionSummary getSummaryFromAction(Action action)
+ {
+ // Is it running?
+ if(action.getExecutionStatus() == ActionStatus.Running) {
+ return WrappedActionTrackingService.buildExecutionSummary(action);
+ }
+ // Has it been given a execution id?
+ // (eg has already finished, but this one was run)
+ if( ((ActionImpl)action).getExecutionInstance() != -1 ) {
+ return WrappedActionTrackingService.buildExecutionSummary(action);
+ }
+ // Not running, and hasn't run, we can't help
+ return null;
+ }
+
/**
* Returns the running action ID for the given
* ExecutionSummary
@@ -112,6 +134,11 @@ public abstract class AbstractActionWebscript extends DeclarativeWebScript
return ActionTrackingServiceImpl.generateCacheKey(summary);
}
+ protected static ExecutionSummary buildExecutionSummary(Action action)
+ {
+ return ActionTrackingServiceImpl.buildExecutionSummary(action);
+ }
+
private static ExecutionSummary getSummaryFromKey(String key)
{
try {
diff --git a/source/java/org/alfresco/repo/web/scripts/action/AbstractExecuteActionWebscript.java b/source/java/org/alfresco/repo/web/scripts/action/AbstractExecuteActionWebscript.java
new file mode 100644
index 0000000000..357f8bfec8
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/action/AbstractExecuteActionWebscript.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.web.scripts.action;
+
+import java.util.Map;
+
+import javax.transaction.UserTransaction;
+
+import org.alfresco.service.cmr.action.Action;
+import org.alfresco.service.cmr.action.ActionStatus;
+import org.alfresco.service.cmr.action.ExecutionSummary;
+import org.alfresco.service.transaction.TransactionService;
+import org.springframework.extensions.webscripts.Cache;
+import org.springframework.extensions.webscripts.Status;
+import org.springframework.extensions.webscripts.WebScriptException;
+import org.springframework.extensions.webscripts.WebScriptRequest;
+
+
+/**
+ * @author Nick Burch
+ * @since 3.4
+ */
+public abstract class AbstractExecuteActionWebscript extends AbstractActionWebscript
+{
+ protected TransactionService transactionService;
+
+ public void setTransactionService(TransactionService transactionService)
+ {
+ this.transactionService = transactionService;
+ }
+
+ protected Map buildModel(
+ RunningActionModelBuilder modelBuilder,
+ WebScriptRequest req,
+ Status status, Cache cache)
+ {
+ try {
+ // Start our transaction
+ UserTransaction txn = transactionService.getUserTransaction();
+ txn.begin();
+
+ // Have the action to run be identified
+ Action action = identifyAction(req, status, cache);
+ if(action == null) {
+ txn.rollback();
+ throw new WebScriptException(
+ Status.STATUS_NOT_FOUND,
+ "No Running Action found with the supplied details"
+ );
+ }
+
+ // Ask for it to be run in the background
+ actionService.executeAction(
+ action, null,
+ false, true
+ );
+
+ // Have it begin
+ txn.commit();
+
+ // TODO Update this after changes to the
+ // action tracking service for pending actions
+ // have been made
+
+ // Wait up to 5 seconds for it to kick off
+ long beganWaitingAt = System.currentTimeMillis();
+ while(beganWaitingAt + 5000 > System.currentTimeMillis() &&
+ action.getExecutionStatus() == ActionStatus.Pending)
+ {
+ try {
+ Thread.sleep(50);
+ } catch(InterruptedException e) {}
+ }
+
+ // Return the details if we can
+System.err.println(action);
+System.err.println(action.getExecutionStatus());
+ ExecutionSummary summary = getSummaryFromAction(action);
+ if(summary == null) {
+ throw new WebScriptException(
+ Status.STATUS_EXPECTATION_FAILED,
+ "Action failed to start in the required timeframe"
+ );
+ }
+
+ return modelBuilder.buildSimpleModel(summary);
+ } catch(Exception e) {
+ // Transaction broke
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected abstract Action identifyAction(
+ WebScriptRequest req,
+ Status status, Cache cache
+ );
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/web/scripts/action/RunningActionRestApiTest.java b/source/java/org/alfresco/repo/web/scripts/action/RunningActionRestApiTest.java
index 5ffe1009bc..8cbd88640a 100644
--- a/source/java/org/alfresco/repo/web/scripts/action/RunningActionRestApiTest.java
+++ b/source/java/org/alfresco/repo/web/scripts/action/RunningActionRestApiTest.java
@@ -738,6 +738,92 @@ public class RunningActionRestApiTest extends BaseWebScriptTest
assertEquals(true, actionTrackingService.isCancellationRequested(rd));
}
+ /**
+ * TODO Fix this up after the changes to the action tracking
+ * service for pending actions have been made
+ */
+ public void DISABLEDtestRunningActionsPost() throws Exception
+ {
+ Response response;
+
+
+ // Not allowed if you're not an admin
+ AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getGuestUserName());
+ response = sendRequest(new PostRequest(URL_RUNNING_ACTIONS, "{}", JSON), Status.STATUS_UNAUTHORIZED);
+ assertEquals(Status.STATUS_UNAUTHORIZED, response.getStatus());
+
+ AuthenticationUtil.setFullyAuthenticatedUser(USER_NORMAL);
+ response = sendRequest(new PostRequest(URL_RUNNING_ACTIONS, "{}", JSON), Status.STATUS_UNAUTHORIZED);
+ assertEquals(Status.STATUS_UNAUTHORIZED, response.getStatus());
+
+
+ // If no noderef supplied, will get an error
+ AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
+ response = sendRequest(new PostRequest(URL_RUNNING_ACTIONS, "{}", JSON), Status.STATUS_BAD_REQUEST);
+ assertEquals(Status.STATUS_BAD_REQUEST, response.getStatus());
+
+
+ // Add a running action
+ UserTransaction txn = transactionService.getUserTransaction();
+ txn.begin();
+
+ ReplicationDefinition rd = replicationService.createReplicationDefinition("Test1", "Testing");
+ replicationService.saveReplicationDefinition(rd);
+ String id = rd.getId();
+
+ txn.commit();
+
+
+ // Ask for it to be started
+ // (It should start but fail due to missing definition parts)
+ JSONObject json = new JSONObject();
+ json.put("nodeRef", rd.getNodeRef().toString());
+
+ response = sendRequest(new PostRequest(URL_RUNNING_ACTIONS, json.toString(), JSON), Status.STATUS_OK);
+ assertEquals(Status.STATUS_OK, response.getStatus());
+
+ // Check we got back some details on it
+ String jsonStr = response.getContentAsString();
+ JSONObject jsonRD = new JSONObject(jsonStr);
+ assertNotNull(jsonRD);
+
+ assertEquals(id, jsonRD.get("actionId"));
+ assertEquals(ReplicationDefinitionImpl.EXECUTOR_NAME, jsonRD.get("actionType"));
+ assertEquals(rd.getNodeRef().toString(), jsonRD.get("actionNodeRef"));
+ assertEquals(false, jsonRD.getBoolean("cancelRequested"));
+
+ // Wait a bit for it to be run + fail
+ // Check that it failed due to insufficient definition options
+ for(int i=0; i<50; i++) {
+ txn = transactionService.getUserTransaction();
+ txn.begin();
+ rd = replicationService.loadReplicationDefinition("Test1");
+ txn.commit();
+
+ if(rd.getExecutionStatus() == ActionStatus.New ||
+ rd.getExecutionStatus() == ActionStatus.Pending ||
+ rd.getExecutionStatus() == ActionStatus.Running) {
+ try {
+ Thread.sleep(100);
+ } catch(InterruptedException e) {}
+ } else {
+ break;
+ }
+ }
+ assertEquals(ActionStatus.Failed, rd.getExecutionStatus());
+
+
+ // Ensure you can't start with an invalid nodeRef
+ json = new JSONObject();
+ json.put("nodeRef", "XX"+rd.getNodeRef().toString()+"ZZ");
+
+ response = sendRequest(new PostRequest(URL_RUNNING_ACTIONS, json.toString(), JSON), Status.STATUS_BAD_REQUEST);
+ assertEquals(Status.STATUS_BAD_REQUEST, response.getStatus());
+ }
+
+
+ // TODO - Running Replication Actions POST unit tests
+
@Override
protected void setUp() throws Exception
diff --git a/source/java/org/alfresco/repo/web/scripts/action/RunningActionsPost.java b/source/java/org/alfresco/repo/web/scripts/action/RunningActionsPost.java
new file mode 100644
index 0000000000..c9d15c4503
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/action/RunningActionsPost.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.web.scripts.action;
+
+import java.io.IOException;
+
+import org.alfresco.service.cmr.action.Action;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+import org.springframework.extensions.webscripts.Cache;
+import org.springframework.extensions.webscripts.Status;
+import org.springframework.extensions.webscripts.WebScriptException;
+import org.springframework.extensions.webscripts.WebScriptRequest;
+
+/**
+ * @author Nick Burch
+ * @since 3.4
+ */
+public class RunningActionsPost extends AbstractExecuteActionWebscript
+{
+ @Override
+ protected Action identifyAction(WebScriptRequest req, Status status,
+ Cache cache) {
+ // Which action did they ask for?
+ String nodeRef = req.getParameter("nodeRef");
+ if(nodeRef == null) {
+ try {
+ JSONObject json = new JSONObject(new JSONTokener(req.getContent().getContent()));
+ if(! json.has("nodeRef")) {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not find required 'nodeRef' parameter");
+ }
+ nodeRef = json.getString("nodeRef");
+ }
+ catch (IOException iox)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not read content from request.", iox);
+ }
+ catch (JSONException je)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not parse JSON from request.", je);
+ }
+ }
+
+ // Load the specified action
+ NodeRef actionNodeRef = new NodeRef(nodeRef);
+ Action action = runtimeActionService.createAction(actionNodeRef);
+
+ return action;
+ }
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/web/scripts/action/RunningReplicationActionsPost.java b/source/java/org/alfresco/repo/web/scripts/action/RunningReplicationActionsPost.java
new file mode 100644
index 0000000000..0825c632dc
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/action/RunningReplicationActionsPost.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.web.scripts.action;
+
+import java.io.IOException;
+
+import org.alfresco.service.cmr.action.Action;
+import org.alfresco.service.cmr.replication.ReplicationDefinition;
+import org.alfresco.service.cmr.replication.ReplicationService;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+import org.springframework.extensions.webscripts.Cache;
+import org.springframework.extensions.webscripts.Status;
+import org.springframework.extensions.webscripts.WebScriptException;
+import org.springframework.extensions.webscripts.WebScriptRequest;
+
+/**
+ * @author Nick Burch
+ * @since 3.4
+ */
+public class RunningReplicationActionsPost extends AbstractExecuteActionWebscript
+{
+ private ReplicationService replicationService;
+
+ @Override
+ protected Action identifyAction(WebScriptRequest req, Status status,
+ Cache cache) {
+ // Which action did they ask for?
+ String name = req.getParameter("name");
+ if(name == null) {
+ try {
+ JSONObject json = new JSONObject(new JSONTokener(req.getContent().getContent()));
+ if(! json.has("name")) {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not find required 'name' parameter");
+ }
+ name = json.getString("name");
+ }
+ catch (IOException iox)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not read content from request.", iox);
+ }
+ catch (JSONException je)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not parse JSON from request.", je);
+ }
+ }
+
+ // Load the specified replication definition
+ ReplicationDefinition replicationDefinition =
+ replicationService.loadReplicationDefinition(name);
+ return replicationDefinition;
+ }
+
+ public void setReplicationService(ReplicationService replicationService)
+ {
+ this.replicationService = replicationService;
+ }
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/web/scripts/replication/ReplicationModelBuilder.java b/source/java/org/alfresco/repo/web/scripts/replication/ReplicationModelBuilder.java
index 5b70be6575..a04e2e9a72 100644
--- a/source/java/org/alfresco/repo/web/scripts/replication/ReplicationModelBuilder.java
+++ b/source/java/org/alfresco/repo/web/scripts/replication/ReplicationModelBuilder.java
@@ -259,12 +259,17 @@ public class ReplicationModelBuilder
}
// Use the details of the running copy
+ // TODO Update this following pending actions changes
if(details.isCancelRequested()) {
model.put(DEFINITION_STATUS, "CancelRequested");
} else {
model.put(DEFINITION_STATUS, "Running");
}
- model.put(DEFINITION_STARTED_AT, ISO8601DateFormat.format(details.getStartedAt()));
+ if(details.getStartedAt() != null) {
+ model.put(DEFINITION_STARTED_AT, ISO8601DateFormat.format(details.getStartedAt()));
+ } else {
+ model.put(DEFINITION_STARTED_AT, null);
+ }
model.put(DEFINITION_ENDED_AT, null);
model.put(DEFINITION_RUNNING_ACTION_ID,
AbstractActionWebscript.getRunningId(details.getExecutionSummary()));