Garbage Collection in the UcompOS RPF

OscarTheGrouch In large and sophisticated Flash-based applications, such as the Rich Portal Applications you develop with the UcompOS Rich Productivity Framework, Garbage Collection becomes an increasingly important consideration.

Garbage Collection is a computer science concept that deals with memory management and re-allocating memory occupied by objects that are no longer needed or in use by the computer program.

Garbage Collection in a large-scale event-driven Flash architecture is a crucial consideration and unfortunately, can also be a tedious proposition to properly implement.

One of the more important considerations in aiding with Garbage Collection in Flash-based application is proper management of event listeners.

In a best-practice implementation, any call to addEventListener() would be followed up with a call to removeEventListener() once the event listener was no longer needed. Event listeners perpetuate the objects they are associated with so even once a particular object is destroyed, that doesn’t necessarily mean any event listeners associated with it will be destroyed too.

Failure to remove event listeners once they are no longer needed in a large-scale implementation can cause memory leaks and performance can break down over time.

In all your Flash applications, you should employ this strategy when and where possible.

In a typical large-scale UcompOS RPF implementation, Flash-based applications and sub-applications are continuously being loaded and unloaded into the UcompOS Portal.

The concept of Proxy Components in the UcompOS RPF involves event listeners being attached to a Proxy Component in one entity that represents an object in another UcompOS entity and then listening for dispatched events.

Therefore, the concept of garbage collection takes on especially critical importance in the UcompOS RPF because if UcompOS applications are being loaded and unloaded constantly and the event listeners that are attached to them are not being properly removed, performance would become an issue in a large-scale implementation.

The UcompOS Portal has been designed such that when SWF content that has been loaded into the UcompOS Portal is unloaded, a garbage collection routine is implemented to try to optimize system performance. (The three ways SWF content is loaded into the UcompOS Portal is in UcompOS Window instances, UcompOS Artifact instances, or into the UcompOS run-time.)

As of the UcompOS RPF Public Alpha release 0.4.6, some additional enhancements to the garbage collection process have been implemented that I will discuss here.

Understanding the UcompOS RPF garbage collection architecture can help you build more scalable Rich Portal Applications.

The recent enhancements come in the realm of Proxy Components.

By strict convention, all Proxy Components must extend the SDK class AbstractProxyComponent. As of UcompOS RPF 0.4.6, AbstractProxyComponent now extends a new SDK class called SDKEventDispatcher which extends EventDispatcher.

(Also, as a side-note, the AbstractProxyComponent class now implements IEventDispatcher in addition to IProxyComponent so you can refer to your Proxy Components as IEventDispatcher or IProxyComponent instances interchangably.)

SDKEventDispatcher simply overrides addEventListener() and offers a protected property _listeners of type Array.

I chose to create this separate class versus simply overriding addEventListener() in AbstractProxyComponent so that in the event the new clean-up process employed can be useful outside the scope of a Proxy Component, one could simply extend SDKEventDispatcher versus EventDispatcher.

Here is the over-ridden addEventListener():

override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
{
	_listeners.push({type:type,listener:listener});
	super.addEventListener(type,listener,useCapture,priority,true);
}

Notice that I am always assigning a true value to the useWeakReference parameter in the super call to addEventListener(). This is because in the context of attaching event listeners to Proxy Components, you always would want them to be weak references to aid in garbage collection.

In AbstractProxyComponent, there is a new protected method, cleanup() which is as follows:

protected function cleanup(event:SDKEvent=null):void
{
	while(_listeners.length)
	{
		var object:Object = _listeners.pop();
		removeEventListener(object.type,object.listener);
	}
	_sdkModel.removeProxyComponent(this.uuid);
	var commandObject:CommandObject = new CommandObject("SDK.cleanup",{uuid:this.uuid});
	var dataPackage:DataPackage = new DataPackage(Utilities.createUID(),_sdkModel.connectionId,this.destination,commandObject);
	_sdkClient.send(dataPackage);
}

What the cleanup() method does is it automatically removes any event listeners that have been attached to the Proxy Component.

It also sends a message to the end-point of the Proxy Component targeting its SDK.cleanup public API method that is built into the UcompOS SDK and therefore exposed by any UcompOS entity. This aids in UcompOS RPF garbage collection-related activities.

Calls to cleanup() do not occur automatically.

When you would call cleanup() in a Proxy Component would be an implementation specific consideration.

For instance, with these new capabilities, I have updated some of the UcompOS Portal Proxy Components that are built into the UcompOS SDK.

Consider the updated constructor of the UcompOSWindowProxy class:

public function UcompOSWindowProxy()
{
	super();
 
	// set the destination property to the UcompOS Portal
	super._destination = _sdkModel.root;
	<strong>addEventListener(CLOSE,cleanup);</strong>
}

The call to addEventListener(CLOSE,cleanup) is the new addition to the constructor.

What it does is it causes the inherited cleanup() method to always be called when the UcompOS Window instance on the UcompOS Portal that is represented by the UcompOSWindowProxy instance is closed.

Therefore, any event listeners you have attached to the UcompOSWindowProxy instance are automatically removed whenever the window is closed.

In 100% of the possible use cases for the UcompOSWindowProxy, this is the desired behavior.

The net result of this is you don’t have to worry about making your own calls to removeEventListener() for your particular UcompOSWindowProxy instances.

The same sort of behavior has been engineered into some of the other Proxy Components built into the UcompOS SDK including UcompOSAlertProxy, UcompOSDialogueProxy, UcompOSArtifactProxy, and UcompOSBrowserWindowProxy.

Consider this strategy when you are building your own Proxy Components and remember to always use removeEventListener() in all your other Flash applications whether you are deploying them in the UcompOS Portal or not.

Cross-Application Interactions in UcompOS Implementations

One of my primary goals in the design of the UcompOS Rich Productivity Framework was to create a flexible environment for the deployment of multiple Rich Internet Applications that needed to work either separately, or discretely to create a singular overall rich experience.

UcompOS Applications launched by the UcompOS Portal are sandboxed in such a way that they exist as isolated entities that can operate independently from the environment they’ve been loaded into.

As I touched upon in my posting on Building Drag and Drop Experiences in the UcompOS RPF, UcompOS applications should not attempt to access other UcompOS entities directly through direct ActionScript or JavaScript class/method interaction.

This is not to say that you cannot do this, but if you were going to, say, load two separate UcompOS entities into a n0n-sandboxed configuration, and have each entity access the other’s classes, you would obviously be tightly coupling the entities in such a way that if two different developers were working on each entity, one could very easily break the implementation unintentionally.

If you have a very compelling reason to do this, I have not prevented you from doing this.

In this posting, I will touch upon some of the numerous models for achieving cross-application interactivity in the UcompOS RPF.

Proxy Components and Services Dictionaries

The model for interactivity across the boundaries of UcompOS entities and applications is to use the framework that’s built into the UcompOS SDK, mainly Services Dictionaries and Proxy Components.  These are two extremely important concepts to understand, which is why I touch upon them so frequently.

In review, a Services Dictionary publishes a list of the “Public API” methods that an entity exposes to other entities.  A Proxy Component is a client apparatus in one entity that is built to connect to the Public API method sponsored by some other entity.

As I’ve also explained numerous times, and particularly in this posting, the UcompOS SDK has a number of Proxy Components built into it that are client apparatus’ to the Public API methods of the UcompOS Portal.  After all, the UcompOS Portal is simply one entity in the overall context of the UcompOS Continuum.

Numerous postings and tutorials I’ve posted give examples of building Services Dictionaries and Proxy Components so I won’t go into the details of this in this posting, but again, understanding their mechanics is crucial.

UcompOS SDK Events

Another crucial concept to understand in the UcompOS RPF is its Event-based implementation.

By strict convention, all Proxy Components extend a class in the UcompOS SDK named AbstractProxyComponent.

As the name implies, it is an abstract class and should never be instantiated directly, only extended.  (Unfortunately, ActionScript 3 doesn’t give us a true foolproof way to enforce abstractness.)

AbstractProxyComponent extends EventDispatcher so thus all Proxy Components inherit an addEventListener(); method.

So essentially, in one UcompOS entity, you can build a Proxy Component that talks to the Public API method in another entity.  And you can register an event listener to receive event notices from that Proxy Component.

That’s why I call these things “Proxy” Components.

You are creating a virtual representation in one entity of a physical implementation in another entity, so essentially, your Proxy Component is a “Proxy” to the true implementation that is actually located in an entirely different entity.

So when you do something like the following:

