ALF-4133 & ALF-4284 - finish execute action webscripts, and return the details of the pending action in the result

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21720 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Nick Burch
2010-08-10 17:01:38 +00:00
parent d598e36b6d
commit 53bca43b13
8 changed files with 171 additions and 67 deletions

View File

@@ -6,7 +6,7 @@
"actionType": "${action.type}", "actionType": "${action.type}",
"actionInstance": "${action.instance?string}", "actionInstance": "${action.instance?string}",
"actionNodeRef": <#if action.nodeRef??>"${action.nodeRef.nodeRef}"<#else>null</#if>, "actionNodeRef": <#if action.nodeRef??>"${action.nodeRef.nodeRef}"<#else>null</#if>,
"startedAt": "${action.startedAt}", "startedAt": <#if action.startedAt??>"${action.startedAt}"<#else>null</#if>,
"cancelRequested": "${action.cancelRequested?string}", "cancelRequested": "${action.cancelRequested?string}",
"details": "${"/api/running-action/" + action.key}", "details": "${"/api/running-action/" + action.key}",
} }

View File

@@ -6,6 +6,5 @@
<url>/api/running-actions?nodeRef={nodeRef?}</url> <url>/api/running-actions?nodeRef={nodeRef?}</url>
<format default="json"/> <format default="json"/>
<authentication>admin</authentication> <authentication>admin</authentication>
<!-- Transactions handled by the parent class --> <transaction>required</transaction>
<transaction>none</transaction>
</webscript> </webscript>

View File

@@ -6,6 +6,5 @@
<url>/api/running-replication-actions?name={name?}</url> <url>/api/running-replication-actions?name={name?}</url>
<format default="json"/> <format default="json"/>
<authentication>admin</authentication> <authentication>admin</authentication>
<!-- Transactions handled by the parent class --> <transaction>required</transaction>
<transaction>none</transaction>
</webscript> </webscript>

View File

@@ -922,7 +922,6 @@
<bean id="abstractExecuteActionWebScript" <bean id="abstractExecuteActionWebScript"
class="org.alfresco.repo.web.scripts.action.AbstractExecuteActionWebscript" class="org.alfresco.repo.web.scripts.action.AbstractExecuteActionWebscript"
parent="abstractActionWebScript" abstract="true"> parent="abstractActionWebScript" abstract="true">
<property name="transactionService" ref="TransactionService" />
</bean> </bean>
<!-- Gets the details of a running action --> <!-- Gets the details of a running action -->

View File

