/* * Copyright 2010 salaboy. * * 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. * under the License. */ package org.drools.services; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.rmi.RemoteException; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import org.apache.commons.collections.map.HashedMap; import org.apache.mina.transport.socket.SocketAcceptor; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; import org.drools.KnowledgeBase; import org.drools.KnowledgeBaseFactoryService; import org.drools.SystemEventListenerFactory; import org.drools.builder.KnowledgeBuilder; import org.drools.builder.KnowledgeBuilderFactoryService; import org.drools.grid.ConnectorException; import org.drools.grid.ExecutionNode; import org.drools.grid.internal.GenericMessageHandlerImpl; import org.drools.grid.internal.NodeData; import org.drools.grid.remote.mina.MinaAcceptor; import org.drools.grid.remote.mina.MinaIoHandler; import org.drools.grid.services.ExecutionEnvironment; import org.drools.grid.services.GridTopology; import org.drools.grid.services.TaskServerInstance; import org.drools.grid.services.configuration.ExecutionEnvironmentConfiguration; import org.drools.grid.services.configuration.GridTopologyConfiguration; import org.drools.grid.services.configuration.MinaProvider; import org.drools.grid.services.configuration.TaskServerInstanceConfiguration; import org.drools.grid.services.factory.GridTopologyFactory; import org.drools.grid.task.CommandBasedServicesWSHumanTaskHandler; import org.drools.grid.task.HumanTaskService; import org.drools.grid.task.TaskServerMessageHandlerImpl; import org.drools.grid.task.responseHandlers.BlockingTaskOperationMessageResponseHandler; import org.drools.grid.task.responseHandlers.BlockingTaskSummaryMessageResponseHandler; import org.drools.io.impl.ClassPathResource; import org.drools.process.instance.impl.WorkItemImpl; import org.drools.runtime.StatefulKnowledgeSession; import org.drools.runtime.process.WorkItem; import org.drools.runtime.process.WorkItemHandler; import org.drools.runtime.process.WorkItemManager; import org.drools.services.task.MockUserInfo; import org.drools.task.Group; import org.drools.task.Status; import org.drools.task.User; import org.drools.task.query.TaskSummary; import org.drools.task.service.TaskService; import org.drools.task.service.TaskServiceSession; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.mvel2.MVEL; import org.mvel2.ParserContext; import org.mvel2.compiler.ExpressionCompiler; /** * * @author salaboy */ public class RegisterTaskTest { private GridTopology grid; private MinaAcceptor serverTask; private MinaAcceptor serverNode; private HumanTaskService client; private EntityManagerFactory emf; private TaskService taskService; private TaskServiceSession taskSession; protected Map<String, User> users; protected Map<String, Group> groups; protected static final int DEFAULT_WAIT_TIME = 5000; protected static final int MANAGER_COMPLETION_WAIT_TIME = DEFAULT_WAIT_TIME; protected static final int MANAGER_ABORT_WAIT_TIME = DEFAULT_WAIT_TIME; protected CommandBasedServicesWSHumanTaskHandler handler; public RegisterTaskTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() throws InterruptedException, IOException { //Task Related Stuff // Use persistence.xml configuration this.emf = Persistence.createEntityManagerFactory( "org.drools.task" ); this.taskService = new TaskService( this.emf, SystemEventListenerFactory.getSystemEventListener() ); this.taskSession = this.taskService.createSession(); MockUserInfo userInfo = new MockUserInfo(); this.taskService.setUserinfo( userInfo ); Map vars = new HashedMap(); Reader reader = null; try { reader = new InputStreamReader( new ClassPathResource( "org/drools/task/LoadUsers.mvel" ).getInputStream() ); this.users = (Map<String, User>) eval( reader, vars ); for ( User user : this.users.values() ) { this.taskSession.addUser( user ); } } finally { if ( reader != null ) { reader.close(); } reader = null; } try { reader = new InputStreamReader( new ClassPathResource( "org/drools/task/LoadGroups.mvel" ).getInputStream() ); this.groups = (Map<String, Group>) eval( reader, vars ); for ( Group group : this.groups.values() ) { this.taskSession.addGroup( group ); } } finally { if ( reader != null ) { reader.close(); } } // Human task Server configuration SocketAddress htAddress = new InetSocketAddress( "127.0.0.1", 9123 ); SocketAcceptor htAcceptor = new NioSocketAcceptor(); htAcceptor.setHandler( new MinaIoHandler( SystemEventListenerFactory.getSystemEventListener(), new TaskServerMessageHandlerImpl( this.taskService, SystemEventListenerFactory.getSystemEventListener() ) ) ); this.serverTask = new MinaAcceptor( htAcceptor, htAddress ); this.serverTask.start(); Thread.sleep( 5000 ); // End Execution Server //Execution Node related stuff System.out.println( "Server 1 Starting!" ); // the servers should be started in a different machine (jvm or physical) or in another thread SocketAddress address = new InetSocketAddress( "127.0.0.1", 9124 ); NodeData nodeData = new NodeData(); // setup Server SocketAcceptor acceptor = new NioSocketAcceptor(); acceptor.setHandler( new MinaIoHandler( SystemEventListenerFactory.getSystemEventListener(), new GenericMessageHandlerImpl( nodeData, SystemEventListenerFactory.getSystemEventListener() ) ) ); this.serverNode = new MinaAcceptor( acceptor, address ); this.serverNode.start(); System.out.println( "Server 1 Started! at = " + address.toString() ); Thread.sleep( 5000 ); } @After public void tearDown() throws InterruptedException, ConnectorException, RemoteException { this.client.disconnect(); this.grid.dispose(); this.handler.dispose(); Assert.assertEquals( 0, this.serverNode.getCurrentSessions() ); this.serverNode.stop(); System.out.println( "Execution Server Stopped!" ); Assert.assertEquals( 0, this.serverTask.getCurrentSessions() ); this.serverTask.stop(); System.out.println( "Task Server Stopped!" ); this.taskSession.dispose(); this.emf.close(); } @Test public void MinaTaskTest() throws InterruptedException, ConnectorException, RemoteException { GridTopologyConfiguration gridTopologyConfiguration = new GridTopologyConfiguration( "MyTopology" ); gridTopologyConfiguration.addTaskServerInstance( new TaskServerInstanceConfiguration( "MyMinaTask", new MinaProvider( "127.0.0.1", 9123 ) ) ); gridTopologyConfiguration.addExecutionEnvironment( new ExecutionEnvironmentConfiguration( "MyMinaExecutionEnv1", new MinaProvider( "127.0.0.1", 9124 ) ) ); this.grid = GridTopologyFactory.build( gridTopologyConfiguration ); Assert.assertNotNull( this.grid ); TaskServerInstance taskServer = this.grid.getTaskServerInstance( "MyMinaTask" ); Assert.assertNotNull( taskServer ); this.client = taskServer.getHumanTaskNode().get( HumanTaskService.class ); Assert.assertNotNull( this.client ); //Create a task to test the HT client. For that we need to have a ksession with a workitem that creates it ExecutionEnvironment ee = this.grid.getExecutionEnvironment( "MyMinaExecutionEnv1" ); Assert.assertNotNull( ee ); // Give me an ExecutionNode in the selected environment // For the Mina we have just one Execution Node per server instance ExecutionNode node = ee.getExecutionNode(); Assert.assertNotNull( node ); KnowledgeBuilder kbuilder = node.get( KnowledgeBuilderFactoryService.class ).newKnowledgeBuilder(); KnowledgeBase kbase = node.get( KnowledgeBaseFactoryService.class ).newKnowledgeBase(); Assert.assertNotNull( kbase ); kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() ); StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); Assert.assertNotNull( ksession ); this.handler = new CommandBasedServicesWSHumanTaskHandler( ksession ); this.handler.setAddress( "127.0.0.1", 9123 ); TestWorkItemManager manager = new TestWorkItemManager(); WorkItemImpl workItem = new WorkItemImpl(); workItem.setName( "Human Task" ); workItem.setParameter( "TaskName", "TaskName" ); workItem.setParameter( "Comment", "Comment" ); workItem.setParameter( "Priority", "10" ); workItem.setParameter( "ActorId", "Darth Vader" ); this.handler.executeWorkItem( workItem, manager ); Thread.sleep( 500 ); BlockingTaskSummaryMessageResponseHandler responseHandler = new BlockingTaskSummaryMessageResponseHandler(); this.client.getTasksAssignedAsPotentialOwner( "Darth Vader", "en-UK", responseHandler ); responseHandler.waitTillDone( DEFAULT_WAIT_TIME ); List<TaskSummary> tasks = responseHandler.getResults(); Assert.assertEquals( 1, tasks.size() ); TaskSummary task = tasks.get( 0 ); Assert.assertEquals( "TaskName", task.getName() ); Assert.assertEquals( 10, task.getPriority() ); Assert.assertEquals( "Comment", task.getDescription() ); Assert.assertEquals( Status.Reserved, task.getStatus() ); Assert.assertEquals( "Darth Vader", task.getActualOwner().getId() ); System.out.println( "Starting task " + task.getId() ); BlockingTaskOperationMessageResponseHandler operationResponseHandler = new BlockingTaskOperationMessageResponseHandler(); this.client.start( task.getId(), "Darth Vader", operationResponseHandler ); operationResponseHandler.waitTillDone( DEFAULT_WAIT_TIME ); System.out.println( "Started task " + task.getId() ); System.out.println( "Completing task " + task.getId() ); operationResponseHandler = new BlockingTaskOperationMessageResponseHandler(); this.client.complete( task.getId(), "Darth Vader", null, operationResponseHandler ); operationResponseHandler.waitTillDone( 15000 ); System.out.println( "Completed task " + task.getId() ); Assert.assertTrue( manager.waitTillCompleted( DEFAULT_WAIT_TIME ) ); Thread.sleep( 500 ); taskServer.getConnector().disconnect(); } private Object eval(Reader reader, Map<String, Object> vars) { try { return eval( toString( reader ), vars ); } catch ( IOException e ) { throw new RuntimeException( "Exception Thrown", e ); } } private String toString(Reader reader) throws IOException { int charValue = 0; StringBuffer sb = new StringBuffer( 1024 ); while ( (charValue = reader.read()) != -1 ) { // result = result + (char) charValue; sb.append( (char) charValue ); } return sb.toString(); } private Object eval(String str, Map<String, Object> vars) { ExpressionCompiler compiler = new ExpressionCompiler( str.trim() ); ParserContext context = new ParserContext(); context.addPackageImport( "org.drools.task" ); context.addPackageImport( "org.drools.task.service" ); context.addPackageImport( "org.drools.task.query" ); context.addPackageImport( "java.util" ); vars.put( "now", new Date() ); return MVEL.executeExpression( compiler.compile( context ), vars ); } } class TestWorkItemManager implements WorkItemManager { private volatile boolean completed; private volatile boolean aborted; private volatile Map<String, Object> results; public synchronized boolean waitTillCompleted(long time) { if ( !isCompleted() ) { try { wait( time ); } catch ( InterruptedException e ) { // swallow and return state of completed } } return isCompleted(); } public synchronized boolean waitTillAborted(long time) { if ( !isAborted() ) { try { wait( time ); } catch ( InterruptedException e ) { // swallow and return state of aborted } } return isAborted(); } public void abortWorkItem(long id) { setAborted( true ); } public synchronized boolean isAborted() { return this.aborted; } private synchronized void setAborted(boolean aborted) { this.aborted = aborted; notifyAll(); } public void completeWorkItem(long id, Map<String, Object> results) { this.results = results; setCompleted( true ); } private synchronized void setCompleted(boolean completed) { this.completed = completed; notifyAll(); } public synchronized boolean isCompleted() { return this.completed; } public WorkItem getWorkItem(long id) { return null; } public Set<WorkItem> getWorkItems() { return null; } public Map<String, Object> getResults() { return this.results; } public void internalAbortWorkItem(long id) { } public void internalAddWorkItem(WorkItem workItem) { } public void internalExecuteWorkItem(WorkItem workItem) { } public void registerWorkItemHandler(String workItemName, WorkItemHandler handler) { } }