var w:UcompOSWindowProxy = new UcompOSWindowProxy();
w.add("http://blog.ucompass.com","UcompOS",800,600);
w.addEventListener(UcompOSWindowProxy.CLOSE,closeHandler);

w in the above scenario is an instance of the Proxy Component UcompOSWindowProxy that is built into the UcompOS SDK.

w is not REALLY the window that gets created on the UcompOS Portal, but it is a virtual representation of it.

But when you add an event listener on the CLOSE event of the window, it is as if you are attaching an event listener to the actual window itself.

I am hopeful that the concept of Proxy Components is making more and more sense to the dedicated readers of this blog.

The event handlers implemented with any Proxy Component are exclusively dispatched an instance of the SDKEvent class.

The SDKEvent class is worth studying.

If you look at the AS3 docs for the SDKEvent class, you’ll notice it has a collection of read-only properties.  One of which is data and another is proxyComponent.

By strict convention, any Public API method in a UcompOS entity returns an item of type Object.  This data is carried back to the Proxy Component that invoked the Public API Method in the form of an SDKEvent instance.

So for instance, building to our simple example above, I could do something like this:

w.addEventListener(UcompOSWindowProxy.WINDOW_INFO,windowInfoHandler);
w.getWindowInfo();
 
private function windowInfoHandler(event:SDKEvent):void
{
 
 // this will be the Object returned by the Public API method I contacted
 var data:Object = event.data;
 
 trace("Window size is "+data.width+" x "+data.height);
 
}

Let’s talk a bit about the proxyComponent property of SDKEvent instances.

It is of type IProxyComponent.

The AbstractProxyComponent event implements the interface IProxyComponent from the SDK, so any Proxy Component can be cast as an item of type IProxyComponent.

Dispatching an Event to a Proxy Component from a Public API Method

So you have built your Public API method and you have set up a Proxy Component in another entity to connect to this Public API Method.

As I have explained, the Object your Public API Method MUST return will be returned to your Proxy Component packaged in an SDKEvent instance.

But what if you asynchronously want to dispatch an SDKEvent to a Proxy Component?

The key to this is the BroadcastEvent class in the SDK and its static dispatchEvent(); method.

As an example of when we might use this capability, suppose we have a UcompOS AIR application that sponsors a Public API Method that allows us to asynchronously return the list of files in a directory.

The implementation of this might look something like this:

private var _uuid:String;
 
public function getFilesInDirectory(data:Object):Object
{
 _uuid = data._dataPackage.uuid;
 var directory:File = new File(data.directory);
 directory.addEventListener(FileListEvent.DIRECTORY_LISTING,getFilesInDirectory_handler);
 directory.getDirectoryListingAsync();
 return SDKEvent.VOID;
}
 
private function getFilesInDirectory_handler(event:FileListEvent):void
{
 var files:Array = [];
 for(var i:uint = 0;i&lt;event.files.length;i++)
 {
 files.push((event.files[i] as File).name);
 }
 BroadcastEvent.dispatchEvent(_uuid,"fileListing",{files:files});    
}

As a brief aside, notice in the Public API method, I am returning SDKEvent.VOID.  This actually suppresses the return altogether of any data to the calling Proxy Component.  This is the best practice when your Public API method doesn’t return anything of value to the calling Proxy Component.

When the UcompOS SDK passes the input Object to a Public API method, it adds a property to the Object called _dataPackage which itself is an Object.

This Object has a property, uuid, which is the same value of the uuid property on the Proxy Component that originated the transaction with the Public API method.

The BroadcastEvent.dispatchEvent(); method expects this uuid value as the first input parameter.

A Proxy Component that invoked this Public API method could have an event listener listening for events of type “fileListing”.  In this scenario, the event handler would be dispatched an SDKEvent with the data dispatched to the BroadcastEvent.dispatchEvent(); method.

Dispatching Continuum Events

The UcompOSGlobalManagerProxy class in the UcompOS SDK has a method named dispatchContinuumEvent();.

It accepts two parameters – the type of event, and a data Object.

When you call this method, you are dispatching an event to every entity in the UcompOS Continuum and the event can be listened for on the UcompOSGlobalManagerProxy Singleton.

So for instance, you could say something like:

UcompOSGlobalManagerProxy.getInstance().dispatchContinuumEvent("myEvent",{name:Ed});

And in an entirely different entity, you could do something like this:

UcompOSGlobalManagerProxy.getInstance().addEventListener("myEvent",eventHandler);

and your event handler could look something like:

private function eventHandler(event:SDKEvent):void 
{
 
 trace("Your name is "+event.data.name);
 
}

The dispatchContinuumEvent(); method doesn’t need to target a specific entity as the BroadcastEvent.dispatchEvent(); method does – it simply dispatches an event to EVERY entity.

Launching one UcompOS Application from Another Entity

The UcompOSGlobalManagerProxy class has a launchApplication(); method which accepts as input an Application Manifest URL as a String.

This enables you to launch a UcompOS Application from another entity.  Similarly, there is a quitApplication(); method as well as a getConnectionId(); method which can be used to find the connectionId of an already running UcompOS Application.

UcompOS Shared Objects

As I posted here, the UcompOS RPF now has a Shared Object implementation where an entity can house Objects of specific names on an Object on the UcompOS Portal that is available to all other entities.

When any Shared Object is created or its properties are updated, a Continuum Event is dispatched.

This creates an environment where the Shared Object itself can become a useful medium for achieving inter-application and inter-entity communication.

A Simple UcompOS Shared Object Impementation Example

The new Shared Object implementation in the UcompOS Rich Productivity Framework provides an additional model for achieving inter-application and sub-application communication and data exchange in a manner that is grounded in the MVC (Model-View-Controller) Design Pattern.

The term Shared Object in the context of the UcompOS RPF is similar in principle to the concept of the Local Shared Object infrastructure that has been in the Flash Player since the days of Flash 4 but in our case, the UcompOS RPF Shared Object is a run-time Object that does not get saved locally (unless you of course configure your own implementation to do so).

In the UcompOS Portal is an Object that gets instantiated into the application’s run-time memory upon authentication.

This Object is then freely available for all UcompOS entities to access using the GlobalManager.setSharedObject, GlobalManager.getSharedObject, and GlobalManager.getSharedObjects public API methods sponsored by the UcompOS Portal.

The UcompOSGlobalManagerProxy class in the UcompOS SDK has an API to these methods in the public methods of the class as indicated  below:

public function setSharedObject(key:String, value:Object):void
public function getSharedObject(key:String):void
public function getSharedObjects(keys:Array):void

One of the more important aspects of the Shared Object implementation is that the UcompOS Portal dispatches a Continuum Event of type SDKEvent.SHARED_OBJECT whenever a property of the Shared Object changes.

A Continuum Event is an event dispatched to every entity in the UcompOS Continuum.

An entity can attach a listener to the UcompOSGlobalManagerProxy Singleton listening for SDKEvent.SHARED_OBJECT events.

The event Object will have a key and a value property representing the property on the Shared Object that was just modified and its associated value.

As a very simple example of what we can do with this, I set up a basic UcompOS implementation.

The implementation involves a UcompOS background application that launches a UcompOS Window with a text area.  Upon initialization, this application launches another UcompOS Window with a sub-application in it next to the initial window  This sub-application also has a text area.

When text is entered in the primary application window’s text area, the text is instantly displayed in the sub-application window’s text area.

The mechanics for this employ the UcompOS Shared Object.

I’ll share the code below so you can get an understanding of how it was configured:

The Dock Manifest

<applications>
 <application background="true">
  http://desktop.ucompass.com/Shared_Object/manifest.xml
 </application>
</applications>

The Application Manifest

<application selfLoading="true" width="500" height="500" x="0" y="100">
 <source>
 <base>http://desktop.ucompass.com/Shared_Object/windowA.html</base>
 </source>
 <titles>
 <title locale="en_US">Shared Object Example</title>
 </titles>
</application>

The Application Code

<html>
<head>
<title>Window A</title>
<script type="text/javascript" src="/UcompOSSDK.js"></script>
<script type="text/javascript">
 
 var g;
 var w;
 
 function start()
 {
  g = new UcompOSGlobalManagerProxy();
  w = new UcompOSWindowProxy();
  w.add("http://desktop.ucompass.com/Shared_Object/windowB.html","Echo",500,500,510,100);
 }
 
 function echo()
 {
  // pause for 1/100th of a second as the onkeypress event is dispatched before the textarea is updated
  setTimeout(function() { g.setSharedObject("echo",document.getElementById('text').value); },10);
 }
 
