/** * Copyright 2010 JBoss Inc * * 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.drools.grid.task; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.drools.SystemEventListenerFactory; import org.drools.eventmessaging.EventKey; import org.drools.eventmessaging.Payload; import org.drools.grid.ConnectorException; import org.drools.grid.GenericNodeConnector; import org.drools.grid.internal.Message; import org.drools.grid.task.TaskClientMessageHandlerImpl.AddTaskMessageResponseHandler; import org.drools.grid.task.TaskClientMessageHandlerImpl.GetContentMessageResponseHandler; import org.drools.grid.task.TaskClientMessageHandlerImpl.GetTaskMessageResponseHandler; import org.drools.grid.task.eventmessaging.EventMessageResponseHandler; import org.drools.runtime.KnowledgeRuntime; 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.task.AccessType; import org.drools.task.Content; import org.drools.task.Group; import org.drools.task.I18NText; import org.drools.task.OrganizationalEntity; import org.drools.task.PeopleAssignments; import org.drools.task.SubTasksStrategy; import org.drools.task.SubTasksStrategyFactory; import org.drools.task.Task; import org.drools.task.TaskData; import org.drools.task.User; import org.drools.task.event.TaskCompletedEvent; import org.drools.task.event.TaskEvent; import org.drools.task.event.TaskEventKey; import org.drools.task.event.TaskFailedEvent; import org.drools.task.event.TaskSkippedEvent; import org.drools.task.service.Command; import org.drools.task.service.ContentData; import org.drools.task.service.responsehandlers.AbstractBaseResponseHandler; /** * @author salaboy * @author Lucas Amador * */ public class CommandBasedServicesWSHumanTaskHandler implements WorkItemHandler { private String ipAddress = "127.0.0.1"; private int port = 9124; private GenericNodeConnector connector; private HumanTaskServiceRemoteClient client; private KnowledgeRuntime session; private Map<Long, Long> idMapping = new HashMap<Long, Long>(); private Map<Long, WorkItemManager> managers = new HashMap<Long, WorkItemManager>(); public CommandBasedServicesWSHumanTaskHandler(KnowledgeRuntime session) { this.session = session; } public void setAddress(String ipAddress, int port) { this.ipAddress = ipAddress; this.port = port; } public void connect() throws ConnectorException, RemoteException { if ( this.connector == null ) { this.connector = new RemoteMinaHumanTaskConnector( "client ht", this.ipAddress, this.port, SystemEventListenerFactory.getSystemEventListener() ); int id = ((StatefulKnowledgeSession) this.session).getId(); this.connector.connect(); this.client = new HumanTaskServiceRemoteClient( this.connector, id ); } } public void executeWorkItem(WorkItem workItem, WorkItemManager manager) { try { connect(); } catch ( RemoteException ex ) { Logger.getLogger( CommandBasedServicesWSHumanTaskHandler.class.getName() ).log( Level.SEVERE, null, ex ); } catch ( ConnectorException ex ) { Logger.getLogger( CommandBasedServicesWSHumanTaskHandler.class.getName() ).log( Level.SEVERE, null, ex ); return; } Task task = new Task(); String taskName = (String) workItem.getParameter( "TaskName" ); if ( taskName != null ) { List<I18NText> names = new ArrayList<I18NText>(); names.add( new I18NText( "en-UK", taskName ) ); task.setNames( names ); } String comment = (String) workItem.getParameter( "Comment" ); if ( comment != null ) { List<I18NText> descriptions = new ArrayList<I18NText>(); descriptions.add( new I18NText( "en-UK", comment ) ); task.setDescriptions( descriptions ); List<I18NText> subjects = new ArrayList<I18NText>(); subjects.add( new I18NText( "en-UK", comment ) ); task.setSubjects( subjects ); } String priorityString = (String) workItem.getParameter( "Priority" ); int priority = 0; if ( priorityString != null ) { try { priority = new Integer( priorityString ); } catch ( NumberFormatException e ) { // do nothing } } task.setPriority( priority ); TaskData taskData = new TaskData(); taskData.setWorkItemId( workItem.getId() ); taskData.setSkipable( !"false".equals( workItem.getParameter( "Skippable" ) ) ); //Sub Task Data Long parentId = (Long) workItem.getParameter( "ParentId" ); if ( parentId != null ) { taskData.setParentId( parentId ); } String subTaskStrategiesCommaSeparated = (String) workItem.getParameter( "SubTaskStrategies" ); if ( subTaskStrategiesCommaSeparated != null && !subTaskStrategiesCommaSeparated.equals( "" ) ) { String[] subTaskStrategies = subTaskStrategiesCommaSeparated.split( "," ); List<SubTasksStrategy> strategies = new ArrayList<SubTasksStrategy>(); for ( String subTaskStrategyString : subTaskStrategies ) { SubTasksStrategy subTaskStrategy = SubTasksStrategyFactory.newStrategy( subTaskStrategyString ); strategies.add( subTaskStrategy ); } task.setSubTaskStrategies( strategies ); } PeopleAssignments assignments = new PeopleAssignments(); List<OrganizationalEntity> potentialOwners = new ArrayList<OrganizationalEntity>(); String actorId = (String) workItem.getParameter( "ActorId" ); if ( actorId != null ) { String[] actorIds = actorId.split( "," ); for ( String id : actorIds ) { User user = new User(); user.setId( id.trim() ); potentialOwners.add( user ); } //Set the first user as creator ID??? hmmm might be wrong if ( potentialOwners.size() > 0 ) { taskData.setCreatedBy( (User) potentialOwners.get( 0 ) ); } } String groupId = (String) workItem.getParameter( "GroupId" ); if ( groupId != null ) { String[] groupIds = groupId.split( "," ); for ( String id : groupIds ) { potentialOwners.add( new Group( id ) ); } } assignments.setPotentialOwners( potentialOwners ); List<OrganizationalEntity> businessAdministrators = new ArrayList<OrganizationalEntity>(); businessAdministrators.add( new User( "Administrator" ) ); assignments.setBusinessAdministrators( businessAdministrators ); task.setPeopleAssignments( assignments ); task.setTaskData( taskData ); ContentData content = null; Object contentObject = workItem.getParameter( "Content" ); if ( contentObject != null ) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out; try { out = new ObjectOutputStream( bos ); out.writeObject( contentObject ); out.close(); content = new ContentData(); content.setContent( bos.toByteArray() ); content.setAccessType( AccessType.Inline ); } catch ( IOException e ) { e.printStackTrace(); } } TaskWorkItemAddTaskMessageResponseHandler taskResponseHandler = new TaskWorkItemAddTaskMessageResponseHandler( workItem.getId(), this.managers, this.idMapping, manager ); this.client.addTask( task, content, taskResponseHandler ); } public void dispose() throws ConnectorException, RemoteException { if ( this.connector != null ) { this.connector.disconnect(); } } public void abortWorkItem(WorkItem workItem, WorkItemManager manager) { Long taskId = this.idMapping.get( workItem.getId() ); if ( taskId != null ) { synchronized ( this.idMapping ) { this.idMapping.remove( taskId ); } synchronized ( this.managers ) { this.managers.remove( taskId ); } this.client.skip( taskId, "Administrator", null ); } } public class TaskWorkItemAddTaskMessageResponseHandler extends AbstractBaseResponseHandler implements AddTaskMessageResponseHandler { private Map<Long, WorkItemManager> managers; private Map<Long, Long> idMapping; private WorkItemManager manager; private long workItemId; public TaskWorkItemAddTaskMessageResponseHandler(long workItemId, Map<Long, WorkItemManager> managers, Map<Long, Long> idMapping, WorkItemManager manager) { this.workItemId = workItemId; this.managers = managers; this.idMapping = idMapping; this.manager = manager; } public void execute(long taskId) { throw new UnsupportedOperationException( "Not supported yet." ); } public void receive(Message message) { Command command = (Command) message.getPayload(); Long taskId = (Long) command.getArguments().get( 0 ); synchronized ( this.managers ) { this.managers.put( taskId, this.manager ); } synchronized ( this.idMapping ) { this.idMapping.put( this.workItemId, taskId ); } System.out.println( "Created task " + taskId + " for work item " + this.workItemId ); EventKey key = new TaskEventKey( TaskCompletedEvent.class, taskId ); TaskCompletedMessageHandler eventResponseHandler = new TaskCompletedMessageHandler( this.workItemId, taskId, this.managers ); CommandBasedServicesWSHumanTaskHandler.this.client.registerForEvent( key, true, eventResponseHandler ); key = new TaskEventKey( TaskFailedEvent.class, taskId ); CommandBasedServicesWSHumanTaskHandler.this.client.registerForEvent( key, true, eventResponseHandler ); key = new TaskEventKey( TaskSkippedEvent.class, taskId ); CommandBasedServicesWSHumanTaskHandler.this.client.registerForEvent( key, true, eventResponseHandler ); } } private class TaskCompletedMessageHandler extends AbstractBaseResponseHandler implements EventMessageResponseHandler { private long workItemId; private long taskId; private final Map<Long, WorkItemManager> managers; public TaskCompletedMessageHandler(long workItemId, long taskId, Map<Long, WorkItemManager> managers) { this.workItemId = workItemId; this.taskId = taskId; this.managers = managers; } public void receive(Message message) { Command cmd = (Command) message.getPayload(); Payload payload = (Payload) cmd.getArguments().get( 0 ); TaskEvent event = (TaskEvent) payload.get(); if ( event.getTaskId() != this.taskId ) { // defensive check that should never happen, just here for testing setError( new IllegalStateException( "Expected task id and arrived task id do not march" ) ); return; } if ( event instanceof TaskCompletedEvent ) { synchronized ( this.managers ) { WorkItemManager manager = this.managers.get( this.taskId ); if ( manager != null ) { GetCompletedTaskMessageResponseHandler getTaskResponseHandler = new GetCompletedTaskMessageResponseHandler( manager ); CommandBasedServicesWSHumanTaskHandler.this.client.getTask( this.taskId, getTaskResponseHandler ); } } } else { synchronized ( this.managers ) { WorkItemManager manager = this.managers.get( this.taskId ); if ( manager != null ) { manager.abortWorkItem( this.workItemId ); } } } } public void execute(Payload payload) { throw new UnsupportedOperationException( "Not supported yet." ); } } private class GetCompletedTaskMessageResponseHandler extends AbstractBaseResponseHandler implements GetTaskMessageResponseHandler { private WorkItemManager manager; public GetCompletedTaskMessageResponseHandler(WorkItemManager manager) { this.manager = manager; } public void receive(Message message) { Command cmd = (Command) message.getPayload(); Task task = (Task) cmd.getArguments().get( 0 ); long workItemId = task.getTaskData().getWorkItemId(); String userId = task.getTaskData().getActualOwner().getId(); Map<String, Object> results = new HashMap<String, Object>(); results.put( "ActorId", userId ); long contentId = task.getTaskData().getOutputContentId(); if ( contentId != -1 ) { GetResultContentMessageResponseHandler getContentResponseHandler = new GetResultContentMessageResponseHandler( this.manager, task, results ); CommandBasedServicesWSHumanTaskHandler.this.client.getContent( contentId, getContentResponseHandler ); } else { this.manager.completeWorkItem( workItemId, results ); } } public void execute(Task task) { throw new UnsupportedOperationException( "Not supported yet." ); } } private class GetResultContentMessageResponseHandler extends AbstractBaseResponseHandler implements GetContentMessageResponseHandler { private Task task; private final WorkItemManager manager; private Map<String, Object> results; public GetResultContentMessageResponseHandler(WorkItemManager manager, Task task, Map<String, Object> results) { this.manager = manager; this.task = task; this.results = results; } public void receive(Message message) { Command cmd = (Command) message.getPayload(); Content content = (Content) cmd.getArguments().get( 0 ); ByteArrayInputStream bis = new ByteArrayInputStream( content.getContent() ); ObjectInputStream in; try { in = new ObjectInputStream( bis ); Object result = in.readObject(); in.close(); this.results.put( "Result", result ); if ( result instanceof Map ) { Map< ? , ? > map = (Map) result; for ( Map.Entry< ? , ? > entry : map.entrySet() ) { if ( entry.getKey() instanceof String ) { this.results.put( (String) entry.getKey(), entry.getValue() ); } } } this.manager.completeWorkItem( this.task.getTaskData().getWorkItemId(), this.results ); } catch ( IOException e ) { e.printStackTrace(); } catch ( ClassNotFoundException e ) { e.printStackTrace(); } } public void execute(Content content) { throw new UnsupportedOperationException( "Not supported yet." ); } } }