/* Copyright (c) 2014, Effektif GmbH.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 com.effektif.workflow.test.impl;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.effektif.workflow.api.json.TypeName;
import com.effektif.workflow.api.model.TriggerInstance;
import com.effektif.workflow.api.model.WorkflowId;
import com.effektif.workflow.api.model.WorkflowInstanceId;
import com.effektif.workflow.api.query.WorkflowInstanceQuery;
import com.effektif.workflow.api.workflow.Activity;
import com.effektif.workflow.api.workflow.ExecutableWorkflow;
import com.effektif.workflow.impl.WorkflowInstanceStore;
import com.effektif.workflow.impl.activity.AbstractActivityType;
import com.effektif.workflow.impl.workflowinstance.ActivityInstanceImpl;
import com.effektif.workflow.impl.workflowinstance.UnlockListener;
import com.effektif.workflow.impl.workflowinstance.WorkflowInstanceImpl;
import com.effektif.workflow.test.WorkflowTest;
/** UnlockListener is a feature to notify external services after
* the workflow instance has been unlocked.
*
* Wait states will pause the execution till an external
* message comes in that resumes execution of the workflow instance.
* When that message arrives, the workflow instance has to be locked.
* When the external work is automatic (not a user task) you may want
* to push a notification to the external service notifying
* a new activity instance has to be performed.
* If that notification is sent straight from inside the execute
* method of the wait state activity, the external service might
* send the message before the workflow instance is unlocked.
* This would cause a lock exception and retry.
*
* @author Tom Baeyens
*/
public class UnlockListenerTest extends WorkflowTest {
static List<String> notificationsReceived = null; // initialized in resetNotificationsReceived()
public static class Listener implements UnlockListener {
ActivityInstanceImpl activityInstance;
public Listener(ActivityInstanceImpl activityInstance) {
this.activityInstance = activityInstance;
}
@Override
public void unlocked(WorkflowInstanceImpl workflowInstanceImpl) {
// When the notification is received, we now check
// if the workflow instance store actually is unlocked
WorkflowInstanceId workflowInstanceId = workflowInstanceImpl.getId();
WorkflowInstanceQuery workflowInstanceQuery = new WorkflowInstanceQuery().workflowInstanceId(workflowInstanceId);
WorkflowInstanceImpl storedWorkflowInstance = cachedConfiguration
.get(WorkflowInstanceStore.class)
.findWorkflowInstances(workflowInstanceQuery)
.get(0);
assertNull(storedWorkflowInstance.lock);
String notificationMessage = "Activity "+activityInstance.activity.id+" is started "+
"and it's workflow instance unlocked";
notificationsReceived.add(notificationMessage);
}
}
@TypeName("unlockListening")
public static class ListeningActivity extends Activity {
}
public static class ListeningActivityImpl extends AbstractActivityType {
public ListeningActivityImpl() {
super(ListeningActivity.class);
}
@Override
public void execute(ActivityInstanceImpl activityInstance) {
// Notifications should only be sent out after the workflow instance
// is unlocked.
activityInstance.workflowInstance.addUnlockListener(new Listener(activityInstance));
// ListeningActivityImpl is typically a wait state
}
}
@Before
public void resetNotificationsReceived() {
notificationsReceived = new ArrayList<>();
}
@Test
public void testUnlockListener() {
// Create a workflow
ExecutableWorkflow workflow = new ExecutableWorkflow()
.activity("a", new ListeningActivity());
// Deploy the workflow to the engine
WorkflowId workflowId = workflowEngine
.deployWorkflow(workflow)
.checkNoErrorsAndNoWarnings()
.getWorkflowId();
// Start a new workflow instance
workflowEngine
.start(new TriggerInstance()
.workflowId(workflowId));
assertEquals("Activity a is started and it's workflow instance unlocked", notificationsReceived.get(0));
}
}