</script>
</head>
<body>
<u>Enter some text</u><br/>
<textarea id="text" style="width: 400px; height: 400px;" onkeypress="echo();"></textarea>
</body>
</html>

The Sub-Application Code

 
<html>
<head>
<title>Window B</title>
<script type="text/javascript" src="/UcompOSSDK.js"></script>
<script type="text/javascript">
 
 var g;
 var w;
 
 function start()
 {
  g = new UcompOSGlobalManagerProxy();
  g.addEventListener(g.SHARED_OBJECT,echo);
 }
 
 function echo(data)
 {
  switch(data.key)
  {
   case "echo":
    document.getElementById('text').value = data.value;
   break;
  }
 }
 
</script>
</head>
<body>
<u>What you're saying in the other window</u><br/>
<textarea id="text" style="width: 400px; height: 400px;"></textarea>
</body>
</html>

UcompOS SDK Communication Mechanics

I want to spend some time looking a bit deeper under the hood of the UcompOS SDK particularly in terms of how the SDK is configured to enable entities to talk to one another.

Understanding these mechanics can help you understand how to build the best Proxy Components that will promote the richest experiences for your UcompOS Rich Portal Application.

As you’ve read about in my previous blog postings, the Flash Player’s LocalConnection infrastructure is the medium used for inter-entity communication in the UcompOS Rich Productivity Framework.

A slight exception to this is with UcompOS AIR 2.0 applications that take advantage of AIR 2.0′s new ServerSocket class such that messages are sent to the AIR application over a socket versus LocalConnection.

My reasons for using LocalConnection despite its known limitations have to do with the fact that LocalConnection is such a practical lowest common denominator solution and is equally available to all versions of ActionScript.

Limitations of the LocalConnection include the inability to send data packets in greater than 40K chunks. The SDK elegantly works around this limitation by implementing its own incremental transmission and aggregation logic.

For the most part, the messages sent between entities don’t ever come anywhere near 40K but are closer to 1K. In some use cases, larger data chunks may need to be sent over the UcompOS “SDK Tunnel”. For instance, in Educator 2, I am building a whiteboard application and content drawn in the application often needs to be transmitted elsewhere as a ByteArray encoded PNG.

Messages sent back and forth in the UcompOS Continuum via the SDK are placed into an instance of a class called DataPackage. The DataPackage itself will receive a polymorphic construct of type IDataPackageObject as one of its input parameters.

(REMINDER: There is AS3 documentation for the SDK)

Currently, the classes in the SDK that implement IDataPackageObject are CommandObject and EventObject.

With this knowledge we can talk a bit more about the mechanics of data transmission.

As I’ve explained, a UcompOS entity serves both as a server and a client in the context of the UcompOS Continuum.

The “touch points” of a UcompOS entity are the classes SDKClient and SDKServer. SDKClient is of course also the class that is instantiated when a UcompOS application starts up.

The SDKClient‘s send(); method receives a DataPackage as input. In addition to the DataPackage having the polymorphic IDataPackageObject instance embedded, it also has information about the destination entity as well as the origin entity. The send(); method then uses the LocalConnection infrastructure, or an extended Socket class, to send the DataPackage to the remote entity (encoded into a compressed ByteArray).

The SDKServer then serves as the server infrastructure in a UcompOS entity.

The SDKServer‘s server(); method is the method targeted by the SDKClient‘s send(); method.

This method decodes the compressed ByteArray, serializes it into a DataPackage, and then determines what type of IDataPackageObject instance is in it.

It then passes the DataPackage to a polymorphic construct of type IServerHandler.

Right now, as you’d expect, there are two classes in the SDK that implement IServerHandler: CommandObjectHandler and EventObjectHandler.

Communication in the UcompOS RPF is both synchronous and asynchronous.

The transmission of a CommandObject from one entity to another results in the receiving entity generating an EventObject and passing it back to the sending entity in real-time. In that regard it is a synchronous communication process.

From an implementation point of view, the EventObjectHandler class causes the Proxy Component that made the original call in the calling entity to dispatch an event of type SDKEvent and this event object will have a data property that represents the data returned by the method contacted in the target entity.

The API method in the target entity must by strict convention return an item of type Object. This Object can have an eventType property which will be the event type of the SDKEvent dispatched by the calling Proxy Component via the EventObjectHandler class.

Typically in a UcompOS application, one would attach an event listener to a Proxy Component instance for the event type they knew would be returned by the target remote API method.

Thus the model takes on more of an asynchronous flavor even though you are able to take action on the return of data from a target entity in real-time.

There is a way to implement more of a callback type synchronous implementation.

The AbstractProxyComponent‘s call(); method returns a String that is used as the Universally Unique ID of the Transmission. All Proxy Components by strict convention must extend AbstractProxyComponent.

The EventObject that is returned from the target entity has a transactionId property that is the value of the String returned by the call(); method of AbstractProxyComponent.

One can easily facilitate a true callback strategy armed with this knowledge.

Building a Multilingual UcompOS Implementation

The UcompOS Rich Productivity Framework is designed to make it easy to serve localized Rich Portal Application implementations.

In this tutorial, we are going to explore the localization capabilities of the UcompOS RPF and look at some strategies for leveraging these capabilities.

I have created a Video that I encourage you to view that shows the implementation we are going to build in this tutorial in action, and you should also Download the source code that we build in this application so you can better follow along with it.

As is the case with most of our UcompOS tutorials, we are going to focus much less on aesthetics and presentation and more on the highlighting of core UcompOS fundamentals and mechanics.

In addition to highlighting the localization capabilities of the UcompOS RPF, we are also going to touch on a number of other useful and important topics including some advanced capabilities of UcompOS Application Manifest files as well as working with the UcompOSStyleProxy class which manages the aesthetic presentation of the UcompOS Portal.

In addition, we are going to learn more about the UcompOS Menu Bar, and also about the concept of declaring default UcompOS Background Applications.

Our Target Implementation

The implementation we want to build will involve a UcompOS application that opens some simple content in a UcompOS Window.  The content will internally be configured to display some simple text that can be automatically translated on the fly to another language using Yahoo’s BabelFish free translation API.

We will set up the application such that the user can switch the operating language using a “language chooser” we’ll build into the UcompOS Menu Bar.

We will also create graphical artifacts that provide a customized experience to the end user when they switch between languages.

The languages we’ll allow users to choose from will be:

  • English
  • Spanish
  • German
  • French
  • Italian

Two UcompOS Applications Involved

Our implementation will involve the construction of two UcompOS Applications.  One we will consider the Controller for our implementation, and another we will consider the View.

Both our applications will be UcompOS HTML applications that will leverage the UcompOS JavaScript SDK.

We are going to put all assets and code related to our implementation in a single folder named Multilingual.  Inside the Multilingual folder are controller and view subfolders with the pertinent assets and code in each folder.

Implementation Specifics

Let’s talk a little bit more about exactly how we want our implementation to behave.

We want to place a language chooser on the UcompOS Menu Bar that lets the user switch between languages.

We want this Menu Bar to be perpetually on the UcompOS Menu Bar even when our View application is in focus.

Our Dock Manifest

Let’s take a look at our Dock Manifest and discuss some of its more important aspects:

<applications>
<application background="true" default="true">

http://desktop.ucompass.com/Multilingual/controller/manifest.xml

</application>
<application>

http://desktop.ucompass.com/Multilingual/view/manifest.xml

</application>
</applications>

Obviously, the first UcompOS Application listed in our Dock Manifest is our Controller application and the second is our View application.

A very important point to discuss are the two attributes set for our Controller application, specifically background=”true” and default=”true”.

When you declare a UcompOS Application as a background application, that means it is to be launched immediately upon authentication to the UcompOS Portal and it is to not be presented on the UcompOS Application Dock.

The code is simply loaded in the UcompOS run-time immediately and remains available for interaction throughout the session.

Setting an application as the default has implications on the UcompOS Menu Bar – the Menu Bar of the application declared as the default application is the Menu Bar that shows when no application is in focus.

The best analogy to this is to consider the Finder application in Mac OS X.  The Finder’s Menu Bar shows up in Mac OS X when no other application is open.  Also, if you click the Mac OS X desktop on the wallpaper (not on an artifact from a running application), the Menu Bar of the Finder is what is displayed.

This is paralleled in the UcompOS RPF by designating an application with the default=”true” attribute in the Dock Manifest.

If no application is configured with the default=”true” attribute, then the base, default UcompOS Menu Bar is displayed when no application is in focus.

