Skip to content

Commit

Permalink
BZ-1254823 - Tasks with reassignment throws exception when completing…
Browse files Browse the repository at this point in the history
… it using the REST API

(cherry picked from commit 8982766)
  • Loading branch information
Marco Rietveld committed Sep 28, 2015
1 parent 0176070 commit 6b43985
Showing 1 changed file with 102 additions and 73 deletions.
@@ -1,3 +1,18 @@
/*
* Copyright 2015 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.kie.remote.services.cdi;

import static org.kie.remote.services.cdi.DeploymentInfoBean.emptyDeploymentId;
Expand Down Expand Up @@ -33,11 +48,14 @@
import org.jbpm.services.api.TaskNotFoundException;
import org.jbpm.services.api.UserTaskService;
import org.jbpm.services.task.commands.AddTaskCommand;
import org.jbpm.services.task.commands.CancelDeadlineCommand;
import org.jbpm.services.task.commands.CompleteTaskCommand;
import org.jbpm.services.task.commands.CompositeCommand;
import org.jbpm.services.task.commands.FailTaskCommand;
import org.jbpm.services.task.commands.GetContentCommand;
import org.jbpm.services.task.commands.GetTaskCommand;
import org.jbpm.services.task.commands.GetTaskContentCommand;
import org.jbpm.services.task.commands.ProcessSubTaskCommand;
import org.jbpm.services.task.commands.SkipTaskCommand;
import org.jbpm.services.task.commands.TaskCommand;
import org.jbpm.services.task.exception.PermissionDeniedException;
Expand Down Expand Up @@ -81,7 +99,7 @@
public class ProcessRequestBean {

private static final Logger logger = LoggerFactory.getLogger(ProcessRequestBean.class);

/* KIE processing */

