| LowRA API Documentation | Annexes | All Packages | All Classes | Index | Frames |
|
| IoC Plugins communication | ||
You will find below the various methods to use communication channel for LowRA IoC plugin.
A plugin can have :
The private ( or internal ) events make communication flow beetween each part of the plugin.
Private events are used to execute Command associated with passed-in event type. ( FrontController design )
All stuff are done by the FrontController defined for each plugin instance.
First, take a look to a very basic Plugin implementation :
package
{
import com.bourre.ioc.bean.BeanFactory;
import com.bourre.ioc.parser.ContextNodeNameList;
import com.bourre.plugin.AbstractPlugin;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class PluginA extends AbstractPlugin
{
public static const onClickAButtonEVENT : String = "onClickAButton";
public function PluginA( )
{
super( );
buildButton( );
}
public function buildButton( ) : void
{
var button : Sprite = new Sprite( );
button.graphics.beginFill( 0x000000, 1 );
button.graphics.drawRect( 10, 10, 100, 20 );
button.graphics.endFill( );
button.buttonMode = true;
button.addEventListener( MouseEvent.CLICK, onClickHander );
var root : DisplayObjectContainer = BeanFactory.getInstance( ).locate( ContextNodeNameList.ROOT ) as DisplayObjectContainer;
root.addChild( button );
}
public function onClickHander( event : MouseEvent ) : void
{
}
}
}Really simple; just add a button on the root container.
Adds event listener to "MouseEvent.CLICK" button event type.
When button was clicked, we want to inform user the button was clicked ( opening a dialog box on simply logging message throw logger targets ), main goal is to show message to user.
We can simply use the MouseEvent.CLICK handler,but here, we will define a dedicated Command to encapsulate the "show message to user process".
So, we can call this command anywhere in Plugin ( in models, in views, in others commands ) when we have to show a message to user. ( encapsulation power ! )
This is a simple Command named : ShowMessage.as
package
{
import com.bourre.commands.AbstractCommand;
import com.bourre.error.UnreachableDataException;
import com.bourre.events.StringEvent;
import flash.events.Event;
public class ShowMessage extends AbstractCommand
{
public function ShowMessage( )
{
}
override public function execute( event : Event = null ) : void
{
if( event == null || !( event is StringEvent ) )
{
var msg : String = this + ".execute() failed, event data is unreachable";
getLogger().error( msg );
throw( new UnreachableDataException( msg ) );
}
else
{
getLogger().debug( getOwner() + "say : " + StringEvent( event ).getString() );
}
}
}
}
ShowMessage only logs message using LowRA Logging API (enough for this example).
Now we have to associated this command with an event type ( FrontController rules ), thus, when want to execute ShowMessage command, will just send this event.
To associate Command with event type, use the FrontController defined in current plugin.
public function initController() : void
{
var c : FrontController = getController( );
c.pushCommandClass( "onShowMessage", ShowMessage );
}
Okay, now all is ready. Command is implemented, Event type is associated.
To execute ShowMessage command, just dispatch the associated event type using FrontController broadcaster.
To do this, use the firePrivateEvent() method.
So our method named onClickHandler() become :
public function onClickHander( event : MouseEvent ) : void
{
firePrivateEvent( new StringEvent( "onShowMessage", this, "Button was clicked" ) );
}
When button was clicked, private event is dispatched using FrontController. Command associated with event type brodcasted is found and executed.
In output panel, we have a message like : "PluginA say : Button was clicked".
Summary :
Private ( or internal ) events dispatching : events are broadcasted only in current plugin.
firePrivateEvent( ) method
The public events make communication with all plugins defined in IoC context.
We have to define communication between plugins in the xml context. ( without specific definition, no communications are allowed ).
First, define a new Plugin to show comminucation with our PluginA plugin, named it PluginB :
package
{
import com.bourre.ioc.bean.BeanFactory;
import com.bourre.ioc.parser.ContextNodeNameList;
import com.bourre.plugin.AbstractPlugin;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class PluginB extends AbstractPlugin
{
public function PluginB( )
{
super( );
}
}
}
Example scenario : we want to use PluginB as "Message display" for all messages from PluginA.
So, PluginB should implement event handler for the "PluginA#onShowMessage" event type.
Let's implement it now and this is the new PluginB implementation :
package
{
import com.bourre.ioc.bean.BeanFactory;
import com.bourre.ioc.parser.ContextNodeNameList;
import com.bourre.plugin.AbstractPlugin;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class PluginB extends AbstractPlugin
{
public function PluginB( )
{
super( );
}
public function onShowMessage( event : StringEvent ) : void
{
getLogger().debug( "I receive a message from application : " + event.getString() );
}
}
}
Important : The event handler name must be the same as event type broadcasted.
Here, PluginA will dispatch a "onShowMessage" event type, so PluginB must implement a onShowMessage() method.
PluginB is ready to receive PluginA event; we have to built communication between this two plugins.
Communication is done in xml context :
<beans> <dll url="PluginADLL.swf" />
<dll url="PluginBDLL.swf" />
<root id="root" />
<plugin id="pluginA" type="PluginA" /> <plugin id="pluginB" type="PluginB"> <listen ref="pluginA" /> </plugin> </beans>
Communication is define using the <listen> context node.
Here we pass the reference to PluginA to tell the PluginB : "Hey PluginB ! you have to listen all public events from PluginA ok ?"
You can listen to as many plugin as you want.
PluginB is ready, communication is defined in context.
Last step, PluginA have to dispatch this event type into the public communication channel.
To dispatch public events ( so events which can be listened by others plugin ), we have to call the firePublicEvent( ) method.
Example, our PluginA.onClickHandler() become :
public function onClickHander( event : MouseEvent ) : void
{
firePublicEvent( new StringEvent( "onShowMessage", this, "Button was clicked" ) );
}
When button on PluginA was clicked, the output is now : "I receive a message from application : Button was clicked"
Great, is PluginB who received the message !
Summary :
Public events dispatching :
firePublicEvent() method
The external ( or targeted ) events make communication between specific plugin in IoC context.
Taking the same example as for "Public commnication", now PluginA don't want to dispatch public event.
PluginA want to dispatch his #onShowMessage to a specific plugin in context; here our PluginB plugin.
PluginB implementation does not change; event handler must defined to be triggered by the event API.
PluginA must be modified to store a reference to "which plugin is targeted for event communication".
In fact, we can define this reference in two ways :
To avoid coupling, it is better to set this reference by the xml context, like this :
<beans> <dll url="PluginADLL.swf" />
<dll url="PluginBDLL.swf" />
<root id="root" />
<plugin id="pluginA" type="PluginA"> <method-call name="registerChannel"> <argument ref="pluginB" /> </method-call> </plugin> <plugin id="pluginB" type="PluginB" /> </beans>
No more <listen> node definition; events are no more public.
We call a new PluginA#registerChannel( ) method to store the reference to the targeted plugin for communication, here the PluginB.
Note : I decide to add a new method to register channel, but it is possible to pass this reference directly in PluginA constructor.
This is the implementation of this registerChannel( ):
private var _oMsgChannel : EventChannel;
public function registerChannel( target : Plugin ) : void
{
_oMsgChannel = target.getChannel();
}Reference to dedicated plugin is done.
To fire events throw this specific communication channel, we use the #fireExternalEvent( ) method :
public function onClickHander( event : MouseEvent ) : void
{
fireExternalEvent( new StringEvent( "onShowMessage", this, "Button was clicked" ), _oMsgChannel );
}When button on PluginA was clicked, the output is now : "I receive a message from application : Button was clicked"
Great, is PluginB only who received the message !
Summary :
External events dispatching :
fireExternalEvent() methodNote : If you want to store channel reference using BeanFactory locator, so without any xml context information, simply retreive targeted plugin instance, and get the channel :
public function onClickHander( event : MouseEvent ) : void
{
var targetPlugin : Plugin : BeanFactory.getInstance().locate( "pluginB" ) as Plugin;
var targetChannel : EventChannel = targetPlugin.getChannel();
fireExternalEvent( new StringEvent( "onShowMessage", this, "Button was clicked" ), targetChannel );
}
Problem with this way : if you change the ID of the PluginB in xml context, you have to recompile the PluginA. ( coupling is bad ).