Also, if you try to configure a Dock Manifest with more than one application specified as the default, you’ll encounter a run-time error from the UcompOS Portal.

Also, in an individual application’s Application Manifest, you can instruct the UcompOS Portal to use the default Menu Bar.  We’ll look at this shortly as this will be how we configure our View application.

The Controller Application Manifest

Let’s take a look at the Application Manifest for our Controller:

<application>

 <source>
 <base>http://desktop.ucompass.com/Multilingual/controller/Controller.html</base>
 </source>

 <menu>
 <menuitem label="Language">
 <menuitem label="English" icon="http://desktop.ucompass.com/Multilingual/view/images/icons/en_US_menubar.png" data="en_US"/>
 <menuitem label="Spanish" icon="http://desktop.ucompass.com/Multilingual/view/images/icons/es_ES_menubar.png" data="es_ES"/>
 <menuitem label="German" icon="http://desktop.ucompass.com/Multilingual/view/images/icons/de_DE_menubar.png" data="de_DE"/>
 <menuitem label="French" icon="http://desktop.ucompass.com/Multilingual/view/images/icons/fr_FR_menubar.png" data="fr_FR"/>
 <menuitem label="Italian" icon="http://desktop.ucompass.com/Multilingual/view/images/icons/it_IT_menubar.png" data="it_IT"/>
 </menuitem>
 </menu>

</application>

As you can see our Controller Application Manifest is very simple but its chief critical responsibility is to furnish a Menu Bar implementation for the UcompOS Portal.

Since our Controller Application is configured as the default application in our Dock Manifest, its Menu Bar will be what displays when no other application is in focus.

The XML structure for the Menu Bar is very simple and straightforward.  Notice the icon property points to the network URL of an icon image to be displayed on the Menu Bar.  Also, a data property must be present in a Menu Bar node for an event to be dispatched to the applications and sub-applications the Menu Bar is associated with when the user chooses a Menu Bar option on the UcompOS Portal.

Our Menu Bar configures a Language Chooser on the UcompOS Menu Bar and lets the end-user choose between one of five different languages.

The View Application Manifest

Now let’s take a look at the View application’s Application Manifest:

<application selfLoading="true" width="500" height="500" x="100" y="100">

 <source>
 <base>http://desktop.ucompass.com/Multilingual/view/View.html</base>
 </source>

 <titles>
 <title locale="en_US">A Multilingual Application</title>
 <title locale="es_ES">Un uso multilingue</title>
 <title locale="de_DE">Eine mehrsprachige Anwendung</title>
 <title locale="fr_FR">Une application multilingue</title>
 <title locale="it_IT">Un'applicazione multilingue</title>
 </titles>

 <icons>
 <icon locale="en_US">http://desktop.ucompass.com/Multilingual/view/images/icons/en_US_dock.png</icon>
 <icon locale="es_ES">http://desktop.ucompass.com/Multilingual/view/images/icons/es_ES_dock.png</icon>
 <icon locale="de_DE">http://desktop.ucompass.com/Multilingual/view/images/icons/de_DE_dock.png</icon>
 <icon locale="fr_FR">http://desktop.ucompass.com/Multilingual/view/images/icons/fr_FR_dock.png</icon>
 <icon locale="it_IT">http://desktop.ucompass.com/Multilingual/view/images/icons/it_IT_dock.png</icon>
 </icons>

 <toolTips>
 <toolTip locale="en_US">See a UcompOS Application translate text into English</toolTip>
 <toolTip locale="es_ES">Vea un uso de UcompOS traducir el texto a inglés</toolTip>
 <toolTip locale="de_DE">Sehen Sie eine UcompOS Anwendung, Text ins Englische zu übersetzen</toolTip>
 <toolTip locale="fr_FR">Voir l'application d'UcompOS traduire le texte en anglais</toolTip>
 <toolTip locale="it_IT">Vedi un'applicazione di UcompOS tradurre il testo in inglese</toolTip>
 </toolTips>

 <menu default="true"/>

</application>

The first thing to notice about the Application Manifest above is the strategy employed for localizing Application titles, icons, and tool tips.

The Application Title shows up on the UcompOS Application Dock for a particular application as well as any UcompOS Windows that are spawned by the application.  The same applies to Application Icons.

Tool tips show up when the user mouses over an application icon on the UcompOS Application Dock and the mouse hovers for a second.

Notice how the locale attributes in this manifest match up to the data attributes for the menu bar model in our Controller manifest.

Another important thing to take note of is the <menu default=”true”/> element in the manifest.

This tells the UcompOS Portal that when this application is in focus, still use the UcompOS Portal’s default Menu Bar which will be the Menu Bar of our Controller Application.

Also, note the selfLoading=”true” attribute as well as the width, height, x, and y attributes in our manifest’s root <application/> element.

This tells the UcompOS Portal to launch the application into a UcompOS Window instance versus simply loading it into the UcompOS run-time.

Preparing the Graphics

The next task in building our implementation will be to prepare the graphic assets we’ll use.

In this implementation, I want our application icon to automatically update on the UcompOS Dock and UcompOS Window instances spawned by our application to reflect the most recently selected language.  So I’ll need five different application dock icons – one for each language.

Then on the UcompOS Menu Bar, we will add a “language chooser” utility.  I want each node in the language chooser, which will represent a different language, to have an icon representative of the given language.  So I’ll need five different menu bar icons – one for each language.

Finally, each time a new language is selected, I want the background wallpaper for my UcompOS Portal implementation to display an image representative of the chosen language.

I have created a folder named images in my Multilingual project’s view folder and in the images folder I’ve created two more folders:  icons and backgrounds.  I am placing the dock and menu bar icons in the icons folder and the background images in the backgrounds folder.

The Controller Source Code

As you can see in our Controller‘s Application Manifest, it points to the following network URL as the location for the application’s source code:

http://desktop.ucompass.com/Multilingual/controller/Controller.html

Let’s take a look at this application’s source code below and discuss it:

<html>
<head>
<title>Multilingual Controller</title>

<script type="text/javascript" src="/UcompOSSDK.js"></script>

<script type="text/javascript">

 var m;
 var g;
 var s;

 function start()
 {
 m = new UcompOSMenuBarProxy();
 g = new UcompOSGlobalManagerProxy();
 s = new UcompOSStyleProxy();

 m.addEventListener(m.CHANGE,menuChangeHandler);
 }

 function menuChangeHandler(menuData)
 {
 g.changeLanguage(menuData.data);
 s.setBackgroundImage("http://desktop.ucompass.com/Multilingual/view/images/backgrounds/"+menuData.data+".jpg");
 }

</script>

</head>
</html>

The first thing to notice is since this is an HTML application, we have the UcompOS JavaScript SDK installed.

Our start(); method employs a class we haven’t looked at yet in any of our tutorials, UcompOSMenuBarProxy, which manages and handles events dispatched by the Menu Bar on the UcompOS Portal.

In this case, we are added an event handler to handle CHANGE events.

In addition to the UcompOSMenuBarProxy, we are also working with the UcompOSGlobalManagerProxy and UcompOSStyleProxy classes in this application.

In this application, when we receive notification that the user has selected a new option on the Menu Bar, we access the newly selected language as the data property of the menuData Object passed to the event handler by the UcompOS SDK.

We then take that value and pass it to the changeLanguage(); method of the UcompOSGlobalManagerProxy.  This method configures the operating language on the UcompOS Portal with the newly chosen language string.  Whenever the UcompOS Portal’s operating language changes, a UcompOS Continuum Event is dispatched meaning that every running application and sub-application in the UcompOS Continuum is notified instantly.  This detail will be important to us when we look at our View application.

We also call the setBackgroundImage(); of the UcompOSStyleProxy and pass it the URL of a background image that is representative of the newly selected language.  This method sets the wallpaper image for the UcompOS Portal.

The View Source Code

As we saw in our View application’s Application Manifest, the source code of our View application is reachable at a network URL of:

http://desktop.ucompass.com/Multilingual/view/View.html

In the View application, we are starting with a string of text embedded in an HTML DIV element that is in the English language.

In our start(); method, we are creating an instance of the UcompOSGlobalManagerProxy class and calling its getSessionInfo(); method.  We are also attaching an event listener for events of type UcompOSGlobalManagerProxy.SESSION_INFO.

The getSessionInfo(); method the UcompOS Global Manager Proxy is extremely important.  It returns an Object with a number of important properties including the unique user Id that the current user is authenticated into the UcompOS Portal with.

Also, it returns the current language the UcompOS Portal is operating in in a property called language.