@Inject
Expand All @@ -92,12 +110,12 @@ public class ProcessRequestBean {

/** AuditLogService **/
private static final String PERSISTENCE_UNIT_NAME = "org.jbpm.domain";

@PersistenceUnit(unitName = PERSISTENCE_UNIT_NAME)
private EntityManagerFactory emf;

private AuditLogService auditLogService;

// Injection methods for tests

public void setProcessService(ProcessService processService) {
Expand All @@ -112,67 +130,67 @@ public void setAuditLogService(AuditLogService auditLogService) {
this.auditLogService = auditLogService;
}

// Audit Log Service logic
// Audit Log Service logic

@PostConstruct
public void initAuditLogService() {
public void initAuditLogService() {
auditLogService = new JPAAuditLogService(emf);
if( emf == null ) {
if( emf == null ) {
((JPAAuditLogService) auditLogService).setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
}
}
public AuditLogService getAuditLogService() {

public AuditLogService getAuditLogService() {
return auditLogService;
}

// Methods used
public <T> void processCommand(Command<T> cmd, JaxbCommandsRequest request, int i, JaxbCommandsResponse jaxbResponse) {

public <T> void processCommand(Command<T> cmd, JaxbCommandsRequest request, int i, JaxbCommandsResponse jaxbResponse) {
String version = request.getVersion();
if( version == null ) {
if( version == null ) {
version = "pre-6.0.3";
}
if( ! version.equals(VERSION) ) {
if( ! version.equals(VERSION) ) {
logger.warn( "Request received from client version [{}] while server is version [{}]! THIS MAY CAUSE PROBLEMS!", version, VERSION);
}
jaxbResponse.setVersion(VERSION);

String cmdName = cmd.getClass().getSimpleName();
logger.debug("Processing command " + cmdName);
String errMsg = "Unable to execute " + cmdName + "/" + i;

Object cmdResult = null;
try {
// check that all parameters have been correctly deserialized/unmarshalled
preprocessCommand(cmd);

String corrKeyString = request.getCorrelationKeyString();
List<String> correlationKeyProps = null;
if( corrKeyString != null ) {
if( corrKeyString != null ) {
String [] correlationKeyPropsArr = corrKeyString.split(":");
if( correlationKeyPropsArr.length > 0 ) {
if( correlationKeyPropsArr.length > 0 ) {
correlationKeyProps = Arrays.asList(correlationKeyPropsArr);
}
}
if( cmd instanceof TaskCommand<?> ) {

if( cmd instanceof TaskCommand<?> ) {
TaskCommand<?> taskCmd = (TaskCommand<?>) cmd;
// TODO: correlation key sessions and task completion! BZ-1245616-related
cmdResult = doTaskOperation(
taskCmd.getTaskId(),
request.getDeploymentId(),
request.getProcessInstanceId(),
null,
taskCmd.getTaskId(),
request.getDeploymentId(),
request.getProcessInstanceId(),
null,
taskCmd);
} else if( cmd instanceof AuditCommand<?>) {
} else if( cmd instanceof AuditCommand<?>) {
AuditCommand<?> auditCmd = ((AuditCommand<?>) cmd);
auditCmd.setAuditLogService(getAuditLogService());
cmdResult = auditCmd.execute(null);
} else {
cmdResult = doKieSessionOperation(
cmd,
request.getDeploymentId(),
cmd,
request.getDeploymentId(),
correlationKeyProps,
request.getProcessInstanceId());
}
Expand All @@ -182,7 +200,7 @@ public <T> void processCommand(Command<T> cmd, JaxbCommandsRequest request, int
} catch (Exception e) {
logger.warn(errMsg, e);
jaxbResponse.addException(e, i, cmd, FAILURE);
}
}
if (cmdResult != null) {
try {
// addResult could possibly throw an exception, which is why it's here and not above
Expand All @@ -194,9 +212,9 @@ public <T> void processCommand(Command<T> cmd, JaxbCommandsRequest request, int
}
}
};
void preprocessCommand(Command cmd) {
if( AcceptedServerCommands.SEND_OBJECT_PARAMETER_COMMANDS.contains(cmd.getClass()) ) {

void preprocessCommand(Command cmd) {
if( AcceptedServerCommands.SEND_OBJECT_PARAMETER_COMMANDS.contains(cmd.getClass()) ) {
if( cmd instanceof CompleteWorkItemCommand ) {
checkThatUserDefinedClassesWereUnmarshalled(((CompleteWorkItemCommand) cmd).getResults());
} else if( cmd instanceof SignalEventCommand ) {
Expand All @@ -219,39 +237,39 @@ void preprocessCommand(Command cmd) {
checkThatUserDefinedClassesWereUnmarshalled(((CompleteTaskCommand) cmd).getData());
} else if( cmd instanceof FailTaskCommand ) {
checkThatUserDefinedClassesWereUnmarshalled(((FailTaskCommand) cmd).getData());
}
}
}
}
void checkThatUserDefinedClassesWereUnmarshalled(Object obj) {
if( obj != null ) {
if( obj instanceof List ) {
for( Object listElem : (List) obj ) {

void checkThatUserDefinedClassesWereUnmarshalled(Object obj) {
if( obj != null ) {
if( obj instanceof List ) {
for( Object listElem : (List) obj ) {
verifyObjectHasBeenUnmarshalled(listElem);
}
} else if( obj instanceof Map ) {
for( Object mapVal : ((Map) obj).values() ) {
} else if( obj instanceof Map ) {
for( Object mapVal : ((Map) obj).values() ) {
verifyObjectHasBeenUnmarshalled(mapVal);
}
} else {
} else {
verifyObjectHasBeenUnmarshalled(obj);
}
}
}
private void verifyObjectHasBeenUnmarshalled(Object obj) {
if( Element.class.isAssignableFrom(obj.getClass()) ) {

private void verifyObjectHasBeenUnmarshalled(Object obj) {
if( Element.class.isAssignableFrom(obj.getClass()) ) {
String typeName = ((Element) obj).getAttribute("xsi:type");
throw new IllegalStateException("Could not unmarshall user-defined class instance parameter of type '" + typeName + "'");
}
}

/**
* Executes a command on the {@link KieSession} from the proper {@link RuntimeManager}. This method
* ends up synchronizing around the retrieved {@link KieSession} in order to avoid race-conditions.
*
*
* @param cmd The command to be executed.
* @param deploymentId The id of the runtim
* @param deploymentId The id of the runtim
* @param correlationKeyProps The defining properties for a correlation key
* @param processInstanceId The process instance id, if available (otherwise null).
* @return The result of the {@link Command}.
Expand All @@ -274,47 +292,47 @@ public <T> T doKieSessionOperation(Command<T> cmd, String deploymentId, List<Str
}
}

private Context getDeploymentCommandContext(List<String> correlationKeyProps, Long processInstanceId, Command cmd) {
if( cmd instanceof StartCorrelatedProcessCommand || cmd instanceof StartProcessInstanceCommand ) {
private Context getDeploymentCommandContext(List<String> correlationKeyProps, Long processInstanceId, Command cmd) {
if( cmd instanceof StartCorrelatedProcessCommand || cmd instanceof StartProcessInstanceCommand ) {
return EmptyContext.get();
}
// correlation key
CorrelationKey correlationKey = null;
if( correlationKeyProps != null && ! correlationKeyProps.isEmpty() ) {
CorrelationKeyFactory factory = KieInternalServices.Factory.get().newCorrelationKeyFactory();
if( correlationKeyProps != null && ! correlationKeyProps.isEmpty() ) {
CorrelationKeyFactory factory = KieInternalServices.Factory.get().newCorrelationKeyFactory();
correlationKey = factory.newCorrelationKey(correlationKeyProps);
} else if (cmd instanceof CorrelationKeyCommand ) {
} else if (cmd instanceof CorrelationKeyCommand ) {
correlationKey = ((CorrelationKeyCommand) cmd).getCorrelationKey();
}
if( correlationKey != null ) {
}
if( correlationKey != null ) {
return CorrelationKeyContext.get(correlationKey);
}

// process instance
if( processInstanceId == null && cmd instanceof ProcessInstanceIdCommand ) {
if( processInstanceId == null && cmd instanceof ProcessInstanceIdCommand ) {
processInstanceId = ((ProcessInstanceIdCommand) cmd).getProcessInstanceId();
if( processInstanceId != null ) {
if( processInstanceId != null ) {
return ProcessInstanceIdContext.get(processInstanceId);
}
}
if( processInstanceId != null ) {
if( processInstanceId != null ) {
return ProcessInstanceIdContext.get(processInstanceId);
}

// empty
return EmptyContext.get();
}

/**
* Returns the actual variable instance from the runtime (as opposed to retrieving the string value of the
* variable via the history/audit operations.
*
* variable via the history/audit operations.
*
* @param deploymentId The id of the runtime
* @param processInstanceId The process instance id (required)
* @param varName The name of the variable
* @return The variable object instance.
*/
public Object getVariableObjectInstanceFromRuntime(String deploymentId, long processInstanceId, String varName) {
public Object getVariableObjectInstanceFromRuntime(String deploymentId, long processInstanceId, String varName) {
try {
Object procVar = processService.getProcessInstanceVariable(processInstanceId, varName);
return procVar;
Expand All @@ -335,14 +353,14 @@ public Object getVariableObjectInstanceFromRuntime(String deploymentId, long pro
taskDeploymentIdCommands.add(FailTaskCommand.class);
taskDeploymentIdCommands.add(SkipTaskCommand.class);
}

/**
* There are 3 possibilities here: <ol>
* <li>This is an operation that should be done on a deployment if possible, but it's an independent task.</li>
* <li>This is an operation that should be done on a deployment, and a deployment/runtime is available.</li>
* <li>This is an operation that does <b>not</b> modify the {@link KieSession} and should be done via the injected {@link TaskService}.</li>
* </ol>
*
*
* @param taskId
* @param deploymentId
* @param processInstanceId
Expand All @@ -351,19 +369,30 @@ public Object getVariableObjectInstanceFromRuntime(String deploymentId, long pro
* @param errorMsg
* @return
*/
private <T> T doTaskOperation(Long taskId, String deploymentId, Long processInstanceId, Task task, TaskCommand<T> cmd) {
private <T> T doTaskOperation(Long taskId, String deploymentId, Long processInstanceId, Task task, TaskCommand<T> cmd) {

// take care of serialization
if( cmd instanceof GetTaskCommand
|| cmd instanceof GetContentCommand
|| cmd instanceof GetTaskContentCommand ) {
cmd = new ExecuteAndSerializeCommand(cmd);
if( cmd instanceof GetTaskCommand
|| cmd instanceof GetContentCommand
|| cmd instanceof GetTaskContentCommand ) {
cmd = new ExecuteAndSerializeCommand(cmd);
}

if( emptyDeploymentId(deploymentId) && taskDeploymentIdCommands.contains(cmd.getClass()) ) {
deploymentId = getDeploymentId(task,taskId, cmd);
}

if( cmd instanceof CompleteTaskCommand ) {
CompleteTaskCommand completeCmd = (CompleteTaskCommand) cmd;
String userId = completeCmd.getUserId();
Map<String, Object> data = completeCmd.getData();

cmd = new CompositeCommand(
new CompleteTaskCommand(taskId, userId, data),
new ProcessSubTaskCommand(taskId, userId, data),
new CancelDeadlineCommand(taskId, true, true));
}

try {
return userTaskService.execute(deploymentId, cmd);
} catch (TaskNotFoundException e) {
Expand All @@ -379,7 +408,7 @@ private <T> T doTaskOperation(Long taskId, String deploymentId, Long processInst


public <T> T doRestTaskOperation(Long taskId, String deploymentId, Long processInstanceId, Task task, TaskCommand<T> cmd) {
try {
try {
return doTaskOperation(taskId, deploymentId, processInstanceId, task, cmd);
} catch (PermissionDeniedException pde) {
throw KieRemoteRestOperationException.conflict(pde.getMessage(), pde);
Expand All @@ -396,7 +425,7 @@ private String getDeploymentId(Task task, Long taskId, TaskCommand cmd) {
task = userTaskService.getTask(taskId);
}
String deploymentId = null;
if( task != null && task.getTaskData() != null ) {
if( task != null && task.getTaskData() != null ) {
deploymentId = task.getTaskData().getDeploymentId();
}
return deploymentId;
Expand Down

0 comments on commit 6b43985

Please sign in to comment.