package org.jbpm.pvm.internal.wire.operation; import java.util.HashSet; import java.util.List; import java.util.Set; import org.jbpm.internal.log.Log; import org.jbpm.pvm.internal.env.Context; import org.jbpm.pvm.internal.env.EnvironmentImpl; import org.jbpm.pvm.internal.util.FilterListener; import org.jbpm.pvm.internal.util.Listener; import org.jbpm.pvm.internal.util.Observable; import org.jbpm.pvm.internal.wire.Descriptor; import org.jbpm.pvm.internal.wire.WireContext; import org.jbpm.pvm.internal.wire.WireDefinition; import org.jbpm.pvm.internal.wire.WireException; import org.jbpm.pvm.internal.wire.descriptor.ArgDescriptor; /** * subscribes to an {@link Observable observable}. * *

The target object can be a {@link Listener} * or a specific method to call can be specified (by {@link #setMethodName(String)})

* *

The event can be filtered by specifying a {@link Context} (with {@link #setContextName(String)}), * objects to observe (with {@link #setObjectNames(List)}) and events to observe * (with {@link #setEventNames(List)}). If the objects or events are not specified, * then all objects and events are observed.

* *

The {@link #setWireEvents(boolean)} specifies if the object or the {@link Descriptor} events * should be observed.

* * @author Tom Baeyens * @author Guillaume Porcher (documentation) * */ public class SubscribeOperation implements Operation { private static final long serialVersionUID = 1L; private static Log log = Log.getLog(SubscribeOperation.class.getName()); String contextName = null; List eventNames = null; boolean wireEvents = false; List objectNames = null; String methodName = null; List argDescriptors = null; public void apply(Object target, WireContext targetWireContext) { Listener listener = null; // if a method has to be invoked, rather then using the observable interface if (methodName!=null) { listener = new MethodInvokerListener( methodName, argDescriptors, targetWireContext, target ); } else { try { listener = (Listener) target; } catch (ClassCastException e) { throw new WireException("couldn't subscribe object "+target+ " because it is not a Listener"); } } // if there is a filter specified on the event names if ( (eventNames!=null) && (! eventNames.isEmpty()) ) { listener = new FilterListener(listener, eventNames); } // identify the wireContext WireContext wireContext = null; if (contextName!=null) { EnvironmentImpl environment = EnvironmentImpl.getCurrent(); if (environment!=null) { try { wireContext = (WireContext) environment.getContext(contextName); if (wireContext==null) { throw new WireException("couldn't subscribe because context "+contextName+" doesn't exist"); } } catch (ClassCastException e) { throw new WireException("couldn't subscribe because context "+contextName+" is not a WireContext", e); } } else { throw new WireException("couldn't get context "+contextName+" for subscribe because no environment available in context "+targetWireContext); } } else { wireContext = targetWireContext; } if (wireEvents) { WireDefinition wireDefinition = wireContext.getWireDefinition(); // if there are objectNames specified if (objectNames!=null) { // subscribe to the descriptors for the all objectNames for (String objectName: objectNames) { Descriptor descriptor = wireDefinition.getDescriptor(objectName); subscribe(listener, descriptor); } // if no objectNames are specified, subscribe to all the descriptors } else { Set descriptors = new HashSet(wireDefinition.getDescriptors().values()); for(Descriptor descriptor: descriptors) { subscribe(listener, descriptor); } } } else if ( (objectNames!=null) && (!objectNames.isEmpty()) ) { // for every objectName for (String objectName: objectNames) { // subscribe to the objects themselves Object object = wireContext.get(objectName); if (object==null) { throw new WireException("couldn't subscribe to object in context "+wireContext.getName()+": object "+objectName+" unavailable"); } if (! (object instanceof Observable)) { throw new WireException("couldn't subscribe to object in context "+wireContext.getName()+": object "+objectName+" ("+object.getClass().getName()+") isn't "+Observable.class.getName()); } subscribe(listener, (Observable)object); } } else { // subscribe to the context subscribe(listener, wireContext); } } void subscribe(Listener listener, Observable observable) { log.trace("adding "+listener+" as listener to "+observable); observable.addListener(listener); } /** * Gets the list of argDescriptor used to create the arguments given to the method (only if a specific method has to be called). */ public List getArgDescriptors() { return argDescriptors; } /** * Sets the list of argDescriptor used to create the arguments given to the method. */ public void setArgDescriptors(List argDescriptors) { this.argDescriptors = argDescriptors; } /** * Gets the list of events to listen to. */ public List getEventNames() { return eventNames; } /** * Sets the list of events to listen to. */ public void setEventNames(List eventNames) { this.eventNames = eventNames; } /** * Gets the name of the method to invoke when an event is received. */ public String getMethodName() { return methodName; } /** * Sets the name of the method to invoke when an event is received. */ public void setMethodName(String methodName) { this.methodName = methodName; } /** * Gets the name of the WireContext where the Observable should be found. */ public String getContextName() { return contextName; } /** * Sets the name of the WireContext where the Observable should be found. */ public void setContextName(String contextName) { this.contextName = contextName; } /** * Gets the list of name of the Observable objects to observe. */ public List getObjectNames() { return objectNames; } /** * Sets the list of name of the Observable objects to observe. */ public void setObjectNames(List objectNames) { this.objectNames = objectNames; } /** *

true if the target object will listen to Descriptor related events.

*

false if the target object will listen to the object instance events.

*/ public boolean isWireEvents() { return wireEvents; } /** * Sets if the object should listen to descriptor events or to events fired by the named object. *

true if the target object will listen to Descriptor related events.

*

false if the target object will listen to the object instance events.

*/ public void setWireEvents(boolean wireEvents) { this.wireEvents = wireEvents; } }