The UcompOS Event Propagation Model

The other day, I wrote a blog posting describing how the UcompOS RPF implements the MVC design pattern.

This implies that there is an event-driven architecture that has been facilitated in the UcompOS Continuum and that is indeed the case.

In this blog posting, we have to roll our sleeves up and really dig into the UcompOS SDK so that I can help you understand how the UcompOS RPF Event Architecture works.  If you have full command of the UcompOS RPF’s event architecture, it will help you build the most engaging and interactive rich experiences for your Rich Portal Applications.

The architecture at first glance is necessarily complex and involved and this will probably likely be just one of many blog postings I’ll make in reference to this topic and as time passes, I am going to work hard to make the event architecture simpler, more transparent, and as close as possible to best practice.  Of course developer feedback will be a crucial part of that mission.

CommandObject Transactions

If you’ve read my other postings, you have a very basic understanding of Proxy Components and Services Dictionaries.

Simply put, a UcompOS entity exposes its internal functionality to other UcompOS entities by publishing a Services Dictionary and a UcompOS entity contacts functionality in another entity by using a Proxy Component.

By strict convention, ALL communication between entities in the UcompOS Continuum should occur via the SDK class SDKClient and its send(); method.  (NOTE: There is a very esoteric exception to this that is handled behind the scenes by the UcompOS RPF that would involve two UcompOS entities participating in drag and drop interactions but that is beyond the scope of my article here and will be covered in an upcoming tutorial.)

The UcompOS SDK has both client and server infrastructure implemented.  Therefore, each UcompOS entity is capable of serving both as a server capable of receiving commands from other entities as well as a client capable of sending commands to other entities simultaneously.

The UcompOS RPF implements an asynchronous event dispatchment model.

When an entity needs to access a public API command in another entity, it (usually with the assistance of a Proxy Component) creates a CommandObject instance that is packaged into a DataPackage instance and sends it to the target entity via the SDKClient send(); method.  All these details are masked by the call(); method of AbstractProxyComponent which all Proxy Components must inherit from.

The server(); method of the SDKServer class is the first spot in the target entity to come in contact with the DataPackage.

DataPackages sent across the SDK Tunnel are encoded into compressed ByteArrays.

The server implementation in the SDK decodes the DataPackage and passes it to one of a couple different polymorphic constructs in the SDK:  CommandObjectHandler or EventObjectHandler

In the scenario where one entity is contacting the public API method of another entity, the DataPackage will contain a CommandObject and thus the DataPackage will be passed to the CommandObjectHandler in the SDK.

This will pass the data Object to the internal implementation code in the target entity.

By strict convention, any method that is capable of being targeted by another entity must accept exactly one parameter of type Object and return an item of type Object.

In order to understand the full event cycle in the UcompOS RPF, we must study what happens when this public API method returns this Object.  Where does this Object go from here?  How does it get back to the calling entity?

CommandObjectHandler passed the DataPackage to the internal implementation method and is returned the Object return from the method.

At this point, CommandObjectHandler turns from a server implementation to a client implementation and it creates a new DataPackage, puts an EventObject instance into it, and then sends the DataPackage back to the original entity.  So the original entity then becomes a server.

When the DataPackage with the EventObject packaged into it gets back to the SDKServer implementation in the calling entity, it is passed to the EventObjectHandler class.

The EventObjectHandler class then passes it to any event handlers that have been attached to the Proxy Component that made the initial public API call in the first place.

This is in fact why AbstractProxyComponent, which all Proxy Components extend from, inherits from EventDispatcher – so we can implement addEventListener(); thus implementing a paradigm many Flex and Flash coders are much more accustomed to.

When a public API method returns its required Object, an eventType property can be set to it.  If you do not explicitly set this, then CommandObjectHandler will set this for you as the constant SDKEvent.COMPLETE.

This eventType property is important as it has implications as far as how events get passed to a Proxy Component’s event handlers.

Suppose I have the following Services Dictionary class in a UcompOS application:

package
{
 
  import com.ucompass.ucompos.sdk.server.AbstractServicesDictionary;
 
  public class ServicesDictionary extends AbstractServicesDictionary
  {
    _map =
    {
      'Greeting.sayHello':
      {
 
        static:true,
        classRef:api,
        method:'sayHello',
        description:'Returns a greeting'
      }
 
    };
 
  }
 
}

Let’s suppose I have the following public API method that maps to Greeting.sayHello in my Services Dictionary example above:

public static function sayHello(data:Object):Object
{
  return {eventType:"Hello",greeting:"Hello there, "+data.name+"!"};
}

Now let’s suppose my Proxy Component located in another entity that will contact the Greeting.sayHello method above looks something like this:

package
{
 
  import com.ucompass.ucompos.sdk.client.AbstractProxyComponent;
  import com.ucompass.ucompos.sdk.model.SDKModel;
 
  public class Greeting extends AbstractProxyComponent
  {
 
    public function Greeting()
    {
      super._destination = SDKModel.getInstance().parent;
    }
 
    public function getGreeting(name:String):void
    {
      call("Greeting.sayHello",{name:name});
    }
 
  }
 
}
}

In my entity that will call Greeting.sayHello, I may see the following:

var g:Greeting = new Greeting();
g.getGreeting("Edward");

Now how do I get the greeting back from the entity that is exposing the public API method Greeting.sayHello?

Because AbstractProxyComponent extends EventDispatcher, and because my Greeting Proxy Component extends AbstractProxyComponent (a strict requirement of all Proxy Components), I can add an event listener to it.

g.addEventListener("Hello",greetingHandler);
 
private function greetingHandler(event:SDKEvent):void
{
  var greeting:String = event.data.greeting;
}

Notice my event handler is passed an instance of SDKEvent.  This is universal for all Proxy Components.

The SDKEvent instance will have a data property which will be the data Object returned by the remote public API method in the contacted entity.

Therefore, the eventType property in the return Object of a public API method determines which Proxy Component event handlers are passed an SDKEvent instance.

UcompOS Continuum Events

The above example shows a very simple example of an asynchronous request-response phase of a Proxy Component – public API method transaction.

There is another type of event in the UcompOS RPF called a Continuum Event.

The UcompOS Portal sponsors a public API method named GlobalManager.dispatchEvent.  This is accessed through the UcompOSGlobalManagerProxy Singleton class in the UcompOS SDK and its dispatchContinuumEvent(); method which accepts as input two parameters: type:String, and data:Object

When this method is accessed, every entity in the entire UcompOS Continuum is dispatched the event.

The implications of this is that you can monitor activity across the boundaries of different applications.  For instance, maybe you have a UcompOS Chat Application and when you receive an instant message from an individual user, you automatically want a separate UcompOS Address Book Application to open to that user’s Address Book entry.

Targeted EventObject Instances

The BroadcastEvent Singleton class in the UcompOS SDK has a dispatchEvent(); method.  This lets you send an EventObject on the fly to a single target entity.

For instance, the UcompOS SDK has a Proxy Component, that is the interface to various public API methods in the UcompOS Portal, called UcompOSWindowProxy.  The UcompOSWindowProxy‘s add(); method attaches an MDI window to the UcompOS Portal.

Internal to the UcompOS Portal implementation, it wants to notify the entity that created the UcompOS Window instance when certain user-driven activities occur such as when the window is moved, closed, minimized, maximized, etc.

Let’s look at a very simple example with some code.

Let’s suppose I have a UcompOS Application and I want to create a UcompOS Window, then I want to know when the user has closed the window.

In my application, the code I’d use to form the UcompOS Window could look like this:

var w:UcompOSWindowProxy = new UcompOSWindowProxy();
w.add("http://desktop.ucompass.com/MySubApp.swf","My Sub Application",500,500,100,100);

This will load the content at http://desktop.ucompass.com/MySubApp.swf into a UcompOS Window of dimensions 500 x 500 positioned at (100,100) from the upper-left origin point of the UcompOS Portal.

Now suppose I want to know when that window has closed.

No problem:

w.addEventListener(UcompOSWindowProxy.CLOSE,closeHandler);
private function closeHandler(event:SDKEvent):void
{
 // the window has closed
}

The reason why this works this way is that internal to the UcompOS Portal, there is a call to the UcompOS SDK static method BroadcastEvent.dispatchEvent(); that dispatches an EventObject (encapsulated in a DataPackage of course) to the entity that created the UcompOS Window.

As another example, consider the UcompOSMenuBarProxy class.  I haven’t covered the UcompOS Menu Bar in any tutorials quite yet, but the UcompOSMenuBarProxy class has a setMenuBar(); method that lets you attach an XML model that will be used as the dataProvider for the Menu Bar on the UcompOS Portal while the application in scope is in focus.

You could do something like this:

var menuModel:XML = new XML("<menu><menuitem label='File'><menuitem label='Open' data='1'/><menuitem label='Close' data='2'/></menuitem></menu>");
var m:UcompOSMenuBarProxy = UcompOSMenuBarProxy.getInstance();
m.setMenuBar(menuModel);
m.addEventListener(UcompOSMenuBarProxy.CHANGE,menuBarHandler);
 
private function menuBarHandler(event:SDKEvent):void
{
 var chooseString:String = "User chose "+event.data.label+" whose data property is "+event.data.data;
}

Summary

The event architecture in the UcompOS RPF is indeed complex at first glance.  There is no getting around that.  I am going to continue to work to simplify it, improve the documentation surrounding it, and get the implementation details as close as possible to a true best practice MVC implementation.

The UcompOS RPF Implements the MVC Design Pattern

The Model-View-Controller (MVC) design pattern is a classic design pattern often used by applications that need the ability to maintain multiple views of the same data.

The internals of the UcompOS Portal application (which is a Flex 4 application) were created strictly following the MVC Design Pattern.

In addition, the overall UcompOS Continuum (I refer to the UcompOS Continuum as the UcompOS Portal and all the UcompOS applications and sub-applications it launches that work together collectively to create a Rich Experience) takes on an implementation style that closely resembles MVC.

When a UcompOS application is launched by the UcompOS Portal, the application is invisibly loaded into the UcompOS run-time.  It has no visual presentation.  You can launch a UcompOS application immediately into a UcompOS Window or UcompOS Browser Window by adding the selfLoading=’true’ attribute to the application’s root Application Manifest element (which will launch the content in a UcompOS Window) and the newWindow=’true’ attribute (which will launch the content in a UcompOS Browser Window).  Even in these scenarios though, a “helper” UcompOS Application is loaded into the UcompOS run-time which then is given the task of launching your application’s base content into a UcompOS Window or UcompOS Browser Window instance.  So technically, in these scenarios, your UcompOS base application code is actually a sub-application.

In a best practice implementation, you can think of the base source code of your overall UcompOS Application (that gets loaded invisibly into the UcompOS run-time) as serving as the Model and Controller for your UcompOS Application and the sub-applications that are launched into UcompOS Window, UcompOS Browser Window, or UcompOS Artifact instances as the View from an MVC implementation point of view.

From a terminology point of view, I have been internally referring to the content that is loaded invisibly into the run-time as the Portlet Manager, and the visual code launched into UcompOS Browser Windows, UcompOS Windows, or UcompOS Artifacts as the Portlets.  I have refrained from making this the official terminology however.  This project, necessarily, has a lot of jargon associated with it and I want to be very judicious and careful with the terms used to describe the various aspects and features of the framework.

In the implementations I have been building, I delegate any network responsibilities as far as retrieving data from a remote data source or updating a remote model to the Portlet Manager.  The Portlet Manager also implements listeners to the artifacts, windows, and browser window instances it spawns and launches and manages other Portlets based on user interactivity with said artifacts, windows, and browser window instances.

In a Portlet instance, there will obviously be functionality that involves manipulating or working with data presentations that correspond to  the Model in the overall application.  My standard practice is to dispatch any model changes to the Portlet Manager by using a Proxy Component class housed in the Portlet instance and a public API method exposed in the Portlet Manager’s Services Dictionary.

One thing I haven’t talked about in my postings yet is the Event Dispatchment architecture in the UcompOS RPF.  This topic is worthy of and will receive thorough coverage in the near future.

As a very generic foreshadowing to this, the AbstractProxyComponent class is in the UcompOS SDK and it is the class all Proxy Components must extend.

AbstractProxyComponent itself extends EventDispatcher and therefore, any Proxy Component has the addEventListener(); method available to it.

The event type you can register with a Proxy Component is of type SDKEvent which is also a class built into the UcompOS SDK.

As a very simple example, consider the following example code implemented in a UcompOS Application:

var w:UcompOSWindowProxy = new UcompOSWindowProxy();
w.add("http://www.google.com","Google",800,600,100,100);

This will open a UcompOS Window in the UcompOS Portal of dimensions 800 x 600 at 100,100 relative to the upper-left origin point.

Now, consider the following:

w.addEventListener(UcompOSWindowProxy.CLOSE,closeHandler);
private function closeHandler(event:SDKEvent):void
{
  // the window was closed!
}

I’ll devote my entire next posting to the SDKEvent class which is extremely important in terms of building highly interactive Rich Portal Applications with the UcompOS RPF and I’ll walk through the data flow and event propagation model involved with the simple example above.