/* * Copyright 2012 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. * 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 org.jbpm.kie.services.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.kie.scanner.MavenRepository.getMavenRepository; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; 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 java.util.Set; import org.drools.compiler.kie.builder.impl.InternalKieModule; import org.jbpm.kie.services.api.DeploymentIdResolver; import org.jbpm.kie.services.impl.KModuleDeploymentUnit; import org.jbpm.kie.test.objects.OtherPerson; import org.jbpm.kie.test.objects.Person; import org.jbpm.kie.test.objects.Thing; import org.jbpm.kie.test.util.AbstractKieServicesBaseTest; import org.jbpm.process.instance.impl.demo.SystemOutWorkItemHandler; import org.jbpm.services.api.model.DeploymentUnit; import org.jbpm.services.api.model.ProcessDefinition; import org.junit.After; import org.junit.Assume; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.kie.api.KieServices; import org.kie.api.builder.ReleaseId; import org.kie.api.runtime.KieSession; import org.kie.api.runtime.manager.audit.AuditService; import org.kie.api.runtime.manager.audit.VariableInstanceLog; import org.kie.api.runtime.process.ProcessInstance; import org.kie.scanner.MavenRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BPMN2DataServicesReferencesTest extends AbstractKieServicesBaseTest { private static final Logger logger = LoggerFactory.getLogger(DeploymentIdResolver.class); private List<DeploymentUnit> units = new ArrayList<DeploymentUnit>(); private DeploymentUnit deploymentUnit; private String deploymentId; private boolean loadBusinesRuleProcesses = true; private static final String PROC_ID_BUSINESS_RULE = "org.jbpm.kie.test.references.business"; private static final String RULE_BUSINESS_RULE_PROCESS = "org.jbpm.kie.test.references.rules"; private boolean loadCallActivityProcesses = true; private static final String PROC_ID_CALL_ACTIVITY = "org.jbpm.kie.test.references.parent"; private static final String PROC_ID_CALL_ACTIVITY_BY_NAME = "org.jbpm.kie.test.references.parent.name"; private static final String PROC_ID_ACTIVITY_CALLED = "org.jbpm.kie.test.references.subprocess"; private boolean loadGlobalImportProcesses = true; private static final String PROC_ID_GLOBAL = "org.jbpm.kie.test.references.global"; private static final String PROC_ID_IMPORT = "org.jbpm.kie.test.references.import"; private boolean loadJavaMvelScriptProcesses = true; private static final String PROC_ID_JAVA_SCRIPT_QUALIFIED_CLASS = "org.jbpm.kie.test.references.qualified.java"; private static final String PROC_ID_JAVA_THING_SCRIPT_QUALIFIED_CLASS = "org.jbpm.kie.test.references.qualified.java.thing"; private static final String PROC_ID_MVEL_SCRIPT_QUALIFIED_CLASS = "org.jbpm.kie.test.references.qualified.mvel"; private static final String PROC_ID_RULE_SCRIPT_QUALIFIED_CLASS = "org.jbpm.kie.test.references.qualified.drools"; private boolean loadSignalGlobalInfoProcess = true; private static final String PROC_ID_SIGNAL = "org.jbpm.signal"; @Before public void prepare() { configureServices(); KieServices ks = KieServices.Factory.get(); ReleaseId releaseId = ks.newReleaseId(GROUP_ID, ARTIFACT_ID, VERSION); List<String> resources = new ArrayList<String>(); // extension if( loadGlobalImportProcesses ) { resources.add("repo/processes/references/importWithScriptTask.bpmn2"); resources.add("repo/processes/references/globalBasedOnEntryExitScriptProcess.bpmn2"); } // call activity (referenced sub processes) if( loadCallActivityProcesses ) { resources.add("repo/processes/references/callActivityByNameParent.bpmn2"); resources.add("repo/processes/references/callActivityParent.bpmn2"); resources.add("repo/processes/references/callActivitySubProcess.bpmn2"); } // item def, business rules if( loadBusinesRuleProcesses ) { resources.add("repo/processes/references/businessRuleTask.bpmn2"); resources.add("repo/processes/references/businessRuleTask.drl"); } // qualified class in script if( loadJavaMvelScriptProcesses ) { resources.add("repo/processes/references/javaScriptTaskWithQualifiedClass.bpmn2"); resources.add("repo/processes/references/javaScriptTaskWithQualifiedClassItemDefinition.bpmn2"); resources.add("repo/processes/references/mvelScriptTaskWithQualifiedClass.bpmn2"); resources.add("repo/processes/references/rulesScriptTaskWithQualifiedClass.bpmn2"); } // qualified class in script if( loadSignalGlobalInfoProcess ) { resources.add("repo/processes/general/signal.bpmn"); } InternalKieModule kJar1 = createKieJar(ks, releaseId, resources); File pom = new File("target/kmodule", "pom.xml"); pom.getParentFile().mkdir(); FileOutputStream fs = null; try { fs = new FileOutputStream(pom); fs.write(getPom(releaseId).getBytes()); } catch (Exception e) { fail( "Unable to write pom.xml to filesystem: " + e.getMessage()); } try { fs.close(); } catch (Exception e) { logger.info("Unable to close fileystem used to write pom.xml" ); } MavenRepository repository = getMavenRepository(); repository.deployArtifact(releaseId, kJar1, pom); // check assertNotNull(deploymentService); deploymentUnit = new KModuleDeploymentUnit(GROUP_ID, ARTIFACT_ID, VERSION); deploymentService.deploy(deploymentUnit); units.add(deploymentUnit); deploymentId = deploymentUnit.getIdentifier(); procInstIds.clear(); } private Set<Long> procInstIds = new HashSet<>(); @After public void cleanup() { for( long procInstId : procInstIds ) { try { processService.abortProcessInstance(procInstId); } catch( Exception e ) { // ignore if it fails.. } } cleanupSingletonSessionId(); if (units != null && !units.isEmpty()) { for (DeploymentUnit unit : units) { deploymentService.undeploy(unit); } units.clear(); } close(); } @SafeVarargs private final long startProcess(String deploymentId, String processId, Map<String, Object>... params) { Long procInstId; if( params != null && params.length > 0 ) { procInstId = processService.startProcess(deploymentId, processId, params[0]); } else { procInstId = processService.startProcess(deploymentId, processId); } procInstIds.add(procInstId); return procInstId; } @Test public void testImport() throws IOException { Assume.assumeTrue("Skip import/global tests", loadGlobalImportProcesses); String processId = PROC_ID_IMPORT; ProcessDefinition procDef = bpmn2Service.getProcessDefinition(deploymentId, processId); assertNotNull(procDef); // check that process runs Person person = new Person(); person.setName("Max Rockatansky"); person.setId(1979l); person.setTime(3l); Map<String, Object> params = new HashMap<String, Object>(); params.put("person", person); Long procId = startProcess(deploymentId, processId, params); ProcessInstance procInst = processService.getProcessInstance(procId); assertNull(procInst); // verify process information Collection<String> refClasses = bpmn2Service.getJavaClasses(deploymentId, processId); assertNotNull( "Null set of referenced classes", refClasses ); assertFalse( "Empty set of referenced classes", refClasses.isEmpty() ); assertEquals( "Number referenced classes", 1, refClasses.size() ); assertEquals( "Imported class in process", refClasses.iterator().next(), Person.class.getName() ); } @Test public void testGlobal() throws IOException { Assume.assumeTrue("Skip import/global tests", loadGlobalImportProcesses); String processId = PROC_ID_GLOBAL; ProcessDefinition procDef = bpmn2Service.getProcessDefinition(deploymentId, processId); assertNotNull(procDef); // check that process runs Person person = new Person(); person.setName("Max Rockatansky"); person.setId(1979l); person.setTime(3l); KieSession ksession = deploymentService.getRuntimeManager(deploymentId).getRuntimeEngine(null).getKieSession(); ksession.setGlobal("person", person); ksession.getWorkItemManager().registerWorkItemHandler("MyTask", new SystemOutWorkItemHandler()); Long procId = startProcess(deploymentId, processId); ProcessInstance procInst = processService.getProcessInstance(procId); assertNull(procInst); String log = person.getLog(); assertFalse( "Empty log" , log == null || log.trim().isEmpty() ); assertEquals( "Empty log" , log.split(":").length, 4); // verify process information Collection<String> refClasses = bpmn2Service.getJavaClasses(deploymentId, processId); assertNotNull( "Null set of referenced classes", refClasses ); assertFalse( "Empty set of referenced classes", refClasses.isEmpty() ); assertEquals( "Number referenced classes", 1, refClasses.size() ); assertEquals( "Imported class in process", refClasses.iterator().next(), Person.class.getName() ); } @Test public void testCallActivityByName() throws IOException { Assume.assumeTrue("Skip call activity tests", loadCallActivityProcesses); String processId = PROC_ID_CALL_ACTIVITY_BY_NAME; ProcessDefinition procDef = bpmn2Service.getProcessDefinition(deploymentId, processId); assertNotNull(procDef); // run process (to verify that it works) Map<String, Object> params = new HashMap<String, Object>(); params.put("x", "oldValue"); Long procId = startProcess(deploymentId, processId, params); ProcessInstance procInst = processService.getProcessInstance(procId); assertNull(procInst); AuditService auditService = deploymentService.getRuntimeManager(deploymentId).getRuntimeEngine(null).getAuditService(); List<? extends VariableInstanceLog> logs = auditService.findVariableInstances(procId); boolean foundY = false; for( VariableInstanceLog log: logs ) { if( log.getVariableId().equals("y") && log.getValue().equals("new value") ) { foundY = true; } } assertTrue( "Parent process did not call sub process", foundY); // check information about process Collection<String> refProcesses = bpmn2Service.getReusableSubProcesses(deploymentId, processId); assertNotNull( "Null set of referenced processes", refProcesses ); assertFalse( "Empty set of referenced processes", refProcesses.isEmpty() ); assertEquals( "Number referenced processes", 1, refProcesses.size() ); assertEquals( "Imported class in processes", PROC_ID_ACTIVITY_CALLED, refProcesses.iterator().next() ); } @Test public void testCallActivity() throws IOException { Assume.assumeTrue("Skip call activity tests", loadCallActivityProcesses); String processId = PROC_ID_CALL_ACTIVITY; ProcessDefinition procDef = bpmn2Service.getProcessDefinition(deploymentId, processId); assertNotNull(procDef); // run process (to verify that it works) Map<String, Object> params = new HashMap<String, Object>(); params.put("x", "oldValue"); Long procId = startProcess(deploymentId, processId, params); ProcessInstance procInst = processService.getProcessInstance(procId); assertNull(procInst); AuditService auditService = deploymentService.getRuntimeManager(deploymentId).getRuntimeEngine(null).getAuditService(); List<? extends VariableInstanceLog> logs = auditService.findVariableInstances(procId); boolean foundY = false; for( VariableInstanceLog log: logs ) { if( log.getVariableId().equals("y") && log.getValue().equals("new value") ) { foundY = true; } } assertTrue( "Parent process did not call sub process", foundY); // check information about process Collection<String> refProcesses = bpmn2Service.getReusableSubProcesses(deploymentId, processId); assertNotNull( "Null set of referenced processes", refProcesses ); assertFalse( "Empty set of referenced processes", refProcesses.isEmpty() ); assertEquals( "Number referenced processes", 1, refProcesses.size() ); assertEquals( "Imported class in processes", PROC_ID_ACTIVITY_CALLED, refProcesses.iterator().next() ); } @Test public void testBusinessRuleTask() throws IOException { Assume.assumeTrue("Skip business rule tests", loadBusinesRuleProcesses); String processId = PROC_ID_BUSINESS_RULE; ProcessDefinition procDef = bpmn2Service.getProcessDefinition(deploymentId, processId); assertNotNull(procDef); // check that process runs Person person = new Person(); person.setName("Max Rockatansky"); person.setId(1979l); person.setTime(3l); KieSession ksession = deploymentService.getRuntimeManager(deploymentId).getRuntimeEngine(null).getKieSession(); List<String> list = new ArrayList<String>(); ksession.setGlobal("list", list); Long procId = startProcess(deploymentId, processId); String ruleOutput = "Executed"; assertEquals("Global did not contain output from rule!", 1, list.size()); assertEquals("Global did not contain correct output of rule!", ruleOutput, list.get(0)); ProcessInstance procInst = processService.getProcessInstance(procId); assertNull( "Process instance did not complete!", procInst ); // check information about process Collection<String> refRules = bpmn2Service.getRuleSets(deploymentId, processId); assertNotNull( "Null set of imported rules", refRules ); assertFalse( "Empty set of imported rules", refRules.isEmpty() ); assertEquals( "Number imported rules", 1, refRules.size() ); assertEquals( "Name of imported ruleset", RULE_BUSINESS_RULE_PROCESS, refRules.iterator().next() ); refRules = procDef.getReferencedRules(); assertNotNull( "Null set of imported rules", refRules ); assertFalse( "Empty set of imported rules", refRules.isEmpty() ); assertEquals( "Number imported rules", 1, refRules.size() ); assertEquals( "Name of imported ruleset", RULE_BUSINESS_RULE_PROCESS, refRules.iterator().next() ); } @Test public void testJavaScriptWithQualifiedClass() throws IOException { runScriptTest(PROC_ID_JAVA_SCRIPT_QUALIFIED_CLASS); } @Test public void testJavaThingScriptWithQualifiedClass() throws IOException { runScriptTest(PROC_ID_JAVA_THING_SCRIPT_QUALIFIED_CLASS); } @Test public void testMvelScriptWithQualifiedClass() throws IOException { runScriptTest(PROC_ID_MVEL_SCRIPT_QUALIFIED_CLASS); } private void runScriptTest(String processId) { Assume.assumeTrue("Skip script/expr tests", loadJavaMvelScriptProcesses); ProcessDefinition procDef = bpmn2Service.getProcessDefinition(deploymentId, processId); assertNotNull(procDef); // check that process runs Person person = new Person(); person.setName("Max Rockatansky"); person.setId(1979l); person.setTime(3l); Map<String, Object> params = new HashMap<String, Object>(1); params.put("person", person); Long procId = startProcess(deploymentId, processId, params); assertNull( "Process instance did not complete" , processService.getProcessInstance(procId)); assertTrue( "Script did not modify variable!", person.getLog().startsWith("Hello") ); Collection<String> javaClasses = bpmn2Service.getJavaClasses(deploymentId, processId); assertNotNull( "Null set of java classes", javaClasses ); assertFalse( "Empty set of java classes", javaClasses.isEmpty() ); assertEquals( "Number java classes", 4, javaClasses.size() ); String [] expected = { "java.lang.Object", Person.class.getCanonicalName(), OtherPerson.class.getCanonicalName(), Thing.class.getCanonicalName() }; Set<String> expectedClasses = new HashSet<String>(Arrays.asList(expected)); for( String className : javaClasses ) { assertTrue( "Class name is not qualified: " + className, className.contains(".") ); assertTrue( "Unexpected class: " + className, expectedClasses.remove(className) ); } if( ! expectedClasses.isEmpty() ) { fail( "Expected class not found to be referenced: " + expectedClasses.iterator().next() ); } } @Test @Ignore // TODO! public void testDroolsScriptWithQualifiedClass() throws Exception { Assume.assumeTrue("Skip script/expr tests", loadJavaMvelScriptProcesses); String processId = PROC_ID_RULE_SCRIPT_QUALIFIED_CLASS; ProcessDefinition procDef = bpmn2Service.getProcessDefinition(deploymentId, processId); assertNotNull(procDef); // check that process runs Person person = new Person(); person.setName("Max"); person.setId(1979l); person.setTime(3l); KieSession ksession = deploymentService.getRuntimeManager(deploymentId).getRuntimeEngine(null).getKieSession(); ksession.insert(person); ksession.insert(new Thing()); ksession.insert(new OtherPerson(person)); ksession.insert(person.getName()); ksession.insert(person.getId()); Long procId = startProcess(deploymentId, processId); assertNull( "Process instance did not complete:" , processService.getProcessInstance(procId)); Collection<String> javaClasses = bpmn2Service.getJavaClasses(deploymentId, processId); assertNotNull( "Null set of java classes", javaClasses ); assertFalse( "Empty set of java classes", javaClasses.isEmpty() ); assertEquals( "Number java classes", 4, javaClasses.size() ); String [] expected = { "java.lang.Object", Person.class.getCanonicalName(), OtherPerson.class.getCanonicalName(), Thing.class.getCanonicalName() }; Set<String> expectedClasses = new HashSet<String>(Arrays.asList(expected)); for( String className : javaClasses ) { assertTrue( "Class name is not qualified: " + className, className.contains(".") ); assertTrue( "Unexpected class: " + className, expectedClasses.remove(className) ); } if( ! expectedClasses.isEmpty() ) { fail( "Expected class not found to be referenced: " + expectedClasses.iterator().next() ); } } @Test public void testSignalsAndGlobals() throws IOException { Assume.assumeTrue("Skip signal/global tests", loadSignalGlobalInfoProcess); String processId = PROC_ID_SIGNAL; // check that process starts KieSession ksession = deploymentService.getRuntimeManager(deploymentId).getRuntimeEngine(null).getKieSession(); ksession.setGlobal("person", new Person()); long procInstId = startProcess(deploymentId, processId); ProcessDefinition procDef = bpmn2Service.getProcessDefinition(deploymentId, processId); assertNotNull(procDef); // check information about process assertNotNull( "Null signals list", procDef.getSignals() ); assertFalse( "Empty signals list", procDef.getSignals().isEmpty() ); assertEquals( "Unexpected signal", "MySignal", procDef.getSignals().iterator().next() ); Collection<String> globalNames = procDef.getGlobals(); assertNotNull( "Null globals list", globalNames ); assertFalse( "Empty globals list", globalNames.isEmpty() ); assertEquals( "globals list size", 2, globalNames.size() ); for( String globalName : globalNames ) { assertTrue( "Unexpected global: " + globalName, "person".equals(globalName) || "name".equals(globalName) ); } // cleanup processService.abortProcessInstance(procInstId); } }