The exact implementation details regarding doing the actual language translation are outside the scope of the UcompOS RPF but I’ll explain them briefly.

We are using a web-based service called Enrich which provides an API to the Yahoo BabelFish free online language translation service to convert our content from one language to another.

One other UcompOS-related detail in our implementation is we are creating a UcompOSWindowProxy instance and setting its self property to true.

This lets us access the methods and properties of the UcompOS Window that the application we are operating in has been loaded into.

Once the user changes to a new language, we are then calling the UcompOSWindowProxy‘s setTitle(); method to update the title on the UcompOS Window in real-time.

Let’s take a look at the full source code of our View application below:

<html>
<head
<title>Multilngual Application</title>

<style type="text/css">

 body
 {
 font-family: Helvetica, Arial;
 font-size: 12px;
 }

 #title
 {
 font-size: 24px;
 background-color: #2677B6;
 color: #FFFFFF;
 font-weight: bold;
 text-align: center;
 padding: 2px;
 }

</style>

<script type="text/javascript" src="http://pilotfish.ucompass.com/gofish"></script>
<script type="text/javascript" src="/UcompOSSDK.js"></script>

<script type="text/javascript">

 var currentLanguage = 'en_US';
 var g;
 var thisWindow;
 var languageReference = {en_US:'English',es_ES:'Spanish',fr_FR:'French',de_DE:'German',it_IT:'Italian'};

 function start()
 {
 thisWindow = new UcompOSWindowProxy();
 thisWindow.self = true;
 g = new UcompOSGlobalManagerProxy();
 g.addEventListener(g.LANGUAGE_CHANGE,changeLanguage);
 g.addEventListener(g.SESSION_INFO,init);
 g.getSessionInfo();
 }

 function init(sdkData)
 {
 var c = setInterval(function () { if(callWebService) { clearInterval(c); changeLanguage(sdkData); } },100);
 }

 function changeLanguage(sdkData)
 {
 var query = new Object();
 query['feature'] = 'Search';
 query['module'] = 'Translate';
 query['sourceLanguage'] = currentLanguage;
 query['targetLanguage'] = sdkData.language;
 query['selectedText'] = document.getElementById('content').innerHTML;
 query['handler'] = 'changeLanguage_handler';
 callWebService(query);
 currentLanguage = sdkData.language;
 }

 function changeLanguage_handler(xmlObject)
 {
 document.getElementById('content').style.visibility = 'visible';
 document.getElementById('content').innerHTML = getTextNode(getXPath(xmlObject,"//translation")[0]);
 document.getElementById('title').innerHTML = languageReference[currentLanguage];
 thisWindow.setTitle(languageReference[currentLanguage]+" Window Title");
 }

</script>

</head>

<div id="title"></div>

<p/>

<div id="content" style="visibility: hidden;">
 As the name implies, an air mass is a mass of air that has
 relatively uniform characteristics with respect to temperature,
 and moisture. Air masses are often characterized by both their
 temperatures and their humidities. Air masses can basically be
 classified as warm or cold with respect to temperature and moist
 or dry with respect to humidity. The characteristics of an air
 mass are determined by the region over which it formed. For
 instance, during the winter, when the nights are long and frigid
 over the Polar regions, the air tends to become relatively
 uniform. A very cold and dry air mass develops. Occasionally,
 pieces of these air masses will break free and be transported by
 the jet stream.
</div>

<body>
</body>
</html>

Big Picture Conclusions

By isolating the language chooser into its own application, we are able to take advantage of the concept of UcompOS Continuum Events.  In our implementation, when the user changes their operating language, the UcompOSGlobalManagerProxy‘s changeLanguage(); method is invoked, which causes a UcompOS Continuum Event to be dispatched.

Therefore, we could have an unlimited number of UcompOS applications or sub-applications running, all of which employed their own custom logic and behavior when encountering a single language change event that originated in our Controller application.

Screen Capture

Below is a look at our implementation in operation:

Demo

How UcompOS Flash/Flex Applications are Sandboxed in the UcompOS Portal

There are numerous paradigms for launching UcompOS Applications in the UcompOS Portal.

In many instances, the UcompOS Application itself will be a non-visual entity thought of as perhaps the Model and Controller in an MVC style implementation and then the UcompOS Application would launch individual sub-applications in UcompOS Window, UcompOS Browser Window, or UcompOS Artifact instances which could be considered the View in the MVC implementation.

A UcompOS Application can also be an AIR application running on the desktop launched by the UcompOS Portal and also, a UcompOS Application can be launched immediately into a UcompOS Window or UcompOS Browser Window instance by implementing specific attributes in the root of the UcompOS Application’s application manifest.

The specific implementation details of SWF-based UcompOS content being loaded as a UcompOS application or sub-application into the UcompOS Portal warrants discussion.

If you’re an experienced Flash/Flex developer, you may come to the UcompOS RPF with a pre-conceived idea about how things are implemented and how you would go about building rich experiences.

There are 3 different scenarios where SWF content will be loaded directly into the UcompOS Portal:

  1. The SWF content represents a UcompOS Application that is loaded into the UcompOS Portal run-time.  In this case the SWF content is a non-visual entity.  It gets loaded into a SWFLoader with its visible property set to false that is attached directly to the UcompOS Portal as a child.  This application then likely is involved with launching sub-applications into UcompOS Window, UcompOS Browser Window, or UcompOS Artifact instances.
  2. The SWF content represents a UcompOS sub-application that is loaded into a UcompOS Window instance.  In this case, the SWF content is a visual entity.  It gets loaded into a SWFLoader and the SWFLoader is attached as a child to a UcompOS Window instance.  A UcompOS Window instance is derived from a class that extends the MDIWindow class from the mdi package in the FlexLib project.  And of course MDIWindow extends Panel.
  3. The SWF content represents a UcompOS sub-application that is loaded into a UcompOS Artifact instance.  In this case, the SWF content is a visual entity.  A UcompOS Artifact is actually a VBox implementation that gets attached to the UcompOS Portal and then the SWFLoader is attached as a child to the VBox instance.  The UcompOS Portal is a Flex 4 application with the Halo theme compiled so that is how I am using VBox here.

Here’s the important thing to understand about the SWFLoader instances implemented in all 3 of the above scenarios.  They are implemented in one of two “sandboxed” configurations.

If you are creating a Rich Portal Application and your intentions are to load two separate UcompOS Applications into the UcompOS Portal and then do some sort of coding where your accessing something like FlexGlobals.topLevelApplication, this will not work.

All communication with other entities in the UcompOS RPF should be accomplished exclusively via the communication protocols in the UcompOS SDK using implementations such as Proxy Components and public API methods exposed in Services Dictionaries.

The goal is to keep the UcompOS Portal as “dumb” as possible and enable it to focus exclusively on being really good at its base core objectives which are:

  • An MDI (Multiple Document Interface)
  • Style and aesthetic presentation management
  • Artifact model for widget-like implementation
  • UcompOS Application run-time
  • Event Dispatchment architecture

The classes UcompOSArtifactProxy and UcompOSWindowProxy each have Boolean sandbox parameters.  Also, the root <application/> element in an application manifest has a sandbox attribute which accepts values of true or false.

The default condition if you don’t set the sandbox parameter is true.

From an implementation point of view, all SWFLoader instances attached to the UcompOS Portal have the trustContent set to true.  This may be something I rethink when moving the UcompOS RPF project to Beta but at least in my main UcompOS RPF application I am building, the domain that I serve the UcompOS Portal from will be the exclusive thing I serve from that domain as I am interested in creating the a strong degree of disaggregation. (Of course you should have a solid understanding of policy files (such as crossdomain.xml)).

In the case where the sandbox property is set to true (the default condition), the SWFLoader‘s loadForCompatibility property is also set to true.

This creates a situation where the loaded SWF application is loaded into a sibling ApplicationDomain relative to the UcompOS Portal SWF application.

The loadForCompatibility property addresses the need for a SWF to be able to load child SWFs created with different versions of Flex.

For instance, if you tried to load a Flex 3 UcompOS application or sub-application into the UcompOS Portal with its sandbox set to false, you’ll get run-time errors.

So then when or why would you want to load a UcompOS SWF application or sub-application with its sandbox property set to false?

Primarily only in instances when you wanted to implement drag and drop functionality across the boundaries of a UcompOS sub-application.

If all the drag and drop functionality is within the boundaries of the SWF, then the sandbox setting is irrelevant.