@@ -20,12 +20,8 @@ package org.alfresco.repo.web.scripts.action;
import java.util.Map; import java.util.Map;
import javax.transaction.UserTransaction;
import org.alfresco.service.cmr.action.Action; 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.cmr.action.ExecutionSummary;
import org.alfresco.service.transaction.TransactionService;
import org.springframework.extensions.webscripts.Cache; import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptException;
@@ -38,64 +34,34 @@ import org.springframework.extensions.webscripts.WebScriptRequest;
*/ */
public abstract class AbstractExecuteActionWebscript extends AbstractActionWebscript public abstract class AbstractExecuteActionWebscript extends AbstractActionWebscript
{ {
protected TransactionService transactionService;
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
protected Map<String, Object> buildModel( protected Map<String, Object> buildModel(
RunningActionModelBuilder modelBuilder, RunningActionModelBuilder modelBuilder,
WebScriptRequest req, WebScriptRequest req,
Status status, Cache cache) Status status, Cache cache)
{ {
try { try {
// Start our transaction
UserTransaction txn = transactionService.getUserTransaction();
txn.begin();
// Have the action to run be identified // Have the action to run be identified
Action action = identifyAction(req, status, cache); Action action = identifyAction(req, status, cache);
if(action == null) { if(action == null) {
txn.rollback();
throw new WebScriptException( throw new WebScriptException(
Status.STATUS_NOT_FOUND, 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 // Ask for it to be run in the background
// It will be available to execute once the webscript finishes
actionService.executeAction( actionService.executeAction(
action, null, action, null,
false, true 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 // Return the details if we can
System.err.println(action);
System.err.println(action.getExecutionStatus());
ExecutionSummary summary = getSummaryFromAction(action); ExecutionSummary summary = getSummaryFromAction(action);
if(summary == null) { if(summary == null) {
throw new WebScriptException( throw new WebScriptException(
Status.STATUS_EXPECTATION_FAILED, Status.STATUS_EXPECTATION_FAILED,
"Action failed to start in the required timeframe" "Action failed to be added to the pending queue"
); );
} }

View File

@@ -121,10 +121,15 @@ public class RunningActionModelBuilder
ram.put(ACTION_KEY, AbstractActionWebscript.getRunningId(summary)); ram.put(ACTION_KEY, AbstractActionWebscript.getRunningId(summary));
ram.put(ACTION_NODE_REF, details.getPersistedActionRef()); 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_RUNNING_ON, details.getRunningOn());
ram.put(ACTION_CANCEL_REQUESTED, details.isCancelRequested()); 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; return ram;
} }

View File

@@ -171,7 +171,7 @@ public class RunningActionRestApiTest extends BaseWebScriptTest
id + "=" + instance, jsonRD.get("details")); 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"); rd = replicationService.createReplicationDefinition("Test2", "2nd Testing");
replicationService.saveReplicationDefinition(rd); replicationService.saveReplicationDefinition(rd);
actionTrackingService.recordActionExecuting(rd); actionTrackingService.recordActionExecuting(rd);
@@ -181,7 +181,7 @@ public class RunningActionRestApiTest extends BaseWebScriptTest
rd = replicationService.createReplicationDefinition("AnotherTest", "3rd Testing"); rd = replicationService.createReplicationDefinition("AnotherTest", "3rd Testing");
replicationService.saveReplicationDefinition(rd); replicationService.saveReplicationDefinition(rd);
actionTrackingService.recordActionExecuting(rd); actionTrackingService.recordActionPending(rd);
String id3 = rd.getId(); String id3 = rd.getId();
@@ -464,7 +464,7 @@ public class RunningActionRestApiTest extends BaseWebScriptTest
id + "=" + instance, jsonRD.get("details")); 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"); rd = replicationService.createReplicationDefinition("Test2", "2nd Testing");
replicationService.saveReplicationDefinition(rd); replicationService.saveReplicationDefinition(rd);
actionTrackingService.recordActionExecuting(rd); actionTrackingService.recordActionExecuting(rd);
@@ -474,7 +474,7 @@ public class RunningActionRestApiTest extends BaseWebScriptTest
rd = replicationService.createReplicationDefinition("AnotherTest", "3rd Testing"); rd = replicationService.createReplicationDefinition("AnotherTest", "3rd Testing");
replicationService.saveReplicationDefinition(rd); replicationService.saveReplicationDefinition(rd);
actionTrackingService.recordActionExecuting(rd); actionTrackingService.recordActionPending(rd);
String id3 = rd.getId(); String id3 = rd.getId();
@@ -688,6 +688,29 @@ public class RunningActionRestApiTest extends BaseWebScriptTest
assertEquals(startedAt, jsonRD.get("startedAt")); assertEquals(startedAt, jsonRD.get("startedAt"));
assertEquals(false, jsonRD.getBoolean("cancelRequested")); assertEquals(false, jsonRD.getBoolean("cancelRequested"));
assertEquals("/" + URL_RUNNING_ACTION + key1, jsonRD.get("details")); 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 public void testRunningActionCancel() throws Exception
@@ -736,13 +759,40 @@ public class RunningActionRestApiTest extends BaseWebScriptTest
assertEquals(Status.STATUS_GONE, response.getStatus()); assertEquals(Status.STATUS_GONE, response.getStatus());
assertEquals(true, actionTrackingService.isCancellationRequested(rd)); 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());
} }
/** public void testRunningActionsPost() throws Exception
* 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; Response response;
@@ -792,22 +842,25 @@ public class RunningActionRestApiTest extends BaseWebScriptTest
assertEquals(rd.getNodeRef().toString(), jsonRD.get("actionNodeRef")); assertEquals(rd.getNodeRef().toString(), jsonRD.get("actionNodeRef"));
assertEquals(false, jsonRD.getBoolean("cancelRequested")); assertEquals(false, jsonRD.getBoolean("cancelRequested"));
// Wait a bit for it to be run + fail // Should be pending
// Check that it failed due to insufficient definition options // Wait for it to fail (we didn't
// specify enough options for a valid transfer)
for(int i=0; i<50; i++) { for(int i=0; i<50; i++) {
txn = transactionService.getUserTransaction(); txn = transactionService.getUserTransaction();
txn.begin(); txn.begin();
rd = replicationService.loadReplicationDefinition("Test1"); rd = replicationService.loadReplicationDefinition("Test1");
txn.commit(); txn.commit();
if(rd.getExecutionStatus() == ActionStatus.New || if(rd.getExecutionStatus() == ActionStatus.New) {
rd.getExecutionStatus() == ActionStatus.Pending || // Still pending, or maybe running
rd.getExecutionStatus() == ActionStatus.Running) {
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch(InterruptedException e) {} } catch(InterruptedException e) {}
} else { } else if (rd.getExecutionStatus() == ActionStatus.Failed) {
// We're done
break; break;
} else {
fail("Unexpected status in repo of " + rd.getExecutionStatus());
} }
} }
assertEquals(ActionStatus.Failed, rd.getExecutionStatus()); assertEquals(ActionStatus.Failed, rd.getExecutionStatus());
@@ -817,12 +870,91 @@ public class RunningActionRestApiTest extends BaseWebScriptTest
json = new JSONObject(); json = new JSONObject();
json.put("nodeRef", "XX"+rd.getNodeRef().toString()+"ZZ"); json.put("nodeRef", "XX"+rd.getNodeRef().toString()+"ZZ");
response = sendRequest(new PostRequest(URL_RUNNING_ACTIONS, json.toString(), JSON), Status.STATUS_BAD_REQUEST); response = sendRequest(new PostRequest(URL_RUNNING_ACTIONS, json.toString(), JSON), Status.STATUS_NOT_FOUND);
assertEquals(Status.STATUS_BAD_REQUEST, response.getStatus()); assertEquals(Status.STATUS_NOT_FOUND, response.getStatus());
} }
public void testRunningReplicationsActionsPost() throws Exception
{
Response response;
// TODO - Running Replication Actions POST unit tests
// 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());
}
@Override @Override

View File

@@ -59,10 +59,14 @@ public class RunningActionsPost extends AbstractExecuteActionWebscript
} }
} }
// Load the specified action // Does it exist in the repo?
NodeRef actionNodeRef = new NodeRef(nodeRef); NodeRef actionNodeRef = new NodeRef(nodeRef);
Action action = runtimeActionService.createAction(actionNodeRef); if(! nodeService.exists(actionNodeRef)) {
return null;
}
// Load the specified action
Action action = runtimeActionService.createAction(actionNodeRef);
return action; return action;
} }
} }