/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* 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.server.integrationtests.jbpm.jms;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runners.Parameterized;
import org.kie.api.KieServices;
import org.kie.api.task.model.Status;
import org.kie.server.api.marshalling.Marshaller;
import org.kie.server.api.marshalling.MarshallerFactory;
import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.api.model.ReleaseId;
import org.kie.server.api.model.ServiceResponse;
import org.kie.server.api.model.ServiceResponsesList;
import org.kie.server.api.model.definition.QueryDefinition;
import org.kie.server.api.model.instance.ProcessInstance;
import org.kie.server.api.model.instance.ProcessInstanceList;
import org.kie.server.api.model.instance.TaskInstance;
import org.kie.server.api.model.instance.TaskSummary;
import org.kie.server.api.model.instance.TaskSummaryList;
import org.kie.server.client.KieServicesClient;
import org.kie.server.client.KieServicesConfiguration;
import org.kie.server.client.KieServicesFactory;
import org.kie.server.client.ProcessServicesClient;
import org.kie.server.client.QueryServicesClient;
import org.kie.server.client.jms.AsyncResponseHandler;
import org.kie.server.client.jms.BlockingResponseCallback;
import org.kie.server.client.jms.FireAndForgetResponseHandler;
import org.kie.server.client.jms.RequestReplyResponseHandler;
import org.kie.server.client.jms.ResponseCallback;
import org.kie.server.client.jms.ResponseHandler;
import org.kie.server.integrationtests.category.JMSOnly;
import org.kie.server.integrationtests.jbpm.JbpmKieServerBaseIntegrationTest;
import org.kie.server.integrationtests.shared.KieServerAssert;
import org.kie.server.integrationtests.shared.KieServerDeployer;
import org.kie.server.integrationtests.shared.KieServerSynchronization;
@Category({JMSOnly.class})
public class JmsResponseHandlerIntegrationTest extends JbpmKieServerBaseIntegrationTest {
private static final ReleaseId RELEASE_ID = new ReleaseId("org.kie.server.testing", "definition-project", "1.0.0.Final");
@Parameterized.Parameters(name = "{index}: {0}")
public static Collection<Object[]> data() {
KieServicesConfiguration jmsConfiguration = createKieServicesJmsConfiguration();
Collection<Object[]> parameterData = new ArrayList<>(Arrays.asList(new Object[][]{
{MarshallingFormat.JAXB, jmsConfiguration},
{MarshallingFormat.JSON, jmsConfiguration},
{MarshallingFormat.XSTREAM, jmsConfiguration}
}));
return parameterData;
}
@BeforeClass
public static void buildAndDeployArtifacts() {
KieServerDeployer.buildAndDeployCommonMavenParent();
KieServerDeployer.buildAndDeployMavenProject(ClassLoader.class.getResource("/kjars-sources/definition-project").getFile());
KieServerDeployer.buildAndDeployMavenProject(ClassLoader.class.getResource("/kjars-sources/query-definition-project").getFile());
kieContainer = KieServices.Factory.get().newKieContainer(RELEASE_ID);
createContainer(CONTAINER_ID, RELEASE_ID);
}
@After
public void resetResponseHandler() {
processClient.setResponseHandler(new RequestReplyResponseHandler());
queryClient.setResponseHandler(new RequestReplyResponseHandler());
taskClient.setResponseHandler(new RequestReplyResponseHandler());
}
@Override
protected void addExtraCustomClasses(Map<String, Class<?>> extraClasses) throws Exception {
extraClasses.put(PERSON_CLASS_NAME, Class.forName(PERSON_CLASS_NAME, true, kieContainer.getClassLoader()));
}
@Test
public void testStartProcessUseOfFireAndForgetResponseHandler() throws Exception {
testStartProcessResponseHandler(new FireAndForgetResponseHandler());
}
@Test
public void testStartProcessUseOfAsyncResponseHandler() throws Exception {
ResponseCallback callback = new BlockingResponseCallback(null);
testStartProcessResponseHandler(new AsyncResponseHandler(callback));
// now let's check if response has arrived
ServiceResponsesList response = callback.get();
assertThat(response).isNotNull();
assertThat(response.getResponses()).isNotNull().hasSize(1);
KieServerAssert.assertSuccess(response.getResponses().get(0));
ServiceResponse<? extends Object> serviceResponse = response.getResponses().get(0);
Object result = serviceResponse.getResult();
assertThat(result).isNotNull();
}
@Test
public void testStartProcessUseOfAsyncResponseHandlerWithMarshaller() throws Exception {
ResponseCallback callback = new BlockingResponseCallback(createMarshaller());
testStartProcessResponseHandler(new AsyncResponseHandler(callback));
// now let's check if response has arrived
Long processInstanceId = callback.get(Long.class);
assertThat(processInstanceId).isNotNull().isPositive();
}
@Test
public void testGetProcessInstancesUseOfAsyncResponseHandlerWithMarshaller() throws Exception {
ResponseCallback callback = new BlockingResponseCallback(createMarshaller());
testGetProcessInstancesResponseHandler(new AsyncResponseHandler(callback));
// now let's check if response has arrived
ProcessInstanceList processInstanceList = callback.get(ProcessInstanceList.class);
assertThat(processInstanceList).isNotNull();
assertThat(processInstanceList.getItems()).isNotNull().hasSize(1);
}
@Test
public void testGetTasksUseOfAsyncResponseHandlerWithMarshaller() throws Exception {
ResponseCallback callback = new BlockingResponseCallback(createMarshaller());
testGetTaskResponseHandler(new AsyncResponseHandler(callback));
// now let's check if response has arrived
TaskSummaryList taskSummaryList = callback.get(TaskSummaryList.class);
assertThat(taskSummaryList).isNotNull();
assertThat(taskSummaryList.getItems()).isNotNull().hasSize(1);
}
@Test
public void testStartAndCompleteTaskUseOfFireAndForgetResponseHandler() throws Exception {
testStartAndCompleteTask(new FireAndForgetResponseHandler());
}
@Test
public void testStartAndCompleteTaskUseOfAsyncResponseHandler() throws Exception {
ResponseCallback callback = new BlockingResponseCallback(null);
testStartAndCompleteTask(new AsyncResponseHandler(callback));
}
@Test
public void testQueryRegistrationUseOfFireAndForgetResponseHandler() throws Exception {
testQueryRegistration(new FireAndForgetResponseHandler());
}
@Test
public void testQueryRegistrationUseOfAsyncResponseHandler() throws Exception {
ResponseCallback callback = new BlockingResponseCallback(null);
testQueryRegistration(new AsyncResponseHandler(callback));
}
@Test
public void testGlobalConfigurationOfFireAndForgetResponseHandler() throws Exception {
testStartProcessWithGlobalConfiguration(new FireAndForgetResponseHandler());
}
@Test
public void testGlobalConfigurationOfAsyncResponseHandler() throws Exception {
ResponseCallback callback = new BlockingResponseCallback(createMarshaller());
testStartProcessWithGlobalConfiguration(new AsyncResponseHandler(callback));
Long processInstanceId = callback.get(Long.class);
assertThat(processInstanceId).isNotNull().isPositive();
}
/*
* helper methods that comes with tests that can be invoked with various response handlers
*/
private void testStartProcessResponseHandler(ResponseHandler responseHandler) throws Exception {
List<ProcessInstance> processInstances = queryClient.findProcessInstances(0, 100);
assertThat(processInstances).isEmpty();
// change response handler for processClient others are not affected
processClient.setResponseHandler(responseHandler);
Long processInstanceId = processClient.startProcess(CONTAINER_ID, PROCESS_ID_USERTASK);
// since we use fire and forget there will always be null response
assertThat(processInstanceId).isNull();
KieServerSynchronization.waitForProcessInstanceStart(queryClient, CONTAINER_ID);
// Process should be started completely async - fire and forget.
processInstances = queryClient.findProcessInstances(0, 100);
assertThat(processInstances).hasSize(1);
ProcessInstance pi = processInstances.get(0);
assertThat(pi.getState()).isEqualTo(org.kie.api.runtime.process.ProcessInstance.STATE_ACTIVE);
}
private void testGetProcessInstancesResponseHandler(ResponseHandler responseHandler) throws Exception {
List<ProcessInstance> processInstances = queryClient.findProcessInstances(0, 100);
assertThat(processInstances).isEmpty();
Long processInstanceId = processClient.startProcess(CONTAINER_ID, PROCESS_ID_USERTASK);
assertThat(processInstanceId).isNotNull();
KieServerSynchronization.waitForProcessInstanceStart(queryClient, CONTAINER_ID);
// change response handler for queryClient others are not affected
queryClient.setResponseHandler(responseHandler);
// Process should be started completely async - fire and forget.
processInstances = queryClient.findProcessInstances(0, 100);
assertThat(processInstances).isNull();
// set it back for the sake of verification
queryClient.setResponseHandler(new RequestReplyResponseHandler());
// Process should be started completely async - fire and forget.
processInstances = queryClient.findProcessInstances(0, 100);
assertThat(processInstances).isNotNull().hasSize(1);
ProcessInstance pi = processInstances.get(0);
assertThat(pi.getState()).isEqualTo(org.kie.api.runtime.process.ProcessInstance.STATE_ACTIVE);
}
private void testGetTaskResponseHandler(ResponseHandler responseHandler) throws Exception {
List<ProcessInstance> processInstances = queryClient.findProcessInstances(0, 100);
assertThat(processInstances).isEmpty();
Long processInstanceId = processClient.startProcess(CONTAINER_ID, PROCESS_ID_USERTASK);
assertThat(processInstanceId).isNotNull();
KieServerSynchronization.waitForProcessInstanceStart(queryClient, CONTAINER_ID);
// Process should be started completely async - fire and forget.
processInstances = queryClient.findProcessInstances(0, 100);
assertThat(processInstances).isNotNull().hasSize(1);
ProcessInstance pi = processInstances.get(0);
assertThat(pi.getState()).isEqualTo(org.kie.api.runtime.process.ProcessInstance.STATE_ACTIVE);
// change response handler for taskClient others are not affected
taskClient.setResponseHandler(responseHandler);
List<TaskSummary> tasks = taskClient.findTasksAssignedAsPotentialOwner(USER_YODA, 0, 10);
assertThat(tasks).isNull();
}
private void testStartAndCompleteTask(ResponseHandler responseHandler) throws Exception {
Long processInstanceId = processClient.startProcess(CONTAINER_ID, PROCESS_ID_USERTASK);
assertThat(processInstanceId).isNotNull();
List<ProcessInstance> processInstances = queryClient.findProcessInstances(0, 100);
assertThat(processInstances).isNotNull().hasSize(1);
assertThat(processInstances.get(0)).isNotNull();
assertThat(processInstances.get(0).getState()).isEqualTo(org.kie.api.runtime.process.ProcessInstance.STATE_ACTIVE);
List<TaskSummary> tasks = taskClient.findTasksAssignedAsPotentialOwner(USER_YODA, 0, 10);
assertThat(tasks).hasSize(1);
Long taskId = tasks.get(0).getId();
taskClient.setResponseHandler(responseHandler);
taskClient.startTask(CONTAINER_ID, taskId, USER_YODA);
taskClient.setResponseHandler(new RequestReplyResponseHandler());
KieServerSynchronization.waitForTaskStatus(taskClient, taskId, Status.InProgress.name());
taskClient.setResponseHandler(responseHandler);
taskClient.completeTask(CONTAINER_ID, taskId, USER_YODA, new HashMap<String, Object>());
taskClient.setResponseHandler(new RequestReplyResponseHandler());
KieServerSynchronization.waitForTaskStatus(taskClient, taskId, Status.Completed.name());
tasks = taskClient.findTasksAssignedAsPotentialOwner(USER_YODA, 0, 10);
assertThat(tasks).hasSize(1);
taskId = tasks.get(0).getId();
taskClient.setResponseHandler(responseHandler);
taskClient.startTask(CONTAINER_ID, taskId, USER_YODA);
taskClient.setResponseHandler(new RequestReplyResponseHandler());
KieServerSynchronization.waitForTaskStatus(taskClient, taskId, Status.InProgress.name());
taskClient.setResponseHandler(responseHandler);
taskClient.completeTask(CONTAINER_ID, taskId, USER_YODA, new HashMap<String, Object>());
KieServerSynchronization.waitForProcessInstanceToFinish(processClient, CONTAINER_ID, processInstanceId);
}
private void testQueryRegistration(ResponseHandler responseHandler) throws Exception {
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("stringData", "waiting for signal");
parameters.put("personData", createPersonInstance(CONTAINER_ID));
processClient.startProcess(CONTAINER_ID, PROCESS_ID_USERTASK, parameters);
QueryDefinition query = new QueryDefinition();
query.setName("getTasksByState");
query.setSource(System.getProperty("org.kie.server.persistence.ds", "jdbc/jbpm-ds"));
query.setExpression("select * from AuditTaskImpl where status = 'Reserved'");
query.setTarget("CUSTOM");
queryClient.setResponseHandler(responseHandler);
queryClient.registerQuery(query);
try {
queryClient.setResponseHandler(new RequestReplyResponseHandler());
KieServerSynchronization.waitForQuery(queryClient, query);
List<TaskInstance> tasks = queryClient.query(query.getName(), QueryServicesClient.QUERY_MAP_TASK, 0, 10, TaskInstance.class);
assertThat(tasks).isNotNull().hasSize(1);
Long taskId = tasks.get(0).getId();
query.setExpression("select * from AuditTaskImpl where status = 'InProgress'");
queryClient.setResponseHandler(responseHandler);
queryClient.replaceQuery(query);
queryClient.setResponseHandler(new RequestReplyResponseHandler());
KieServerSynchronization.waitForQuery(queryClient, query);
tasks = queryClient.query(query.getName(), QueryServicesClient.QUERY_MAP_TASK, 0, 10, TaskInstance.class);
assertThat(tasks).isNotNull().isEmpty();
taskClient.startTask(CONTAINER_ID, taskId, USER_YODA);
tasks = queryClient.query(query.getName(), QueryServicesClient.QUERY_MAP_TASK, 0, 10, TaskInstance.class);
assertThat(tasks).isNotNull().hasSize(1);
assertThat(tasks.get(0).getId()).isEqualTo(taskId);
} catch (Exception e) {
queryClient.setResponseHandler(new RequestReplyResponseHandler());
queryClient.unregisterQuery(query.getName());
throw e;
}
queryClient.setResponseHandler(responseHandler);
queryClient.unregisterQuery(query.getName());
queryClient.setResponseHandler(new RequestReplyResponseHandler());
KieServerSynchronization.waitForQueryRemoval(queryClient, query);
}
private void testStartProcessWithGlobalConfiguration(ResponseHandler responseHandler) throws Exception {
KieServicesConfiguration jmsConfiguration = createKieServicesJmsConfiguration();
jmsConfiguration.setMarshallingFormat(marshallingFormat);
jmsConfiguration.setResponseHandler(responseHandler);
KieServicesClient kieServicesClient = KieServicesFactory.newKieServicesClient(jmsConfiguration);
ProcessServicesClient fireAndForgetProcessClient = kieServicesClient.getServicesClient(ProcessServicesClient.class);
Long processInstanceId = fireAndForgetProcessClient.startProcess(CONTAINER_ID, PROCESS_ID_USERTASK);
assertThat(processInstanceId).isNull();
KieServerSynchronization.waitForProcessInstanceStart(queryClient, CONTAINER_ID);
abortAllProcesses();
}
private Marshaller createMarshaller() {
return MarshallerFactory.getMarshaller(new HashSet<>(extraClasses.values()),
configuration.getMarshallingFormat(), client.getClassLoader());
}
}