However, suppose you have two UcompOS SWF sub-applications loaded into UcompOS Window instances and you want to enable items to be dragged and dropped back and forth between them.  This would require you to set the sandbox property to false.  Also, this would require you to build your applications with Flex 4 (although I admittedly have yet to try implementing drag and drop across two different non-sandboxed Flash CS5-created applications).

In an upcoming tutorial, I’ll show a demo of building a UcompOS-based file management system like the one I have built for Educator 2 that enables drag and drop between multiple UcompOS Window instances as well as drag and drop from a UcompOS Window instance to a UcompOS Artifact instance.

The key fact to ascertain here is that strong command of the UcompOS SDK and how it is utilized to send information back and forth between entities in the UcompOS Continuum is compulsory to your developing the most powerful and effective Rich Experiences.

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.

A Simple HTML Digital Camera Browser

In this tutorial, we will look at a variety of core UcompOS Rich Productivity Framework concepts, and in particular we will explore the mechanics of adding a desktop component to your UcompOS Rich Portal Application.

It is recommended you download the source of the application we’ll build in this tutorial at the link below so you can follow along and there is also a video demonstration of the application we are going to build in this tutorial.

Download the Simple HTML Digital Camera Browser Source Code

This tutorial assumes you have at least a basic working knowledge of:

  • Adobe AIR 2.0
  • Adobe Flash Builder
  • ActionScript 3.0
  • HTML
  • JavaScript
  • You should have read my blog posts or watched my video tutorials about UcompOS Proxy Components and Services Dictionaries

The goals for our application are as follows:

We want to build a simple digital camera browser that lets the user browse through and view images from their digital camera in a Rich Portal Application implementation.

We are going to keep the application as deliberately simple as possible and we are not going to address its cosmetics or aesthetics so that we can focus on providing instruction on specific UcompOS concepts and principles.

To further define the specifications for our application, we want to build a UcompOS Application that prompts the user to connect their digital camera to their computer.  We want our application to be able to know when their digital camera has been connected.  Then when the digital camera has been connected, we want to display the contents of their camera to them.  The user should be able to easily browse through their camera’s contents and they should be able to click on a file on the camera to view it.  Also, the file should be opened in the native photo-viewing application on their computer versus simply displayed in the browser.

Again, we are going to focus on a very simple implementation and will not focus on aesthetics or presentation so that we can focus more on the core UcompOS mechanics we are leveraging to build our application.

Our UcompOS application is comprised of the following components:

  • An AIR 2.0 UcompOS Application built with Adobe Flash Builder 4
  • An HTML UcompOS Sub Application

We’ll walk through the process of setting up and building the different pieces of the application fairly linearly and then tie it all together at the end with a screenshot of our application.

Implementation Details

The way I want to design our program, I want a UcompOS Application to load on the UcompOS Application Dock entitled “My Camera”.  When this application is opened, we want it to launch our UcompOS AIR 2.0 application.  I want that application to prompt the user to connect their digital camera.

When the user connects their digital camera, I want to instantly launch a UcompOS Window instance in the UcompOS Portal that displays the contents of the camera to the end user and allows them to browse through any folder structures housed on the camera and then I want to allow them to select a file to be viewed in their default photo viewing application on their computer.

When the camera is disconnected, I want to shut down the application.

Setting up the AIR 2.0 Application

While I could use a number of different technologies to build our AIR application, I am going to use Adobe Flash Builder 4.   The minimum required version for a UcompOS AIR application is AIR 2.0.  You can learn more about AIR 2.0 and access its run-time and SDK at http://labs.adobe.com/technologies/air2/.

The first step is to set up a Flash Builder project for my AIR application.

My project is called Camera_Example.  Pictured at left is the fully expanded project in Flash Builder with all its files. flash_builder_project

Our main class in our AIR application is Camera_Example.mxml.

Notice in my libs folder is the file UcompOSAIRSDK.swc.  This is the UcompOS SDK file for AIR applications.  This file is found in the UcompOS Developers Package in the sdk/air folder that is created when you unzip the UcompOSSDK.zip file contained in the package.

Simply drag and drop that file into the libs folder of any Flash Builder (or Flex) based UcompOS AIR application.

You can also incorporate the UcompOS AIR SDK into Flash-based and HTML-based AIR applications (the SDK has no Flex dependencies) but the techniques for doing so are outside the scope of this tutorial.

Ideally, my goal is for the end user to not even have any knowledge that an AIR application is involved other than the initial install process.  I want the user to operate entirely within the web browser here and my rationale for this in this tutorial is with the goal in mind of showing how multiple technologies are fusing together to create a seamless rich experience.

Of course, AIR needs to be involved because AIR is what we use to do most of the heavy lifting in our application including detecting the camera attachment/detachment, browsing through the camera’s contents, and opening individual pictures on the desktop.

From an implementation point of view, an AIR application can only be launched from the web browser following a user-initiated event such as a mouse click.

When an AIR application is configured as the base source code for a UcompOS Application, and this application appears on the UcompOS Application Dock, when the user clicks the icon in the application dock, that user event is what triggers the launching of the AIR application.

I’ll add that it is possible to implement UcompOS AIR sub-applications and the best practice for doing this is to leverage the UcompOSArtifactProxy class.  This topic will be covered in a future tutorial in the near future.

Our AIR Application’s Descriptor File

Our Camera_Example-app.xml file needs a very crucial adjustment.

By default, you’ll see this XML element commented out:

<!-- <allowBrowserInvocation></allowBrowserInvocation> -->

This needs to be uncommented and issued a true value:

<allowBrowserInvocation>true</allowBrowserInvocation>

This tells the AIR runtime that your application is allowed to be launched from the web browser.

If you try to instantiate the UcompOS AIR SDK in an AIR application that does not have its descriptor set up in this manner, you’ll get a compile-time error and you won’t be able to package your application.

cameraEven though we do want our AIR application to be as innocuous as possible, if a user does stumble upon it on their main OS’ dock or in the folder on their computer where it’s been installed, I want them to see the custom icon at left and this icon and other varieties in different sizes are in the assets_embed/png folder.

Therefore in my app-descriptor file, I have implemented the following:

<icon>
 <image16x16>assets_embed/png/image16x16.png</image16x16>
 <image32x32>assets_embed/png/image32x32.png</image32x32>
 <image48x48>assets_embed/png/image48x48.png</image48x48>
 <image128x128>assets_embed/png/image128x128.png</image128x128>
 </icon>

AIR Application Code

Since I want the user to know as little as possible, if anything, about the presence of the AIR application, I want it to be invisible.  Therefore, I’ll give the visible property in the root WindowedApplication tag a value of false.  This will suppress any windows from being displayed.

Next, I want to instantiate the UcompOS SDK.

This should happen once the main application dispatches its applicationComplete event.

My root MXML tag looks like this:

<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
   xmlns:s="library://ns.adobe.com/flex/spark"
   xmlns:mx="library://ns.adobe.com/flex/halo"
   applicationComplete="start();"
 visible="false">

Now let’s take a look at the private variables I am declaring in my main class.  We’ll cover the purpose of each of these variables further in the tutorial:

private static var _cameraRoot:String;
private var _h:UcompOSHTMLProxy;
private var _d:UcompOSDockProxy;

Now let’s take a look at my start(); method:

private function start():void
{
 AIRSDKClient.getInstance(this,new ServicesDictionary());
 AIRSDKClient.getInstance().addEventListener(SDKClient.SDK_READY,ucompos_init);
 implementStorageVolumeListeners();
}

The instantiation of the UcompOS AIR SDK is very similar to the instantiation of the UcompOS Flex/Flash SDK that targets browser-based content with a few key exceptions:

  • The Singleton class AIRSDKClient is leveraged versus the SDKClient class
  • We pass this as the first parameter to the getInstance(); method and an optional Services Dictionary as the second parameter.  We’ll look at the Services Dictionary for this application below.
  • Internal to the AIRSDKClient class, the SDKClient class is instantiated.  Once it is instantiated, it dispatches an Event of type SDKClient.SDK_READY and only then can you safely instantiate and use any of the Proxy Components built into the SDK so you must listen for this event and implement any Proxy Component-related startup code in the event handler for this event

In our start(); method, we have a call to implementStorageVolumeListeners();

Let’s take a look at the implementStorageVolumeListeners(); method:

private function implementStorageVolumeListeners():void
{
 StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_MOUNT,mountHandler);
 StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_UNMOUNT,unmountHandler);
}

