package jadex.bpmn.runtime.handler;
import jadex.bpmn.model.MActivity;
import jadex.bpmn.runtime.BpmnInterpreter;
import jadex.bpmn.runtime.ProcessThread;
import jadex.bridge.IComponentManagementService;
import jadex.bridge.IMessageAdapter;
import jadex.bridge.IMessageService;
import jadex.bridge.MessageType;
import jadex.commons.IFilter;
import jadex.commons.SReflect;
import jadex.commons.SUtil;
import jadex.commons.concurrent.DefaultResultListener;
import jadex.commons.concurrent.IResultListener;
import jadex.commons.service.SServiceProvider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Handler for message events.
*/
public class EventIntermediateMessageActivityHandler extends DefaultActivityHandler
{
//-------- constants --------
/** The isThrowing property name (distinguishes send/receive events). */
public static final String PROPERTY_THROWING = "isThrowing";
/** The type property message type identifies the meta type (e.g. fipa). */
public static final String PROPERTY_MESSAGETYPE = "messagetype";
/** The filter property describes the filter for receiving a message. */
public static final String PROPERTY_FILTER = "filter";
/** The property message is the message to be sent. */
public static final String PROPERTY_MESSAGE = "message";
//-------- methods --------
/**
* Execute an activity.
* @param activity The activity to execute.
* @param instance The process instance.
* @param thread The process thread.
*/
public void execute(final MActivity activity, final BpmnInterpreter instance, final ProcessThread thread)
{
boolean send = thread.hasPropertyValue(PROPERTY_THROWING)? ((Boolean)thread.getPropertyValue(PROPERTY_THROWING)).booleanValue() : false;
if(send)
{
sendMessage(activity, instance, thread);
}
else
{
receiveMessage(activity, instance, thread);
}
}
/**
* Send a message.
* @param activity The activity to execute.
* @param instance The process instance.
* @param thread The process thread.
*/
protected void sendMessage(final MActivity activity, final BpmnInterpreter instance, final ProcessThread thread)
{
SServiceProvider.getService(instance.getServiceProvider(), IMessageService.class)
.addResultListener(instance.createResultListener(new DefaultResultListener()
{
public void resultAvailable(Object source, Object result)
{
final IMessageService ms = (IMessageService)result;
SServiceProvider.getService(instance.getServiceProvider(), IComponentManagementService.class)
.addResultListener(instance.createResultListener(new DefaultResultListener()
{
public void resultAvailable(Object source, Object result)
{
IComponentManagementService cms = (IComponentManagementService)result;
String mtname = (String)thread.getPropertyValue(PROPERTY_MESSAGETYPE, activity);
MessageType mt = mtname!=null? ms.getMessageType(mtname): ms.getMessageType("fipa");
Map msg;
if(thread.hasPropertyValue(PROPERTY_MESSAGE))
{
msg = (Map)thread.getPropertyValue(PROPERTY_MESSAGE);
}
else
{
msg = new HashMap();
}
// Convenience conversion of strings to component identifiers for receivers.
String ri = mt.getReceiverIdentifier();
if(thread.hasPropertyValue(ri))
{
Object recs = thread.getPropertyValue(ri);
List newrecs = new ArrayList();
if(SReflect.isIterable(recs))
{
for(Iterator it=SReflect.getIterator(recs); it.hasNext(); )
{
Object rec = it.next();
if(rec instanceof String)
{
newrecs.add(cms.createComponentIdentifier((String)rec, true, null));
}
else
{
newrecs.add(rec);
}
}
}
else
{
if(recs instanceof String)
{
newrecs.add(cms.createComponentIdentifier((String)recs, true, null));
}
else
{
newrecs.add(recs);
}
}
msg.put(ri, newrecs);
}
String[] params = mt.getParameterNames();
for(int i=0; params!=null && i<params.length; i++)
{
if(thread.hasPropertyValue(params[i]) && !params[i].equals(ri))
{
msg.put(params[i], thread.getPropertyValue(params[i]));
}
}
String[] paramsets = mt.getParameterSetNames();
for(int i=0; paramsets!=null && i<paramsets.length; i++)
{
if(thread.hasPropertyValue(paramsets[i]) && !paramsets[i].equals(ri))
{
msg.put(paramsets[i], thread.getPropertyValue(paramsets[i]));
}
}
thread.setWaiting(true);
ms.sendMessage(msg, mt, instance.getComponentAdapter().getComponentIdentifier(), instance.getClassLoader())
.addResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
instance.notify(activity, thread, null);
}
public void exceptionOccurred(Object source, Exception exception)
{
thread.setException(exception);
instance.notify(activity, thread, null);
}
});
}
}));
}
}));
}
/**
* Receive a message.
* @param activity The activity to execute.
* @param instance The process instance.
* @param thread The process thread.
*/
protected void receiveMessage(final MActivity activity, final BpmnInterpreter instance, final ProcessThread thread)
{
thread.setWaiting(true);
// thread.setWaitInfo(type);
IFilter filter = (IFilter)thread.getPropertyValue(PROPERTY_FILTER, activity);
if(filter==null)
{
filter = new IFilter()
{
public boolean filter(Object obj)
{
boolean ret = obj instanceof IMessageAdapter;
if(ret)
{
try
{
IMessageAdapter msg = (IMessageAdapter)obj;
String[] params = activity.getPropertyNames();
for(int i=0; ret && params!=null && i<params.length; i++)
{
// Todo: distinguish message activity properties and message parameters
if(!params[i].equals("isThrowing"))
{
// Fetch property from message event activity, because current activity might be multiple event.
ret = SUtil.equals(thread.getPropertyValue(params[i], activity), msg.getValue(params[i]));
}
}
}
catch(RuntimeException e)
{
instance.getLogger().warning("Error during message matching: "+instance+", "+thread+", "+obj+", "+e);
ret = false;
}
}
return ret;
}
};
}
thread.setWaitFilter(filter);
// System.out.println("Waiting for message: "+filter);
}
}