mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
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:
@@ -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 {
|
||||
|
@@ -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
|
||||
);
|
||||
}
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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()));
|
||||
|
Reference in New Issue
Block a user