This method leverages AIR 2.0 capabilities.  StorageVolumeInfo is a Singleton class in AIR 2.0 that can have an event listener attached to it to handle StorageVolumeChangeEvent.STORAGE_VOLUME_MOUNT and StorageVolumeChangeEvent.STORAGE_VOLUME_UNMOUNT events.  These events are dispatched whenever a new mount point is introduced to the base Operating System or whenever a mount point is removed.  Our handlers for these events are mountHandler(); and unmountHandler(); respectively.

Before we take a look at mountHandler(); and unmountHandler();, let’s take a look at the ucompos_init(); method that is invoked once our UcompOS AIR SDK has been fully initialized and we are ready to interact with it fully:

private function ucompos_init(event:Event):void
 {
  _h = new UcompOSHTMLProxy();
  _h.alert("Please connect your digital camera to your computer");
  _d = UcompOSDockProxy.getInstance();
 }

In this method, we are creating an instance of UcompOSHTMLProxy.  This class has a number of methods that let us execute common JavaScript methods such as alert();, prompt();, and confirm(); in the UcompOS Portal’s HTML wrapper file.

I am choosing to use a regular JavaScript alert to prompt the user to connect their digital camera to their computer.

I am also going to create a reference to the UcompOSDockProxy Singleton and my reasons for doing this will become clear below.

Now, let’s take a look at the mountHandler(); method.

private function mountHandler(event:StorageVolumeChangeEvent):void
{
 _d.setAlert(true);
 _cameraRoot = event.rootDirectory.nativePath;
 w = new UcompOSWindowProxy();
 w.add("http://desktop.ucompass.com/Camera_Example/Camera_Browser.html",event.rootDirectory.name,400,400);
 var object:Object = API.getFiles({});
 }

This method is invoked when the user attaches a new storage volume to their computer.  It is worth mentioning at this time that the simple example being developed here could be used to browse any type of removable storage.  We just happen to be focusing on a scenario that would involve a digital camera.

The implementation details of mountHandler(); are straightforward.  First, we want to call the setAlert(); method of the UcompOSDockProxy instance and pass a value of true to it.  This makes the icon associated with this application on the UcompOS Portal Application Dock “Chirp” and glow drawing the user’s attention to it.

Then, we want to set the _cameraRoot property to event.rootDirectory.nativePath.  The StorageVolumeChangeEvent contains a rootDirectory property which is of type File and represents the file location on the file system where the base of the mount point is located.

Next we create an instance of UcompOSWindowProxy of 400 x 400 and load our HTML sub-application into it.  Our HTML sub-application will be the actual camera browser that the end user interacts with and we’ll review that later.

Our unmountHandler(); method is extremely simple:

private function unmountHandler(event:StorageVolumeChangeEvent):void
{
 w.close();
 UcompOSGlobalManagerProxy.getInstance().quitApplication();
}

This calls the close(); method on our UcompOSWindowProxy instance and then quits out of the application once the camera is removed.

Way back when we instantiated the UcompOS AIR SDK, we passed a new instance of ServicesDictionary to the instantiation method.

There are two public API methods we need our AIR application to sponsor and we are calling them Camera.getFiles and Camera.openFile.

Camera.getFiles will take the path to a given folder on the file system and return a list of the contents of that folder.

Camera.openFile will take the path to a given file on the file system and open it up with the application on the computer that the file is associated with.

First, let’s take a look at our ServicesDictionary:

package cameraexample
{
  import com.ucompass.ucompos.sdk.server.AbstractServicesDictionary;
  public class ServicesDictionary extends AbstractServicesDictionary
  {
    public function ServicesDictionary()
    {
      _map =
      {
        'Camera.getFiles':
        {
          static:true,
          classRef:API,
          method:'getFiles',
          description:'Lists files in a folder'
        },
 
        'Camera.openFile':
        {
          static:true,
          classRef:API,
          method:'openFile',
          description:'Opens a file in its native application'
        }
      }
    }
  }
}

As you can see, both of our public API methods are housed as static methods in an API class.

Here is the method that corresponds to the Camera.getFiles public API method:

public static function getFiles(data:Object):Object
{
  var folder:String = data.folder;
  if(!folder)
  {
    folder = Camera_Example.cameraRoot;
  }
 
  var file:File = new File(folder);
  var files:Array = [];
 
  for(var i:uint = 0;i<file.getDirectoryListing().length;i++)
  {
    var _file:File = file.getDirectoryListing()[i] as File;
    files.push({name:_file.name,isDirectory:_file.isDirectory});
  }
 
  return {eventType:"files",files:files,folder:folder};
 
}

The Camera.getFiles public API method expects a folder property to be on the Object parameter passed to the method.  If it’s not, it retrieves the contents at the base of the camera.

Back in our base application, we have a static getter function that retrieves the value of cameraRoot (which is why we established the value of _cameraRoot in the mountHandler(); method).

Our method simply builds an Array of Objects each having a name property and a Boolean to indicate if the item is a directory.

In our return Object, we return the eventType property set to files as well as our Array of files and a reference to the folder whose contents were retrieved.  We’ll learn more about the purpose of this eventType property when we look at our HTML sub-application.

Our public API method Camera.openFile is extremely simple:

public static function openFile(data:Object):Object
{
 var file:File = new File(data.file);
 file.openWithDefaultApplication();
 return {};
}

That’s it for our AIR application.  We are ready to package it with adt or the compiler built into Flash Builder.

I am packaging it into a file named Camera_Example.air and it will be reachable at a network URL of http://desktop.ucompass.com/Camera_Example/Camera_Example.air

Our HTML Sub-Application

Now we are ready to build our HTML sub-application which will be the interface the end-user actually interacts with.

The URL of our application will be at http://desktop.ucompass.com/Camera_Example/Camera_Browser.html.  This is the URL passed to the add(); method of our UcompOSWindowProxy instance of our mountHandler(); method in our AIR application.

We want this application to be extremely simple.

We just want it to list out the contents of our digital camera and present them as files or folders.

When the user clicks on a folder resource, we want to display the items in that folder.  When they click on a file resource, we want to open that file in the application that the file is associated with on their computer.

From an implementation point of view, when we click a folder, we are going to call our AIR application’s public API method Camera.getFiles and when we click a file we are going to call Camera.openFile.

The first thing we are going to do in our HTML sub-application is implement the UcompOS JavaScript SDK:

<script type="text/javascript" src="/UcompOSSDK.js"></script>

While it is not a requirement, best practice recommends you place the UcompOS JavaScript SDK and SWF files in the root directory of your webserver.

Here are two variables we initialize:

var camera;
var d;

When the UcompOS JavaScript SDK has initialized, it looks for a start(); method in the application its implemented into.

Our start(); method is as follows:

function start()
 {
   d = new UcompOSDockProxy();
   camera = new Camera();
   camera.addEventListener("files",filesHandler);
   camera.getFiles();
 }

We are creating an instance of UcompOSDockProxy which we’ll use to suspend the Dock alert we set in our AIR application.

More importantly, we are creating an instance of Camera, and adding an event listener to it and calling its getFiles(); method.

Camera is a Proxy Component we have built in our HTML sub-application.  A Proxy Component is an interface to the public API methods located in other entities.

In our case, the Proxy Component Camera in our sub-application is the interface to the Camera.getFiles and Camera.openFile public API methods sponsored by our AIR application.

Let’s take a look at our Proxy Component Camera and walk through it as the mechanics of Proxy Components are very important to understand:

function Camera()
{
  this.setDestination(parentConnectionId);
  this.getFiles = function(folder)
  {
    this.call("Camera.getFiles",{folder:folder});
  }
 
  this.openFile = function(file)
  {
    this.call("Camera.openFile",{file:file});
  }
}
 
Camera.prototype = new AbstractProxyComponent();
Camera.prototype.constructor = Camera;

The last two lines of the class would be analogous to saying Camera extends AbstractProxyComponent in ActionScript 3.0.  Any Proxy Component must extend AbstractProxyComponent (in ActionScript as well as JavaScript).

In our class implementation, we pass the parentConnectionId property to the setDestination method of our class (which is a method inherited from AbstractProxyComponent).

Since our sub-application was launched by our AIR application, in the context of the UcompOS Continuum, we know that our AIR application is the parent of the sub-application in scope and we can safely use the UcompOS JavaScript SDK global variable parentConnectionId (this is analogous to the public property SDKModel.getInstance().parent in the UcompOS AIR/Flash/Flex SDK).

Our Camera class also implements two methods: getFiles(); and openFile();.  As you can see by referring to the class code, both of these call the public API methods in our AIR application Camera.getFiles and Camera.openFile by using the call(); method in our class that is inherited from AbstractProxyComponent.

