协作工作流应用中的服务集成与事件通知
在协作工作流应用中,任务状态管理、事件通知以及服务集成是非常重要的部分。下面将详细介绍相关的服务和实现机制。
1. 任务状态管理与 StarEntry
在工作流程中,
StarEntry
用于反映任务的当前状态,包含了 STAR 信息。
TaskEntry
则对任务上发生的状态变化进行建模。当调用
write
方法时,如果当前的
TaskEntry
存在,会将其移除,并根据
StarEntry
的状态创建一个新的条目。
StarEntry
的状态实际上就是对创建的
TaskEntry
的状态更改命令。若出现非法的状态更改,会在
TaskEntry
的子类中抛出异常。以下是相关代码示例:
// remove the current StarEntry
StarEntry removalTemplate = new StarEntry();
removalTemplate.location = location;
removalTemplate.taskId = taskId;
takeIfExists(removalTemplate);
// write the new StarEntry
Lease lease = space.write(template, null, Lease.FOREVER);
这些状态对象会触发事件通知给已注册状态更改事件的监听器,可利用此机制通知
EventMailbox
监听器活动状态的变化。
2. 事件邮箱服务(Event Mailbox Service)
事件邮箱服务(Mercury)允许客户端存储事件通知。当一个实体向该服务注册后,服务会收集针对该实体的事件,直到实体发起事件的传递。
2.1 事件邮箱接口(EventMailbox)
事件邮箱服务由
EventMailbox
接口定义:
public interface EventMailbox
{
MailboxRegistration register (long leaseDuration) throws RemoteException;
}
客户端调用
register
方法,会得到一个
MailboxRegistration
对象。
2.2 邮箱注册接口(MailboxRegistration)
MailboxRegistration
接口允许实体管理远程事件传递的时间和位置:
package net.jini.event;
public interface MailboxRegistration
{
Lease getLease();
RemoteEventListener getListener();
void enableDelivery(RemoteEventListener target) throws RemoteException;
void disableDelivery() throws RemoteException;
}
通过该接口,实体可以获取
RemoteEventListener
,并在需要的方法中使用。实体可以断开网络连接而不用担心丢失事件,事件会由邮箱监听器存储。之后,实体可以激活并调用
enableDelivery
方法指定一个
RemoteEventListener
作为保存事件的目标。
2.3 JavaSpace 的 notify 方法
JavaSpace 接口的
notify
方法用于注册对匹配指定模板的未来传入条目的兴趣:
EventRegistration notify(Entry tmpl, Transaction txn,
RemoteEventListener listener, long lease,
MarshalledObject handback)
throws RemoteException, TransactionException;
当匹配的条目被写入时,指定的
RemoteEventListener
会被通知。调用
notify
时,需要提供租赁时间的上限,即希望 JavaSpaces 服务记住该注册的时长。每次调用
notify
会返回一个
net.jini.core.event.EventRegistration
对象。
2.4 事件邮箱服务与 JavaSpaces 的连接
以下代码展示了如何将事件邮箱服务与 JavaSpaces 连接起来:
EventMailbox mailbox;
JavaSpace space;
// register with the EventMailbox Service
MailboxRegistration reg = mailbox.register (Lease.FOREVER);
// get the remote event listener for the registration
RemoteEventListener listener = reg.getListener();
// create a template to match on
SomeEntry template = new SomeEntry();
// create a MarshalledObject to handback
MarshalledObject handback = new MarshalledObject(myData);
// supply the template, listener, and handback to the JavaSpace notify method
EventRegistration eventReg = space.notify(template,
null,
listener,
Lease.FOREVER,
handback)
当匹配模板的条目被写入 JavaSpace 时,监听器(邮箱)会收到一个
RemoteEvent
对象的通知。可以通过
MailboxRegistration
的
enableDelivery
方法控制通知的传递。
3. 邮箱服务(MailboxService)
MailboxService
提供了对事件邮箱注册和事件传递的管理,以及用户邮箱映射功能。
3.1 邮箱管理器接口(MailboxManager)
MailboxManager
接口是
EventMailbox
和
MailboxRegistration
接口的包装器,允许将用户映射到注册信息:
package org.jworkplace.mailbox;
import java.rmi.RemoteException;
import net.jini.core.lease.LeaseDeniedException;
import net.jini.core.lease.UnknownLeaseException;
import net.jini.core.event.RemoteEventListener;
import net.jini.admin.Administrable;
public interface MailboxManager extends Administrable {
public void register(String user, long duration) throws RemoteException,
LeaseDeniedException;
public RemoteEventListener getListener(String user) throws RemoteException;
public void start(String user, RemoteEventListener listener) throws RemoteException;
public void pause(String user) throws RemoteException;
public void stop(String user) throws RemoteException,
UnknownLeaseException;
}
3.2 邮箱服务实现(MailboxService)
MailboxService
实现了
RemoteMailboxManager
接口,以下是其主要代码:
package org.jworkplace.mailbox;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.RemoteObject;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import java.util.Map;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Collection;
import java.util.Collections;
import net.jini.discovery.LookupDiscovery;
import net.jini.discovery.DiscoveryListener;
import net.jini.discovery.DiscoveryEvent;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.entry.Entry;
import net.jini.lookup.entry.Name;
import net.jini.lookup.entry.ServiceInfo;
import net.jini.event.EventMailbox;
import net.jini.event.MailboxRegistration;
import net.jini.lease.LeaseRenewalService;
import net.jini.lease.LeaseRenewalManager;
import net.jini.core.lease.Lease;
import net.jini.core.lease.LeaseDeniedException;
import net.jini.core.lease.UnknownLeaseException;
import net.jini.core.event.RemoteEventListener;
import org.jworkplace.util.ServiceFinder;
import org.jworkplace.service.*;
public class MailboxService extends ServiceImpl implements ServiceAdmin,
RemoteMailboxManager, DiscoveryListener
{
// The interface to the EventMailbox
private EventMailbox mailbox;
// The lease renewal manager to renew the registration leases
// this could also use the LeaseRenewalService
private LeaseRenewalManager leaseRenewalMgr;
// performs Lookup discovery of the EventMailbox service
private LookupDiscovery mgt;
// A mapping of user to registration
private Map userMap;
public static void main(String args[]) throws Exception {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
new MailboxService(args);
} catch(IOException e) {
e.printStackTrace();
System.exit(1);
}
try {
Thread.sleep(Long.MAX_VALUE);
} catch(InterruptedException e) { }
System.exit(0);
}
//
public MailboxService(String[] args) throws IOException {
super(args);
// Enable a thread safe collection
userMap = Collections.synchronizedMap(new HashMap());
// Instantiate the lease renewal manager
leaseRenewalMgr = new LeaseRenewalManager();
// now start finding registrars (lookup services)
mgt = new LookupDiscovery(LookupDiscovery.NO_GROUPS);
mgt.addDiscoveryListener(this);
((LookupDiscovery)mgt).setGroups(LookupDiscovery.ALL_GROUPS);
}
// register the supplied user with the EventMailbox service
// and store the mapping
public void register(String user, long duration) throws RemoteException, LeaseDeniedException
{
MailboxRegistration reg = mailbox.register(duration);
leaseRenewalMgr.renewFor(reg.getLease(), duration, null);
userMap.put(user, reg);
}
// get the listener for this user
public RemoteEventListener getListener(String user) throws RemoteException {
MailboxRegistration reg = (MailboxRegistration)userMap.get(user);
if(reg != null) {
return reg.getListener();
}
return null;
}
// enable delivery to the listener specified
public void start(String user, RemoteEventListener listener) throws RemoteException {
MailboxRegistration reg = (MailboxRegistration)userMap.get(user);
if(reg != null)
reg.enableDelivery(listener);
}
// disable delivery and queue notifications
public void pause(String user) throws RemoteException {
MailboxRegistration reg = (MailboxRegistration)userMap.get(user);
if(reg != null)
reg.disableDelivery();
}
// disable and stop notification
public void stop(String user) throws RemoteException, UnknownLeaseException {
// cancel lease
MailboxRegistration reg = (MailboxRegistration)userMap.get(user);
if(reg != null) {
Lease lease = reg.getLease();
lease.cancel();
}
}
/*
** DiscoveryListener Interface
*/
public synchronized void discarded(DiscoveryEvent e) { }
// Find the EventMailbox Service
public synchronized void discovered(DiscoveryEvent de) {
// get the array of lookup services discovered
ServiceRegistrar[] registrars = de.getRegistrars();
// If we already have found the EventMailbox return
if(mailbox == null) {
try {
// loop through the LUS's to find the EventMailbox
for(int i=0; i < registrars.length; i++) {
// Call the ServiceFinder utility
mailbox = (EventMailbox)ServiceFinder.findEMS(registrars[i]);
if(mailbox != null) {
// Terminate the discovery threads
mgt.terminate();
break;
}
}
} catch (Exception e) { e.printStackTrace(); }
}
}
}
当用户成为工人(例如被分配到任务)时,
WorkflowService
会将用户注册到事件邮箱服务,并创建
StarEntry
模板,注册匹配条目空间通知。当分配给工人的任何
StarEntry
被写入空间时,工人会收到通知。
4. 工作流服务(Workflow Service)
工作流服务在协作工作流应用中起着核心作用,负责管理流程定义和激活流程实例。
4.1 工作流管理器接口(WorkflowManager)
WorkflowManager
接口提供了管理工作流流程定义的方法:
package org.jworkplace.workflow;
import java.rmi.RemoteException;
import net.jini.admin.Administrable;
import com.sun.jini.proxy.UUID;
import org.jworkplace.mailbox.MailboxManager;
/*
** This interface defines the methods required to manage
** workflow process definitions
*/
public interface WorkflowManager extends Administrable {
// create a workflow process, the UUID is a universal unique
// identifier generated by the workflow system
public UUID create(ProcessDef processDef) throws RemoteException;
// retrieve a process definition
public ProcessDef getProcessDef(String owner, String processName) throws RemoteException;
// get all process names
public String[] getProcessNames(String owner) throws RemoteException;
// update an existing process
public void updateProcess(UUID processId, ProcessDef processDef) throws RemoteException;
// remove an existing process definition
public void removeProcess(UUID processId) throws RemoteException;
// get the mailbox manager proxy interface
public MailboxManager getMailboxManager() throws RemoteException;
// create a process listener for a type of task
public void createProcessListener(UUID processId, TaskEntry taskEntry) throws RemoteException;
}
该接口定义了创建、检索、更新和删除流程定义的方法,还可以获取邮箱管理器代理接口,并为特定类型的任务创建流程监听器。
4.2 工作流流程定义(Workflow Process Definition)
工作流流程定义由
ProcessDef
类表示,包含一个唯一的 ID 和一个按时间排序的工作项列表:
public class ProcessDef extends AbstractEntry
{
// unique id assigned by Workflow service
private UUID id;
// The human readable name of the process template
private String processName;
// The owner of the process definition
private String processOwner;
// A time sorted work activity list
private Map workItemList;
public ProcessDef() {
this(null, null);
}
public ProcessDef(String processName, String processOwner) {
this.processName = processName;
this.processOwner = processOwner;
workItemList = Collections.synchronizedSortedMap(new TreeMap());
}
public void setId(UUID id) { this.id = id; }
public UUID getId() { return id; }
public String getProcessName() { return processName; }
public String getProcessOwner() { return processOwner; }
public void setProcessOwner(String owner) { this.processOwner = owner; }
public void addWorkItem(WorkItem item) throws RemoteException
{
workItemList.put(item, item);
}
public void updateWorkItem(WorkItem item) throws RemoteException
{
removeWorkItem(item);
addWorkItem(item);
}
public WorkItem getWorkItem(String id) throws RemoteException {
System.out.println("getWorkItem: " + id);
Iterator itr = (workItemList.values()).iterator();
while(itr.hasNext()) {
WorkItem item = (WorkItem)itr.next();
if( item.getId().equals(id)) {
return item;
}
}
return null;
}
public WorkItem getWorkItem(WorkItem template) throws RemoteException
{
return getWorkItem(template.getId());
}
public WorkItem getFirstItem() throws RemoteException {
WorkItem[] items = getWorkItems();
return items[0];
}
public WorkItem getNextItem(String id) throws RemoteException
{
WorkItem successor = null;
WorkItem item = getWorkItem(id);
if(item != null) {
SortedMap tailView = ((SortedMap)workItemList).tailMap(item);
Object[] array = (tailView.keySet()).toArray();
if(array.length > 1) {
successor = (WorkItem)array[1];
}
}
return successor;
}
public void removeWorkItem(WorkItem template) throws RemoteException
{
Iterator itr = (workItemList.values()).iterator();
while(itr.hasNext()) {
WorkItem item = (WorkItem)itr.next();
if( item.getId().equals(template.getId())) {
workItemList.remove(item);
break;
}
}
}
public WorkItem[] getWorkItems() throws RemoteException
{
Collection collection = workItemList.values();
return (WorkItem[])collection.toArray(new WorkItem[0]);
}
}
工作项(
WorkItem
)由管理员定义并分配给特定的工人。在更复杂的应用中,分配可以先到特定角色,再到特定个人,这样可以将流程定义与流程执行分离。
4.3 工作流服务实现(WorkflowService)
WorkflowService
实现了
WorkflowManager
和
WorkProcess
接口,负责管理流程定义和激活流程实例:
package org.jworkplace.workflow;
import org.jworkplace.workplace.WorkPlaceFactory;
import org.jworkplace.login.LoginHandler;
import org.jworkplace.mailbox.MailboxManager;
import org.jworkplace.account.Session;
import org.jworkplace.util.ServiceFinder;
import org.jworkplace.service.*;
public class WorkflowService extends ServiceImpl implements ServiceAdmin,
WorkflowBackend, DiscoveryListener
{
/** UUID generator */
private UUIDFactory uuidFactory = new UUIDFactory();
// processId to processDef
private Map processMap;
// worker to processId
private Map userMap;
// owner to list of owned processDefs
private Map ownerMap;
// thread to invoke process instance
private WorkflowEngine engine;
// JavaSpace proxy interface
private StarInterface space;
private static String starInterfaceClass = StarInterface.class.getName();
// Event Mailbox proxy interface
private MailboxManager mailbox;
private static String mailboxManagerClass = MailboxManager.class.getName();
// process definition queue
private UUID processToActivate;
private boolean ready = false;
// Lookup discovery manager
private LookupDiscovery mgt;
public static void main(String args[]) throws Exception {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
new WorkflowService(args);
} catch(IOException e) {
e.printStackTrace();
System.exit(1);
}
try {
Thread.sleep(Long.MAX_VALUE);
} catch(InterruptedException e) { }
System.exit(0);
}
public WorkflowService(String[] args) throws IOException {
super(args);
// processId to processDef
processMap = Collections.synchronizedMap(new HashMap());
// worker to processId
userMap = Collections.synchronizedMap(new HashMap());
// owner to list of owned processDefs
ownerMap = Collections.synchronizedMap(new HashMap());
// initialize factory
UUID uuid = uuidFactory.newUUID();
// now start finding registrars (lookup services)
mgt = new LookupDiscovery(LookupDiscovery.NO_GROUPS);
mgt.addDiscoveryListener(this);
((LookupDiscovery)mgt).setGroups(LookupDiscovery.ALL_GROUPS);
// start threads
engine = new WorkflowEngine();
}
//
// Workflow Manager Interface
//
// create the process definition and queue the process for the engine thread
public UUID create(ProcessDef processDef)throws RemoteException
{
// generate a unique id for this process
UUID uuid = uuidFactory.newUUID();
processDef.setId(uuid);
processMap.put(uuid, processDef);
// get the owner and determine if other processes
// belonging to this owner are already defined
String owner = processDef.getProcessOwner();
if(!ownerMap.containsKey(owner)) {
List processList = new ArrayList();
ownerMap.put(owner, processList);
}
// add this process definition to the owners list
List processList = (List)ownerMap.get(owner);
int index = -1;
index = ( (processList.lastIndexOf(owner) == -1 )
? processList.size() : index+1);
processList.add(index, processDef);
// notify the engine a process instance should be created
queueProcess(uuid);
// return the unique reference
return uuid;
}
// returns a Process Defintion given a owner and process name
public ProcessDef getProcessDef(String owner, String processName) throws RemoteException
{
List processList = (List)ownerMap.get(owner);
if(processList == null)
throw new RemoteException();
ProcessDef item = null;
Iterator itr = processList.iterator();
while(itr.hasNext()) {
item = (ProcessDef)itr.next();
if(processName.equals( item.getProcessName()))
break;
}
return item;
}
// returns the list of processes defined by a given owner
public String[] getProcessNames(String owner) throws RemoteException
{
List processList = (List)ownerMap.get(owner);
if(processList == null)
throw new RemoteException();
Iterator itr = processList.iterator();
ArrayList nameList = new ArrayList();
while(itr.hasNext()) {
ProcessDef item = (ProcessDef)itr.next();
nameList.add(item.getProcessName());
}
return (String[])nameList.toArray(new String[0]);
}
// updates a process defintion
public void updateProcess(UUID processId, ProcessDef processDef) throws RemoteException {
processMap.put(processId, processDef);
}
// removes a process definition
public void removeProcess(UUID processId) throws RemoteException
{
processMap.remove(processId);
}
// return the MailboxManager used by this workflow service
public MailboxManager getMailboxManager() throws RemoteException
{
return mailbox;
}
// Called by the engine thread with a CompleteTask object
// during process instantiation
public void createProcessListener(UUID processId, TaskEntry taskEntry) throws RemoteException
{
// get the process definition associated with this id
ProcessDef processDef = (ProcessDef)processMap.get(processId);
try {
// create a TaskListener
TaskListener listener = new TaskListener(
(WorkflowBackend)WorkflowService.this, space);
// pass the TaskListener the Process Definition
MarshalledObject handback = new MarshalledObject(processDef);
// register for notification of state objects
space.setRemoteEventListener(taskEntry, handback, listener);
} catch(Exception e) { e.printStackTrace(); }
}
// waits for next process definition
public synchronized UUID getProcessId()
{
while (ready == false) {
try {
wait();
} catch (InterruptedException e) { }
}
ready = false;
notifyAll();
return processToActivate;
}
// queues a process to activate the process engine
public synchronized void queueProcess(UUID value)
{
while (ready == true) {
try {
wait();
} catch (InterruptedException e) { }
}
processToActivate = value;
ready = true;
notifyAll();
}
}
WorkflowService
主要完成以下三个映射:
-
processMap
:提供流程 ID 到流程定义的映射。
-
userMap
:提供工人到流程的映射。
-
ownerMap
:提供流程管理员到流程的映射。
4.4 工作流程接口(WorkProcess)
WorkProcess
接口为客户端应用提供了与
WorkflowService
交互的 API:
package org.jworkplace.workflow;
import java.rmi.RemoteException;
import java.io.IOException;
import net.jini.admin.Administrable;
import org.jworkplace.account.Session;
public interface WorkProcess
{
public Session connect() throws RemoteException, IOException;
public void disconnect() throws RemoteException, IOException;
public void updateTask(Task item) throws RemoteException, IOException;
public Task[] getTasksAssigned(Resource resource) throws RemoteException;
}
客户端可以通过该接口连接和断开与工作流引擎的连接,接收任务分配并更新已分配的任务。
4.5 工作流程实现
WorkflowService
也实现了
RemoteWorkProcess
接口:
// connect to the workflow engine
public Session connect(UUID processId) throws RemoteException
{
return new Session();
}
// disconnect from the workflow engine
public void disconnect(Session session) throws RemoteException
{
session.isActive(false);
}
// Determine if the task is still valid
public void updateTask(Task task) throws RemoteException
{
ProcessDef processDef = null;
// Determine if the task is still valid
if(!processMap.containsKey(task.processId)) {
return;
}
// update the task list for the worker
updateTaskList(task);
// get the associated work item
processDef = (ProcessDef)processMap.get(task.processId);
WorkItem item = processDef.getWorkItem(task.taskId);
// update the StarEntry
write(item, task);
}
private void updateTaskList(Task task) {
List taskList = null;
Task item = null;
try {
// find the task in the task list
if(userMap.containsKey(task.user)) {
taskList = (List)userMap.get(task.user);
Iterator itr = taskList.iterator();
while(itr.hasNext()) {
item = (Task)itr.next();
if(item.taskId.equals( task.taskId)) {
int pos = taskList.indexOf(item);
// update the task to reflect any changes
taskList.set(pos,task);
}
}
}
} catch(Exception e) { e.printStackTrace(); }
}
// called by clients to get task assingments
public Task[] getTasksAssigned(Resource resource) throws RemoteException {
List taskList = null;
try {
// assume resource contains worker
String worker = resource.getResource();
if(!userMap.containsKey(worker)) return null;
// get the tasklist associated with this worker
taskList = (List)userMap.get(worker);
} catch(Exception e) { e.printStackTrace();
return null; }
return (Task[])taskList.toArray(new Task[0]);
}
//
// Use the StarInterface proxy to interface with JavaSpaces
//
private synchronized void write(WorkItem item, Task task) {
try {
if(space == null) {
System.out.println("WorkflowService::write Lost in space...unable to continue");
shutdown();
}
// Use the item and task information
// to create a StarEntry description
Time time = item.activityTime();
String resource = item.getAssignedTo();
StarEntry entry = new StarEntry(task.processId,
task.taskId,
time.getStartTime(),
time.getStopTime(),
item.description,
task.status,
resource);
// Write the StarEntry to JavaSpaces
space.write(entry);
} catch (Exception e) { e.printStackTrace(); }
}
5. 依赖服务的发现
WorkflowService
需要发现
StarService
和
MailboxManager
服务。通过实现
DiscoveryListener
接口来完成服务发现:
//
// DiscoveryListener Interface
//
public synchronized void discarded(DiscoveryEvent e) { }
public synchronized void discovered(DiscoveryEvent de) {
// get the array of lookup services discovered
ServiceRegistrar[] registrars = de.getRegistrars();
// find JavaSpace proxy
findStarInterface(registrars);
// find our mailbox manager
findMailboxManager(registrars);
// found everything we need terminate discovery
if(space != null && mailbox != null)
mgt.terminate();
}
// loop through discovered service registrars
private void findStarInterface(ServiceRegistrar[] registrars) {
if(space == null) {
try {
Class[] cls = new Class[] { Class.forName(starInterfaceClass) } ;
ServiceTemplate template = new ServiceTemplate(null, cls, null);
for(int i=0; i < registrars.length; i++) {
space = (StarInterface)findService(registrars[i], template);
if(space != null) {
break;
}
}
} catch (Exception e) { e.printStackTrace(); }
}
}
// loop through discovered service registrars
private void findMailboxManager(ServiceRegistrar[] registrars) {
if(mailbox == null) {
try {
Class[] cls = new Class[] { Class.forName(mailboxManagerClass) } ;
ServiceTemplate template = new ServiceTemplate(null, cls, null);
for(int i=0; i < registrars.length; i++) {
mailbox = (MailboxManager)findService(registrars[i], template);
if(mailbox != null) {
break;
}
}
} catch (Exception e) { e.printStackTrace(); }
}
}
// if unable to find service register for notification
private synchronized Object findService(ServiceRegistrar registrar,
ServiceTemplate template) throws RemoteException {
Object service = null;
try {
service = registrar.lookup( template );
} catch ( RemoteException ex ) {
ex.printStackTrace();
}
// TRANSITION_NOMATCH_MATCH to indicate when template match occurs
// generate remote event
if ( service == null ) {
registrar.notify(template, ServiceRegistrar.TRANSITION_NOMATCH_MATCH,
(WorkflowBackend)this, null, Long.MAX_VALUE);
}
return service;
}
//
// ServiceEvent Listener
//
public synchronized void notify(RemoteEvent event) throws UnknownEventException, RemoteException
{
// If service event received determine which service
// has joined the community
if(event instanceof ServiceEvent) {
ServiceEvent serviceEvent = (ServiceEvent)event;
ServiceItem item = serviceEvent.getServiceItem();
if(item.service instanceof StarInterface) {
space = (StarInterface)item.service;
} else if(item.service instanceof MailboxManager) {
mailbox = (MailboxManager)item.service;
}
}
}
当发现服务时,会调用相应的方法进行处理。如果未能找到服务,会使用
ServiceRegistrar
的
notify
方法注册通知,当服务加入社区时会收到通知。
6. 工作流引擎实现(WorkflowEngine)
WorkflowEngine
负责创建
CompleteTask
状态对象的空间监听器,为流程定义中的每个工作项创建任务并更新每个工人的任务列表,以及在工人未注册时将其注册到
MailboxManager
:
// Internal class of WorkflowService
private class WorkflowEngine extends Thread {
public WorkflowEngine() {
super();
start();
}
public void run() {
try {
while (!isInterrupted()) {
// wait for process to be started
UUID uuid = getProcessId();
// create a task completion listener for this process
createProcessListener(uuid, new CompleteTask(uuid));
// create all tasks to activate
activateProcess(uuid);
}
} catch (Exception e) { e.printStackTrace();
} finally { }
}
private void activateProcess(UUID processId) {
ProcessDef processDef = (ProcessDef)processMap.get(processId);
try {
WorkItem[] items = processDef.getWorkItems();
for(int i=0; i<items.length; i++) {
System.out.println("Engine activateProcess: " + items[i].getId());
// create a Task for each WorkItem
WorkItem item = (WorkItem)items[i];
String processName = processDef.getProcessName();
Task task = createTask(processId, processName, item);
// update the task list for the worker
if(task != null)
updateTaskList(task);
// write a StarEntry for each activity
write(items[i], task);
}
} catch (Exception e) { e.printStackTrace(); }
}
private Task createTask(UUID processId, String processName, WorkItem item) {
Task task = null;
try {
String taskId = item.getId();
String worker = item.getAssignedTo();
task = new Task(processId, processName, taskId, worker, ActivityState.TASK_INIT);
// does the worker already have a mailbox
RemoteEventListener listener = mailbox.getListener(worker);
if(listener == null) {
// register the worker
mailbox.register(worker, Long.MAX_VALUE);
// create the registration template for the worker
StarEntry entry = new StarEntry();
entry.resource = item.getAssignedTo();
// get the mailbox for worker
listener = mailbox.getListener(worker);
MarshalledObject handback = new MarshalledObject(worker);
// set the worker mailbox to get space notifications
space.setRemoteEventListener(entry, handback, listener);
}
} catch (Exception e) { e.printStackTrace(); }
return task;
}
private synchronized void updateTaskList(Task task) {
try {
String worker = task.user;
if(!userMap.containsKey(worker)) {
List taskList = new ArrayList();
userMap.put(worker, taskList);
}
List taskList = (List)userMap.get(worker);
taskList.add(task);
} catch (Exception e) { e.printStackTrace(); }
}
}
7. 任务监听器(TaskListener)
TaskListener
是服务端监听器,为工作流系统中定义的每个流程注册。当
CompleteTask
对象被写入空间时,会收到通知:
package org.jworkplace.workflow;
import java.rmi.RemoteException;
import java.rmi.MarshalledObject;
import java.rmi.server.UnicastRemoteObject;
import java.io.IOException;
import net.jini.core.event.RemoteEventListener;
import net.jini.core.event.RemoteEvent;
public class TaskListener implements RemoteEventListener {
private RemoteWorkProcess engine;
private StarInterface space;
public TaskListener(RemoteWorkProcess workProcess, StarInterface starInterface) throws RemoteException {
this.engine = workProcess;
this.space = starInterface;
UnicastRemoteObject.exportObject(this);
}
// this should create a new thread
public void notify(RemoteEvent event) {
try {
CompleteTask template = new CompleteTask();
while(template != null) {
// for each complete task take from space
template = (CompleteTask)space.takeStarIfExists(template);
if(template != null) {
// the handback will contain the Process Definition
MarshalledObject handback = event.getRegistrationObject();
if(handback != null) {
ProcessDef processDef = (ProcessDef)handback.get();
// Get the successor task
WorkItem item = processDef.getNextItem(template.taskId);
if (item != null) {
// Create a task template
String processName = processDef.getProcessName();
String taskId = item.getId();
String worker = item.getAssignedTo();
Task task = new Task(template.processId,
processName,
taskId,
worker,
ActivityState.TASK_READY);
// Put the next task in a ready state
engine.updateTask(task);
}
}
}
}
} catch (Exception e) { e.printStackTrace(); }
}
}
通过以上的服务和机制,可以实现一个完整的协作工作流应用,包括任务状态管理、事件通知和服务集成。这些功能的组合使得工作流系统更加高效和灵活,能够满足不同场景下的协作需求。
协作工作流应用中的服务集成与事件通知(续)
8. 邮件事件处理器(MailEventHandler)
邮件事件处理器在整个协作工作流系统中扮演着重要的角色,它负责处理与邮件相关的事件。虽然文档中没有给出
MailEventHandler
的具体代码实现,但我们可以推测它会与之前提到的
EventMailbox
、
MailboxManager
等服务进行交互,以实现事件的接收、处理和通知等功能。
例如,
MailEventHandler
可能会监听
EventMailbox
中的事件,当有新的事件到来时,根据事件的类型和内容进行相应的处理。可能的处理方式包括向用户发送邮件通知、更新任务状态等。
9. 工作流系统的整体流程与交互
为了更好地理解整个工作流系统的运作,下面通过一个流程图来展示各个组件之间的交互过程:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef data fill:#FFEBEB,stroke:#E68994,stroke-width:2px;
A(客户端):::process -->|连接与操作| B(WorkflowService):::process
B -->|创建流程| C(ProcessDef):::data
B -->|映射管理| D(processMap):::data
B -->|映射管理| E(userMap):::data
B -->|映射管理| F(ownerMap):::data
B -->|发现服务| G(StarService):::process
B -->|发现服务| H(MailboxManager):::process
C -->|工作项分配| I(WorkItem):::data
I -->|创建任务| J(Task):::data
J -->|更新任务列表| E
B -->|注册通知| K(EventMailbox):::process
K -->|事件存储| L(事件队列):::data
M(CompleteTask对象写入):::data -->|触发通知| N(TaskListener):::process
N -->|处理任务| B
B -->|更新任务状态| J
B -->|写入JavaSpace| G
G -->|通知匹配| K
K -->|激活通知| A
从这个流程图中可以看出,客户端与
WorkflowService
进行交互,
WorkflowService
负责管理流程定义、映射关系以及发现依赖服务。工作项被分配后创建任务,任务状态的更新会影响任务列表。
CompleteTask
对象的写入会触发
TaskListener
的处理,进而更新任务状态并通知客户端。
10. 关键技术点总结
以下是对整个协作工作流系统中关键技术点的总结:
| 技术点 | 描述 |
|---|---|
StarEntry
和
TaskEntry
|
用于管理任务的状态和状态变化,通过
write
方法实现状态的更新和创建。
|
EventMailbox
服务
|
允许客户端存储事件通知,通过
MailboxRegistration
接口管理事件的传递。
|
JavaSpace
的
notify
方法
| 用于注册对未来传入条目的兴趣,实现事件的通知机制。 |
MailboxService
| 提供用户邮箱映射功能,管理事件邮箱注册和事件传递。 |
WorkflowService
| 核心服务,负责管理流程定义、激活流程实例,完成流程 ID、工人和流程管理员到流程的映射。 |
WorkflowEngine
|
负责创建空间监听器、创建任务和更新任务列表,以及注册工人到
MailboxManager
。
|
TaskListener
|
服务端监听器,当
CompleteTask
对象被写入空间时,触发后续任务的处理。
|
11. 实际应用与拓展
在实际应用中,这个协作工作流系统可以应用于各种场景,如项目管理、任务分配、审批流程等。通过对系统的进一步拓展,可以实现更多的功能:
- 权限管理 :增加权限管理模块,对不同用户或角色的操作进行限制,确保系统的安全性和数据的保密性。
- 任务调度优化 :结合更复杂的算法和策略,对任务的调度进行优化,提高工作效率。
- 可视化界面 :开发可视化界面,让用户可以更直观地查看和管理工作流,提高用户体验。
12. 总结
通过对协作工作流系统中各个组件和服务的介绍,我们了解了任务状态管理、事件通知和服务集成的实现方式。各个组件之间相互协作,形成了一个完整的工作流系统。通过合理的设计和实现,可以提高工作流系统的效率和灵活性,满足不同场景下的协作需求。
在实际开发中,需要根据具体的业务需求对系统进行定制和优化,同时要注意服务的发现和管理,确保系统的稳定性和可靠性。希望本文对理解和实现协作工作流系统有所帮助。
超级会员免费看

被折叠的 条评论
为什么被折叠?



