diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-action.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-action.lib.ftl index a141834873..5bedcc1072 100644 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-action.lib.ftl +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/action/running-action.lib.ftl @@ -6,7 +6,7 @@ "actionType": "${action.type}", "actionInstance": "${action.instance?string}", "actionNodeRef": <#if action.nodeRef??>"${action.nodeRef.nodeRef}"<#else>null, - "startedAt": "${action.startedAt}", + "startedAt": <#if action.startedAt??>"${action.startedAt}"<#else>null, "cancelRequested": "${action.cancelRequested?string}", "details": "${"/api/running-action/" + action.key}", } 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 index 00a47a3da6..5a30d61c95 100644 --- 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 @@ -6,6 +6,5 @@ /api/running-actions?nodeRef={nodeRef?} admin - - none + required 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 index 8952e774b2..49c138898f 100644 --- 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 @@ -6,6 +6,5 @@ /api/running-replication-actions?name={name?} admin - - none + required diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 855f425270..62c494ab5a 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -922,7 +922,6 @@ - diff --git a/source/java/org/alfresco/repo/web/scripts/action/AbstractExecuteActionWebscript.java b/source/java/org/alfresco/repo/web/scripts/action/AbstractExecuteActionWebscript.java index 357f8bfec8..92b5f50be8 100644 --- a/source/java/org/alfresco/repo/web/scripts/action/AbstractExecuteActionWebscript.java +++ b/source/java/org/alfresco/repo/web/scripts/action/AbstractExecuteActionWebscript.java @@ -20,12 +20,8 @@ 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; @@ -38,64 +34,34 @@ import org.springframework.extensions.webscripts.WebScriptRequest; */ 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" + "No Runnable Action found with the supplied details" ); } // Ask for it to be run in the background + // It will be available to execute once the webscript finishes 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" + "Action failed to be added to the pending queue" ); } diff --git a/source/java/org/alfresco/repo/web/scripts/action/RunningActionModelBuilder.java b/source/java/org/alfresco/repo/web/scripts/action/RunningActionModelBuilder.java index 1a99914ce0..2c626bef72 100644 --- a/source/java/org/alfresco/repo/web/scripts/action/RunningActionModelBuilder.java +++ b/source/java/org/alfresco/repo/web/scripts/action/RunningActionModelBuilder.java @@ -121,10 +121,15 @@ public class RunningActionModelBuilder ram.put(ACTION_KEY, AbstractActionWebscript.getRunningId(summary)); ram.put(ACTION_NODE_REF, details.getPersistedActionRef()); - ram.put(ACTION_STARTED_AT, ISO8601DateFormat.format(details.getStartedAt())); ram.put(ACTION_RUNNING_ON, details.getRunningOn()); ram.put(ACTION_CANCEL_REQUESTED, details.isCancelRequested()); + if(details.getStartedAt() != null) { + ram.put(ACTION_STARTED_AT, ISO8601DateFormat.format(details.getStartedAt())); + } else { + ram.put(ACTION_STARTED_AT, null); + } + return ram; } 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 8cbd88640a..6e1d27617d 100644 --- a/source/java/org/alfresco/repo/web/scripts/action/RunningActionRestApiTest.java +++ b/source/java/org/alfresco/repo/web/scripts/action/RunningActionRestApiTest.java @@ -171,7 +171,7 @@ public class RunningActionRestApiTest extends BaseWebScriptTest id + "=" + instance, jsonRD.get("details")); - // Add a 2nd and 3rd + // Add a 2nd and 3rd - one pending, one running rd = replicationService.createReplicationDefinition("Test2", "2nd Testing"); replicationService.saveReplicationDefinition(rd); actionTrackingService.recordActionExecuting(rd); @@ -181,7 +181,7 @@ public class RunningActionRestApiTest extends BaseWebScriptTest rd = replicationService.createReplicationDefinition("AnotherTest", "3rd Testing"); replicationService.saveReplicationDefinition(rd); - actionTrackingService.recordActionExecuting(rd); + actionTrackingService.recordActionPending(rd); String id3 = rd.getId(); @@ -464,7 +464,7 @@ public class RunningActionRestApiTest extends BaseWebScriptTest id + "=" + instance, jsonRD.get("details")); - // Add a 2nd and 3rd + // Add a 2nd and 3rd, one running and one pending rd = replicationService.createReplicationDefinition("Test2", "2nd Testing"); replicationService.saveReplicationDefinition(rd); actionTrackingService.recordActionExecuting(rd); @@ -474,7 +474,7 @@ public class RunningActionRestApiTest extends BaseWebScriptTest rd = replicationService.createReplicationDefinition("AnotherTest", "3rd Testing"); replicationService.saveReplicationDefinition(rd); - actionTrackingService.recordActionExecuting(rd); + actionTrackingService.recordActionPending(rd); String id3 = rd.getId(); @@ -688,6 +688,29 @@ public class RunningActionRestApiTest extends BaseWebScriptTest assertEquals(startedAt, jsonRD.get("startedAt")); assertEquals(false, jsonRD.getBoolean("cancelRequested")); assertEquals("/" + URL_RUNNING_ACTION + key1, jsonRD.get("details")); + + + // Add one that is pending - has everything except start date + rd = replicationService.createReplicationDefinition("Test3", "Testing"); + replicationService.saveReplicationDefinition(rd); + actionTrackingService.recordActionPending(rd); + String id3 = rd.getId(); + String instance3 = Integer.toString( ((ActionImpl)rd).getExecutionInstance() ); + String key3 = "replicationActionExecutor=" + id3 + "=" + instance3; + + response = sendRequest(new GetRequest(URL_RUNNING_ACTION + key3), Status.STATUS_OK); + assertEquals(Status.STATUS_OK, response.getStatus()); + + jsonStr = response.getContentAsString(); + jsonRD = new JSONObject(jsonStr); + assertNotNull(jsonRD); + assertEquals(id3, jsonRD.get("actionId")); + assertEquals(ReplicationDefinitionImpl.EXECUTOR_NAME, jsonRD.get("actionType")); + assertEquals(instance3, jsonRD.get("actionInstance")); + assertEquals(rd.getNodeRef().toString(), jsonRD.get("actionNodeRef")); + assertEquals(JSONObject.NULL, jsonRD.get("startedAt")); + assertEquals(false, jsonRD.getBoolean("cancelRequested")); + assertEquals("/" + URL_RUNNING_ACTION + key3, jsonRD.get("details")); } public void testRunningActionCancel() throws Exception @@ -736,13 +759,40 @@ public class RunningActionRestApiTest extends BaseWebScriptTest assertEquals(Status.STATUS_GONE, response.getStatus()); assertEquals(true, actionTrackingService.isCancellationRequested(rd)); + + + // You can ask a pending action to cancel + // At this time, it will remain in the queue though + rd = replicationService.createReplicationDefinition("Test2", "Testing"); + replicationService.saveReplicationDefinition(rd); + actionTrackingService.recordActionPending(rd); + String id2 = rd.getId(); + String instance2 = Integer.toString( ((ActionImpl)rd).getExecutionInstance() ); + String key2 = "replicationActionExecutor=" + id2 + "=" + instance2; + + + // Should be in the cache, but not not running and not cancelled + assertEquals(false, actionTrackingService.isCancellationRequested(rd)); + assertEquals(null, rd.getExecutionStartDate()); + + assertNotNull(executingActionsCache.get(key2)); + assertFalse(executingActionsCache.get(key2).isCancelRequested()); + + + // Ask for it to be cancelled via the webscript + response = sendRequest(new DeleteRequest(URL_RUNNING_ACTION + key2), Status.STATUS_GONE); + assertEquals(Status.STATUS_GONE, response.getStatus()); + + + // Should still be in the cache, not running but cancelled + assertNotNull(executingActionsCache.get(key2)); + assertTrue(executingActionsCache.get(key2).isCancelRequested()); + + assertEquals(true, actionTrackingService.isCancellationRequested(rd)); + assertEquals(null, rd.getExecutionStartDate()); } - /** - * TODO Fix this up after the changes to the action tracking - * service for pending actions have been made - */ - public void DISABLEDtestRunningActionsPost() throws Exception + public void testRunningActionsPost() throws Exception { Response response; @@ -792,22 +842,25 @@ public class RunningActionRestApiTest extends BaseWebScriptTest 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 + // Should be pending + // Wait for it to fail (we didn't + // specify enough options for a valid transfer) 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) { + + if(rd.getExecutionStatus() == ActionStatus.New) { + // Still pending, or maybe running try { Thread.sleep(100); } catch(InterruptedException e) {} - } else { + } else if (rd.getExecutionStatus() == ActionStatus.Failed) { + // We're done break; + } else { + fail("Unexpected status in repo of " + rd.getExecutionStatus()); } } assertEquals(ActionStatus.Failed, rd.getExecutionStatus()); @@ -817,14 +870,93 @@ public class RunningActionRestApiTest extends BaseWebScriptTest 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()); + response = sendRequest(new PostRequest(URL_RUNNING_ACTIONS, json.toString(), JSON), Status.STATUS_NOT_FOUND); + assertEquals(Status.STATUS_NOT_FOUND, response.getStatus()); } + public void testRunningReplicationsActionsPost() throws Exception + { + Response response; + + + // Not allowed if you're not an admin + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getGuestUserName()); + response = sendRequest(new PostRequest(URL_RUNNING_REPLICATION_ACTIONS, "{}", JSON), Status.STATUS_UNAUTHORIZED); + assertEquals(Status.STATUS_UNAUTHORIZED, response.getStatus()); + + AuthenticationUtil.setFullyAuthenticatedUser(USER_NORMAL); + response = sendRequest(new PostRequest(URL_RUNNING_REPLICATION_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_REPLICATION_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("name", "Test1"); + + response = sendRequest(new PostRequest(URL_RUNNING_REPLICATION_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")); + + // Should be pending + // Wait for it to fail (we didn't + // specify enough options for a valid transfer) + for(int i=0; i<50; i++) { + txn = transactionService.getUserTransaction(); + txn.begin(); + rd = replicationService.loadReplicationDefinition("Test1"); + txn.commit(); + + if(rd.getExecutionStatus() == ActionStatus.New) { + // Still pending, or maybe running + try { + Thread.sleep(100); + } catch(InterruptedException e) {} + } else if (rd.getExecutionStatus() == ActionStatus.Failed) { + // We're done + break; + } else { + fail("Unexpected status in repo of " + rd.getExecutionStatus()); + } + } + assertEquals(ActionStatus.Failed, rd.getExecutionStatus()); + + + // Ensure you can't start with an invalid name + json = new JSONObject(); + json.put("name", "MadeUpName"); + + response = sendRequest(new PostRequest(URL_RUNNING_REPLICATION_ACTIONS, json.toString(), JSON), Status.STATUS_NOT_FOUND); + assertEquals(Status.STATUS_NOT_FOUND, 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 index c9d15c4503..ea465f5c60 100644 --- a/source/java/org/alfresco/repo/web/scripts/action/RunningActionsPost.java +++ b/source/java/org/alfresco/repo/web/scripts/action/RunningActionsPost.java @@ -59,10 +59,14 @@ public class RunningActionsPost extends AbstractExecuteActionWebscript } } - // Load the specified action + // Does it exist in the repo? NodeRef actionNodeRef = new NodeRef(nodeRef); + if(! nodeService.exists(actionNodeRef)) { + return null; + } + + // Load the specified action Action action = runtimeActionService.createAction(actionNodeRef); - return action; } } \ No newline at end of file