Another very important point, in our start(); method, refer again to this command:

camera.addEventListener("files",filesHandler);

This tells our instance of our Camera class to pass any SDKEvent’s of type “files” to the method filesHandler.

If you refer to our AIR application public API method Camera.getFiles, you’ll recall its return Object sets an eventType property to “files“.

The return Object of the public API method Camera.getFiles is passed to our filesHandler(); method.

Here is the code of our filesHandler(); method:

function filesHandler(data)
{
  var e = document.getElementById('files');
  e.innerHTML = '<p><a href="javascript:void(0);" onclick="getFiles();">Camera Root</a><p/><hr/><p/><u>Current folder: '+data.folder+'</u>';
  for(var i = 0;i<data.files.length;i++)
  {
    if(data.files[i].isDirectory)
    {
      e.innerHTML+='<p/><img src="icons/folder.gif"/> <a href="javascript:void(0);" onclick="getFiles(\''+data.folder+'/'+data.files[i].name+'\');">'+data.files[i].name+'</a>';
    }
    else
    {
      e.innerHTML+='<p/><img src="icons/file.gif"/> <a href="javascript:void(0);" onclick="openFile(\''+data.folder+'/'+data.files[i].name+'\');">'+data.files[i].name+'</a>';
    }
  }
}

Notice we are referencing the files and folder properties of the Object passed to filesHandler();.  We iterate on the files property which we know from our inspection of our AIR application’s public API method Camera.getFiles is an Array and we further know that each Object in this Array has a name:String and isDirectory:Boolean property.

We create simple HTML that displays the name of the files and folders with the appropriate icons and calls the methods getFiles(); for folders and openFile(); for files.

These methods appear below:

function getFiles(folder)
{
 d.setAlert(false);
 camera.getFiles(folder);
}
 
function openFile(file)
{
 camera.openFile(file);
}

In getFiles(); as well as openFile();, notice we are calling the setAlert(); method of the UcompOSDockProxy and passing it a value of false.  This is to cancel the Dock alert we set on the UcompOS Portal’s Application Dock that we set in the AIR application the first time the user clicks on a resource.

That’s all there is to our HTML sub-application.

Configuring Everything as a UcompOS Application

Now we need to set up our application manifest for our simple Digital Camera browser application.

This should be very straightforward if you’ve reviewed some of my other UcompOS tutorials but for AIR applications, there are some special configurations you need to make:

<application>
  <source>
    <base>http://desktop.ucompass.com/Camera_Example/Camera_Example.air</base>
    <params>
      <param>
        <name>appId</name>
        <value>Camera-Example</value>
      </param>
      <param>
        <name>publisherId</name>
        <value>0E5CA255707A7E3F70F12D38B16B8D2A4C17413C.1</value>
      </param>
    </params>
  </source>
  <titles>
    <title locale="en_US" default="true">My Camera</title>
  </titles>
  <icons>
    <icon locale="en_US" default="true">http://desktop.ucompass.com/Camera_Example/icons/camera.png</icon>
  </icons>
</application>

Notice the appId and publisherId parameters you must include in the <params/> element of the manifest.

IMPORTANT: At the time I am authoring this tutorial, the evening of December 27, 2009, the publisherId field faces an uncertain future in AIR 2.0 and may be deprecated.  At present, you can find your publisherId by looking in the $APP/Contents/Resources/META-INF/AIR/publisherid file in the application installation directory for your installed application.  The appId and publisherId parameters must be included otherwise, the UcompOS Portal will not be able to successfully launch your UcompOS AIR application.  Any changes to the AIR 2.0 implementation specifics for publisherId will be blogged about here and updates will immediately be made to the UcompOS RPF accordingly.

Next we’ll take a very quick peak at my Dock Manifest:

<applications>
  <application>
    http://desktop.ucompass.com/Camera_Example/manifest.xml
  </application>
</applications>

In this case, I obviously just have a single application I am loading into my UcompOS Portal implementation that is our simple Digital Camera browser example.

Screenshot of the Application

demo

Conclusion

In this tutorial, we created a deliberately simple application to demonstrate a number of core UcompOS RPF concepts and principles – particularly integrating the desktop into a UcompOS Rich Portal Application 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.

A UcompOS Entity’s UUID

In my last two blog postings, I described Services Dictionaries and Proxy Components which together describe the implementation model of two disparate UcompOS RPF entities engaging in asynchronous communication with each other.  A Proxy Component is a client interface to the functionality in another entity exposed in that entity’s Services Dictionary.

As I described in my blog postings about UcompOS HTML Applications and UcompOS AIR 2.0 Applications, the Flash Player’s LocalConnection infrastructure is the basis of the medium used in the UcompOS Continuum for messages to pass from one entity to another while the AIR 2.0 ServerSocket class is the basis for inbound messages received by a UcompOS AIR 2.0 Application.

Each entity in the UcompOS Continuum that is capable of participating in transactions with other entities will have the UcompOS SDK implemented.

The UcompOS SDK has a Singleton class called SDKModel which has a public connectionId property.

This connectionId is a UUID (Universally Unique Identifier) in the context of the UcompOS Continuum.

Connection Ids are hierarchically structured, so by looking at the connectionId property of one entity, you can decipher the connectionIds of all the ancestors of that entity up to the root entity which is the UcompOS Portal.

Each time an entity launches another entity as  a UcompOS Application, UcompOS Window, UcompOS Artifact, or UcompOS Browser Window, that launched entity is given its connectionId by the launching entity and the mechanics of creating the connectionId is handled seamlessly by the UcompOS SDK.

Suppose the UcompOS Portal had a connectionId of A, then it launched an application.  This application may have a connectionId of A/B. Then suppose that application launched a sub-application in a UcompOS Window.  That sub-application may have a connectionId of A/B/C.  Now suppose that sub-application launched a sub-application in a UcompOS Artifact.  That sub-application may have a connectionId of A/B/C/D.  And so on….

In the SDKModel class, there is also a public property parent that is the connectionId of the entity that launched the entity in scope.

In addition, there is a root property which would be the connectionId of the root entity in the UcompOS Continuum which is the UcompOS Portal.

From an implementation details point of view, the connectionId is used by an entity as the connectionName property passed to the connect method of the LocalConnection instance that the entity uses to send and receive messages from other UcompOS entities.

The SDKClient Singleton class in the SDK has a public send(); method which handles the task of dispatching a DataPackage instance (also a class in the SDK) to a target entity via a LocalConnection target connectionId.

What we’ll learn soon when I start blogging about the UcompOSAIRProxy class is that UcompOS AIR applications have a string appended to their connectionId in the form of:

socket-host-validation port-operation port

For instance this may be a simplified example of a UcompOS AIR application’s connectionId:

A/B/C/D-socket-127-0-0-1-1024-1025

I’ll talk about the semantics of this in the near future and shed more light on the implementation details of an AIR 2.0 UcompOS entity.

The hyphens are used in the host address as periods are not permissible characters in the connectionName parameter passed to a LocalConnection instance’s connect method.

When the SDKClient‘s send(); method encounters the string “socket” followed by the host, validation port, and operation port in the syntax shown here, instead of sending the DataPackage to the AIR UcompOS entity via LocalConnection, it establishes a socket connection to the server socket endpoint broadcasting in the AIR application and sends the DataPackage over a socket connection.

Understanding the concept of the connectionId of a UcompOS entity is an important part of understanding how to build Proxy Components.

For instance, if you were to check the SDK source out of the UcompOS Project SDK SVN Repository, and inspect the code in the com.ucompass.ucompos.sdk.proxycomponents package, these are the Proxy Components built into the SDK that are client apparatus’ to the public API methods sponsored by the UcompOS Portal.

What you would see in the constructor for each of these Proxy Components is the following:

super._destination = _sdkModel.root;

All Proxy Components must extend the SDK abstract class AbstractProxyComponent which has a protected property _destination.

This _destination property indicates the UUID of the entity that contains the functionality being targeted by the Proxy Component.

This property can be set on the fly dynamically but in the case of the Proxy Components built into the SDK, they all target the UcompOS Portal so the _destination in these Proxy Components is always the connectionId of the root entity in the UcompOS Continuum – i.e. the UcompOS Portal.  The connectionId of the root entity in the UcompOS Continuum is always found on the public property root on the SDKModel Singleton in the SDK.

When you build your own Proxy Components, you’ll need a strategy that sets the _destination property either at the time of instantiation of the Proxy Component, or dynamically as it is possible for a single Proxy Component class to target numerous different entities simultaneously.