ALF-4133 - Partial support for executing actions via the webscript

Will need a refactor of pending actions support before this can be finished, and unit tests can be enabled


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21683 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Nick Burch
2010-08-09 14:26:33 +00:00
parent 5e3357245b
commit 7ed6d33810
11 changed files with 422 additions and 2 deletions

View File

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

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<String, Object> 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
);
}

View File

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

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

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