New Proxy Component in UcompOS SDK: UcompOSAlertProxy

This morning, I have just added a new Proxy Component to the UcompOS SDK: UcompOSAlertProxy that is available in version 0.2.2 and later of the UcompOS Developers Package.

UcompOSAlertProxy provides a way to create a modal dialogue on the UcompOS Portal via an implementation of the Flex Alert control.

Previously, I had made this possible with the createAlert(); method of the SDK class UcompOSGlobalManagerProxy.

The inefficiency with this is that UcompOSGlobalManagerProxy is a Singleton class (along with UcompOSDockProxy, UcompOSMenuBarProxy, and UcompOSStyleProxy).  So one instance of UcompOSGlobalManagerProxy would handle the event dispatching for all Alert dialogues created with its createAlert(); method.

So handling events dispatched by Alerts created with UcompOSGlobalManagerProxy‘s createAlert(); method required extra handling and actually provided risks of gaps in data integrity and continuity.

I have removed the createAlert(); from UcompOSGlobalManagerProxy and replaced the functionality with the simpleAlert(); and confirmAlert(); methods of the UcompOSAlertProxy class.

The simpleAlert(); method launches a simple Alert with a single control button that will default with a label of “OK”.

The signature of simpleAlert(); is as follows:

public function simpleAlert(title:String, message:String, okLabel:String="OK"):void

You have the ability to customize the label on the single button presented on the Alert control.

The signature of confirm(); is as follows:

public function confirm(title:String, message:String, okLabel:String = null,
cancelLabel:String = null, defaultButton:String="OK"):void

You can specify the labels to be used on both the OK and Cancal buttons and you can articulate which should be the default button.

When the user takes action and clicks a button on the Alert dialogue, an instance of SDKEvent is dispatched by the UcompOSAlertProxy instance of type UcompOSAlertProxy.ALERT_SUBMIT.

The SDKEvent instance’s data property will have a detail property of type String which will have a value of UcompOSAlertProxy.OK or UcompOSAlertProxy.CANCEL.

Let’s look at a very simple example with the aid of some code:

private function fileExists(file:String):void
{
 var a:UcompOSAlertProxy = new UcompOSAlertProxy();
 a.data = file;
 a.addEventListener(UcompOSAlertProxy.ALERT_SUBMIT,fileExists_handler);
 a.confirm("A file named "+file+" exists in the target location. 
 Do you wish to overwrite it?","Yes","No",UcompOSAlertProxy.CANCEL);
}
 
private function fileExists_handler(event:SDKEvent):void
{
 var a:UcompOSAlertProxy = event.proxyComponent as UcompOSAlertProxy;
 if(event.data.detail==UcompOSAlertProxy.OK)
 {
 trace("Overwrite file "+a.data);
 }
 
}

Building Full Screen Mode UcompOS Implementations

Since the release of Adobe Flash Player 9 in 2006, the Flash Player is capable of entering into what is known as “Full Screen Mode“.

In Full Screen Mode, the content playing in the Flash Player takes over the entire viewport of the display device such that the only content in view and capable of being interacted with is the content currently being executed in the Flash Player.

Depending on the nature of your application, this can in some circumstances create a much more focused and positive experience for your users.

The UcompOS Portal is configured to operate in Full Screen Mode and the UcompOS SDK provides a means for sending the UcompOS Portal into Full Screen Mode from one of your UcompOS applications or sub-applications.

Of course there are some rules and principles to observe when leveraging the power of Full Screen Mode in your UcompOS Applications.

In my blog posting on the Mechanics of UcompOS Desktop (AIR 2.0) Applications, we learned that the launching of an AIR application by the Flash Player must be preceded by a user-triggered mouse event.

The same rule applies to entering into Full Screen Mode.

The UcompOSGlobalManagerProxy class has two pertinent methods:  enterFullScreenMode(); and exitFullScreenMode();.

Both of these methods accept an optional single input parameter, message, of type String.

When you call either of these methods from one of your UcompOS applications or sub-applications, in order to generate the compulsory user mouse click, the UcompOS Portal throws up an Alert dialogue asking the user if they want to allow the request to go into or out of full screen mode.

Of course having the dialogue appear for exitFullScreenMode(); calls is somewhat dubious as all the user needs to do is hit the Escape key on their computer to break out of Full Screen Mode but for continuity, I have decided to keep the mechanics of throwing the Alert in calls to both enterFullScreenMode(); and exitFullScreenMode();.

The optional message parameter lets you customize the text that is presented on the Alert dialogue.

When the UcompOS Portal breaks into or out of Full Screen Mode, a Continuum Event (an instance of the SDKEvent class) of type UcompOSGlobalManagerProxy.SCREEN_MODE_CHANGE is broadcast.

The data Object of the event will have a state property with a literal string value of “normal” or “fullScreen” so that your applications and sub-applications can behave accordingly when the user enters/exits Full Screen Mode.

In the scenario we discussed in my AIR 2.0 UcompOS Applications posting mentioned above, we saw we can leverage the UcompOSArtifactProxy class to create a clickable UcompOS Artifact that immediately launches a particular AIR application (with the aid of the UcompOSAIRProxy class).

This same concept is also available with Full Screen Mode implementations.  You can create a UcompOS Artifact and assign its data Object special properties that tell the UcompOS Portal to launch or exit Full Screen Mode when the artifact is clicked on.

The property names will be enterFullScreenMode and exitFullScreenMode and both should be of type Boolean with a value of  true.

They should be mutually exclusive and you should not have the enterFullScreenMode and exitFullScreenMode properties set on the artifact’s data Object simultaneously.  If you do, the exitFullScreenMode property takes precedent.

Let’s look at a simple code-driven example:

private var artifact:UcompOSArtifactProxy;
 
private function start():void
{
 
 SDKClient.getInstance(this);
 UcompOSGlobalManagerProxy.getInstance().addEventListener
(UcompOSGlobalManagerProxy.SCREEN_MODE_CHANGE,screenModeChangeHandler);
 artifact = new UcompOSArtifactProxy();
 artifact.add(null,null,"http://www.server.com/enterFullScreenModeImage.png");
 artifact.data = {enterFullScreenMode:true};
 
}
 
private function screenModeChangeHandler(event:SDKEvent):void
{
 
 switch(event.data.state)
 {
 
 case "fullScreen":
 artifact.data = {exitFullScreenMode:true};
 artifact.setImage(null,"http://www.server.com/exitFullScreenModeImage.png");
 break;
 case "normal":
 artifact.data = {enterFullScreenMode:true};
 artifact.setImage(null,"http://www.server.com/enterFullScreenModeImage.png");
 
 }
 
}

An important point to make about Full Screen Mode implementations, at this time, UcompOS HTML content cannot be displayed while in full-screen mode.  UcompOS HTML applications and sub-applications rely on an iframe implementation which is outside the visual scope of the Flash Player.

UcompOS HTML entities can still be interacted with via Proxy Components while in Full Screen Mode however.

The same applies to UcompOS AIR 2.0 content.  It cannot be in view while the in Full Screen Mode but it can be interacted with by Proxy Component-driven interactions.

Building Drag and Drop Experiences in the UcompOS RPF

The UcompOS RPF couldn’t rightfully be called a “Rich Productivity Framework” if it didn’t have a model to support drag and drop interactivity.  Drag and Drop behavior could perhaps be considered one of the key characteristics of an application that helped to define the term “Rich Internet Application” in the early 2000s.

This discussion doesn’t focus on building drag and drop interactivity within a single UcompOS application.  Obviously, you can implement whatever sort of drag and drop interactivity within a singular UcompOS HTML, Flash, Flex, or AIR application without restriction or consideration of UcompOS mechanics.

The real power in a UcompOS Rich Portal Application is in implementing inter-application drag and drop interactivity.

Dragging names from an address book application to an e-mail application, dragging images from a file manager to a text editor, highlighting multiple resources and dragging them to a widget to perform some operation on the items simultaneously – these are some of the experiences that can be created.

The mechanics of drag and drop UcompOS implementations are worthy of discussion.  There are some important considerations that need to be made in order for the UcompOS Portal to enable your applications to be configured appropriately for inter-application dragging and dropping.

Sandboxing in the UcompOS RPF

The philosophy of the UcompOS RPF is to achieve the highest degree of sandboxing possible while still achieving our interaction objectives.

Our sandboxing is less for security purposes and more to create an isolated, self-contained environment for a UcompOS entity that is free from unintentional disruption by other UcompOS entities.

Communication between applications in the UcompOS RPF should exclusively occur using the classes built into the SDK.

In no way should you plan to, or should you need to, attempt to directly access classes, properties, or methods of other UcompOS entities within an individual UcompOS entity. You should exclusively rely on the powerful implementation of a UcompOS entity’s public API methods, Services Dictionary, and Proxy Components.

The one exception to this is the implementation of dragging and dropping across two different UcompOS entities.  But the UcompOS Portal handles all the logic for you so that you don’t need to worry about anything other than what should be dragged and what should be allowed to be a drop target and how it should behave when receiving a drop.

The topic of sandboxing in the Flash Player and loading SWF content into other SWF content is a necessarily thorough and rigorous conversation.

In the UcompOS RPF, any SWF content – be it a UcompOS application or sub-application – is loaded into the UcompOS Portal with an implementation of the SWFLoader class.

The SWFLoader has some very important properties that essentially articulate the permissions the child SWF content has in terms of accessing information (classes, properties, methods) of the parent SWF content it was loaded into.

One of the chief goals of the UcompOS RPF is complete disaggregation.  The framework wants you to be able to place resources at any network address without consequence.

Therefore, all SWF content is loaded into the UcompOS Portal with the trustContent property set with a true value.

There are three different ways SWF content is loaded into the UcompOS Portal as listed below:

  • SWF-based UcompOS application loaded invisibly into the UcompOS run-time
  • SWF-based sub-application loaded into a UcompOS Window
  • SWF-based sub-application loaded into a UcompOS Artifact

When you load SWF content into the UcompOS Portal, you can articulate how tightly it is to be sandboxed.

As far as SWF-based UcompOS applications loading invisibly into the UcompOS run-time, you can set a sandbox=”true” or sandbox=”false” attribute to the root tag in that application’s manifest file.  The default condition is sandbox=”true”.

Also, if you look at the signatures of the add(); methods of both UcompOSWindowProxy and UcompOSArtifactProxy, you’ll see they both have sandbox parameters that default to a true value.

By default, a SWF loaded into a UcompOS Window or UcompOS Artifact will take on the sandbox configuration of its root UcompOS Application.

From an implementation point of view, the only difference between the two configurations is SWF content loaded with the sandbox=”true” configuration has the following property set to the SWFLoader used to load the content:

swfLoader.loadForCompatibility = true;

According to the Adobe’s ActionScript 3 documentation:

“Set this property to
true

to indicate that the loaded application might be compiled with a different version of the Flex framework and you want your application to be able to interact with it. Setting the value of the
loadForCompatibility

property to
true

also causes the LoaderContext of the Loader to load the sub-application into a sibling application domain of the main application, rather than a child application domain.”

A full discussion of the LoaderContext and ApplicationDomain classes is outside the scope of this blog posting, but essentially, setting the loadForCompatibility property to true is a form of sandboxing in that you are able to load Flex content created with a different version of the SDK than the parent SWF content.

Unless you have very specific reasons, in most all cases you’ll leave the sandbox property in its default configuration (sandbox=true).

Our plan is that we will always keep the UcompOS Portal running on the latest public release of Flex 4 so leaving sandbox=true will insure you won’t have to continue to update your Flex-based UcompOS content.

Scenarios for when you would want to set sandbox=false are complex and sophisticated and will be covered in an upcoming posting.

The Marshall Plan

The implications laid out above are somewhat important to elaborate upon.

We want to be able to load SWF content created with any version of the Flex SDK into the UcompOS Portal, and then we still want to be able to enable it to participate in drag and drop interactivity with other SWF content, that may have been produced with still other versions of the Flex SDK.

How is this possible?  After all, classes such as the DragManager are involved and certainly it seems we’ll run into compatibility issues.

The answer is taking advantage of a concept the people at Adobe have created that they call the Marshall Plan.  I recommend you explore this important topic.  It deals with how data is marshalled across the boundaries between two different SWFs.

As of the Beta 2 release of Flex 4, the classes that enable this marshalling to automatically occur are no longer automatically compiled into the SWF.  You have to explicitly add them at compilation time.

This must be added as an argument to the Flex compiler for your application:

-includes=mx.managers.systemClasses.MarshallingSupport

Failure to add this to a Flex 4 Beta 2 UcompOS application that is set up for dragging and dropping will yield unpredictable results, and even run-time errors.

Building a Simple Drag and Drop Example

If you have two different UcompOS entities – one the drag source, the other the drag destination – you would set each of them up as if they were both in the same overall application.

You’d set up the drag source to specify the behavior of the drag initiation, and your drag destination to implement your desired behavior of when items are dragged and dropped onto the target.

There is another scenario however and it involves dragging and dropping to a UcompOS Artifact.

In our example, we want to build a very simple example that shows a UcompOS Flex application that employs a DataGrid.  We then want to implement an artifact and enable the user to drag and drop an item from the DataGrid to the artifact.

When the item is dropped, we want to throw a simple HTML alert that outputs some information about the item that was just dropped.

Here are the three resources used to accomplish this task:

The Dock Manifest

<applications>
 <application background="true" default="true">
   http://applications.ucompass.com/SampleApps/UcompOSExamples/assets/manifests/DragAndDropExample.xml
 </application>
</applications>

The Application Manifest

<application selfLoading=”true” width=”206″ height=”250″ preloaderTitle=”Drag and Drop Example”>
 
 <source>
  <base>http://applications.ucompass.com/SampleApps/UcompOSExamples/bin-debug/DragAndDropExample.swf</base>
 </source>
 
 <titles>
  <title default=”true” locale=”en_US”>UcompOS Drag and Drop Example</title>
 </titles>
 
 <icons>
  <icon default=”true” locale=”en_US”>
   http://applications.ucompass.com/SampleApps/UcompOSExamples/assets/png/nature/Cloud-48×48.png
  </icon>
 </icons>
 
</application>

The Application Code

<?xml version="1.0" encoding="utf-8"?>
<s:Application 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();" height="200" width="200">
 <fx:Script>
 <![CDATA[
 import com.ucompass.ucompos.sdk.SDKClient;
 import com.ucompass.ucompos.sdk.events.SDKEvent;
 import com.ucompass.ucompos.sdk.proxycomponents.UcompOSArtifactProxy;
 import com.ucompass.ucompos.sdk.proxycomponents.UcompOSHTMLProxy;
 
 import mx.collections.ArrayCollection;
 [Bindable]
 private var _people:ArrayCollection = new ArrayCollection([
 {Name:"Ed",Age:36},
 {Name:"Max",Age:2},
 {Name:"Mason",Age:1},
 {Name:"Abigail",Age:1}]);
 
 private function start():void
 {
 SDKClient.getInstance(this);
 var artifact:UcompOSArtifactProxy = new UcompOSArtifactProxy();
 artifact.add("Drag Here!",null,
 "http://applications.ucompass.com/SampleApps/UcompOSExamples/assets/png/nature/Cloud-48x48.png",
 300,300);
 artifact.dragDropManager(true,"items",["Name","Age"]);
 artifact.addEventListener(UcompOSArtifactProxy.DRAG_DROP,dragDropHandler);
 }
 
 private function dragDropHandler(event:SDKEvent):void
 {
 var droppedItems:Array = event.data.dragDropData;
 var droppedItem:Object = event.data.dragDropData[0];
 var h:UcompOSHTMLProxy = new UcompOSHTMLProxy();
 h.alert("Your name is "+droppedItem.Name+" and you are "+droppedItem.Age+".");
 }
 
 ]]>
 </fx:Script>
 <mx:DataGrid width="200" height="200" dataProvider="{_people}" dragEnabled="true">
 <mx:columns>
 <mx:DataGridColumn dataField="Name"/>
 <mx:DataGridColumn dataField="Age"/>
 </mx:columns>
 </mx:DataGrid>
</s:Application>

Video Demo

Drag and Drop Example

The Mechanics of UcompOS Desktop (AIR 2.0) Applications

One of the more important and high-impact features of the UcompOS Rich Productivity Framework is the ability for UcompOS Rich Portal Applications to extend to the desktop.

The technology leveraged to accomplish this is Adobe AIR 2.0.

When you consider the presence of AIR 2.0′s new NativeProcess class, which enables an AIR application to target the native Operating System’s base functionality, the prospect of building industrial-strength applications that place very few limits on the developer and allow their imaginations to extend to new heights becomes very attainable.

In this post I want to talk a bit about the mechanics of AIR applications in the UcompOS RPF.  Understanding these mechanics can help you conceptualize and then deploy the most compelling rich experiences for your UcompOS Rich Portal Application.

The first thing to understand is that in the context of the UcompOS RPF, any AIR application will simply be another UcompOS entity.

A UcompOS entity represents any application or sub-application running in a UcompOS implementation.  The UcompOS Portal itself is a UcompOS entity.  All the UcompOS entities running at one time in the UcompOS RPF comprise what I refer to as the UcompOS Continuum as you know if you’ve been reading my blog postings.

There are a few different ways to launch a UcompOS AIR entity – as an application from the UcompOS Application Dock, using the UcompOSAIRProxy class, or by creating a UcompOS Artifact the user can click on to launch the AIR application.

First, let’s understand the mechanics at work here.  The UcompOS Portal is obviously a Flash-based browser entity.  In order for a browser-based Flash application to launch an AIR application, a couple things need to happen.

First, the author of the AIR application has to articulate that the application is allowed to be launched by the browser.

This is very easy to accomplish.

You simply need to have the following element as a direct child of the root element in the application’s manifest descriptor file.

<allowBrowserInvocation>true</allowBrowserInvocation>

The manifest descriptor file is NOT the UcompOS application manifest for the application.  It is the XML file that articulates the base-level behaviors and properties of an AIR application.

If you try to compile an AIR application that instantiates the UcompOS AIR SDK that does not have the above provision made, you’ll get a compilation error.

Does this mean that the only way your UcompOS AIR applications should be launched is by the browser via the UcompOS Portal?

Not necessarily.  There are ways you can set it up so that when your UcompOS AIR application is launched directly by the end-user, it opens the UcompOS Portal to a precise configuration.

It can even be configured so that your AIR application can save custom file types on the user’s desktop that when double-clicked upon can launch the AIR application which in turn launches the UcompOS Portal and then feeds one or more applications with the data contained in the desktop file.

These are a bit more advanced topics that I’ll definitely devote coverage to these capabilities sometime in the next month or so.

The next thing we need to understand is that the browser can only launch an AIR application following a user-triggered mouse click event.

When you configure an AIR application as the base source for a UcompOS Application in that application’s UcompOS Application Manifest and have the application show up on the UcompOS Application Dock, the UcompOS Portal is configured such that the clicking of the application icon on the dock is the click that is used to immediately launch the AIR application.

When you configure the Application manifest that will use an AIR application as its base source code, there are some parameters you need to incorporate into the manifest.

Below is a sample application manifest from a UcompOS AIR application that provides an example of this:

 
<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>

Note that you must at least include the appId and publisherId parameters.

There are a couple other ways to launch a UcompOS AIR application as a sub-application.

The first is with the UcompOSAIRProxy class which is built into the UcompOS SDK.

The UcompOSAIRProxy Class

The UcompOSAIRProxy class deserves some attention in this posting.  It is a Proxy Component that is used to create a virtual representation of a UcompOS AIR application in a UcompOS entity.  Inspecting the class is a good way to learn more about the mechanics of UcompOS AIR Applications.

Let’s look at the signature of the UcompOSAIRProxy‘s constructor:

public function UcompOSAIRProxy(appSource:String, appId:String,
      publisherId:String, airVersion:String, host:String="127.0.0.1", 
      operationPort:uint=0, validationPort:uint=0)

Let me touch on each of the parameters of the UcompOSAIRProxy‘s constructor:

  • appSource: This is the URL of the .air package file associated with the AIR application
  • appId: This is the application id of the AIR file as it exists in the AIR application’s descriptor file
  • publisherId: This is the value of the publisherid that is found in the file at $APP_INSTALL_DIR/Contents/Resources/META-INF/AIR/publisherid - WARNING: the publisherid will be deprecated in AIR 2.0 soon and I will then remove it as a required parameter in the UcompOSAIRProxy’s constructor at that time
  • airVersion: This is the minimum version of AIR to run the application.  AIR 2.0 is the UcompOS minimum requirement.
  • host: UcompOS AIR Applications rely on the ServerSocket class to communicate with other UcompOS entities.  By default, the UcompOS AIR application binds to 127.0.0.1 on the local machine and other UcompOS entities target that destination in socket transmissions.  However, you can override this and bind to some public facing IP address.  (NOTE: The implications here are remotely deployed UcompOS AIR Applications)
  • operationPort and validationPort: UcompOS AIR Applications bind to two ports – one for validation purposes and the other for actual UcompOS data transmissions.  By default, the UcompOS SDK will start with port number 1024, and climb upward using the first two openly available ports for operation and validation.  These port numbers can be explicitly articulated.

A UcompOSAIRProxy class has three specific types of SDKEvent instances associated with it:

  • UcompOSAIRProxy.AIR_APPLICATION_LAUNCHED: Dispatched when the AIR application has launched
  • UcompOSAIRProxy.AIR_APPLICATION_QUIT: Dispatched when the AIR application has quit
  • UcompOSAIRProxy.AIR_APPLICATION_STATUS: Dispatched following a call to the UcompOSAIRProxy instance’s getStatus(); method

An instance of UcompOSAIRProxy also has a getter/setter on the Boolean property status which returns true when the AIR application is running.

The UcompOSAIRProxy class has two methods key to our discussion: launchApplication(); and quitApplication();

You could use launchApplication(); to launch a UcompOS AIR Application as a sub-application.

When you do, however, the UcompOS Portal must find a way to meet the compulsory user-triggered mouse-click requirement mentioned above.

It does this by throwing an Alert onto the interface of the UcompOS Portal asking the user if they agree to allow the AIR application to launch and then by clicking “OK”, the user is providing the necessary mouse-click.

The full signature of the launchApplication(); method is as follows:

public function launchApplication(message:String=null):void

The message parameter allows you to display a custom message on the Alert used in this scenario.

There is an alternative way to launch a UcompOS AIR sub-application that I’ll cover next.

Using a UcompOS Artifact to launch an AIR Application

By now, you know that the UcompOSArtifactProxy class in the UcompOS SDK provides a way to implement the equivalent of “desktop widgets” on the UcompOS Portal interface.  I prefer the term “Artifact” over “Widget” however as I feel widget has functionality implied, whereas a UcompOS Artifact can be functional and can be a full-fledged UcompOS sub-application or it can be strictly presentational.

As is the case with all Proxy Components (i.e. any class that extends AbstractProxyComponent), UcompOSArtifactProxy instances have a data property.

When you set the data property of a UcompOSArtifactProxy instance, this data property is housed on the actual artifact itself on the UcompOS Portal.

There are two special properties that can be added to this data Object: launchAIRApplication and quitAIRApplication

The values of these properties would be the uuid property of the UcompOSAIRProxy instance that was to be launched upon a mouse click of the artifact involved.

So the following code may be something you’d see in practical operation:

var myAIRAppProxy:UcompOSAIRProxy = new UcompOSAIRProxy("http://apps.mysite.com/myApp.air","My-App","My-Publisher-Id","2.0");
var myArtifactProxy:UcompOSArtifactProxy = new UcompOSArtifactProxy();
myArtifactProxy.add("Label for my Artifact",imageContent);
myArtifactProxy.data = {launchAIRApplication:myAIRAppProxy.uuid};

In the above example, as soon as the artifact is clicked on, the AIR application will launch.

You could also do something like the following too:

private function launchHandler(event:SDKEvent):void
{
 switch(event.type)
 {
 case UcompOSAIRProxy.AIR_APPLICATION_LAUNCHED:
  myArtifactProxy.setImage(imageContentAppOn);
  myArtifactProxy.data = {quitAIRApplication:myAIRAppProxy.uuid};
 break;
 case UcompOSAIRProxy.AIR_APPLICATION_QUIT:
  myArtifactProxy.setImage(imageContentAppOff);
  myArtifactProxy.data = {quitAIRApplication:myAIRAppProxy.uuid};
 break;
 }
}

In the above example, we are listening to see when the AIR application is launched as well as when it quits.  We then replace the artifact image with a status indicator using the UcompOSArtifactProxy‘s setImage(); method so it easily shows the user if the associated AIR application is running or not.

As an example of how I am using this concept myself, in the Educator 2 Rich Portal Application I am building entirely on top of the UcompOS RPF, on the taskbar (an artifact container with a number of artifacts housed in it), there is an icon to launch the “Educator 2 Desktop”, which is obviously an AIR application.

When they click this icon, the Educator 2 Desktop immediately launches and the icon turns green indicating the feature is connected.  When they click it again, the Educator 2 Desktop quits and the icon turns red indicating the feature is disconnected.

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.

Shared Object Model Implemented into UcompOS RPF

As of the UcompOS RPF Public Alpha Release 0.1.13 that I posted last night, there is a new Shared Object implementation model.

On the UcompOS Portal, there is a run-time Object that can be used to share information across multiple entities in a UcompOS implementation.

Note that at this time this is just a run-time Object.  This is NOT an implementation of the Local Shared Object that gets permanently housed in the Flash Player’s local storage infrastructure.

The UcompOSGlobalManagerProxy has three new methods: setSharedObject();, getSharedObject();, and getSharedObjects();.

I’ll describe each of them below:

public function setSharedObject(key:String, value:Object):void

This sets a property named key on the UcompOS Portal shared object and assigns it a value of value.

A very important point is that when this method is called, the UcompOS Portal dispatches a UcompOS Continuum event of type UcompOSGlobalManagerProxy.SHARED_OBJECT with properties of key and value such that each entity in the Continuum is notified when a Shared Object value is updated.  This could easily enable two disparate UcompOS Applications to update their interfaces in real-time according to model changes implemented by the other.

public function getSharedObject(key:String):void

This retrieves the value on the UcompOS Portal shared object in the property key.

The information is received asynchronously by listening for an SDKEvent of type UcompOSGlobalManagerProxy.SHARED_OBJECT and testing the value of the event object’s key property.

public function getSharedObjects(keys:Array):void

This retrieves multiple shared objects simultaneously.  Each member of the keys array is the name of a property on the UcompOS Portal shared object.

The data is retrieved asynchronously by listening for an SDKEvent of type UcompOSGlobalManagerProxy.SHARED_OBJECTS whose data Object will have a sharedObjects property that is an Object.  Each property name requested in the keys array is a property name in the sharedObjects Object with its value the value of the corresponding item on the UcompOS Portal shared object.

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

Meet the UcompOS Portal Proxy Components

If you’ve read my previous postings, you should now have a basic understanding of some of the core mechanics of the UcompOS Rich Productivity Framework including Proxy Components and Services Dictionaries.

The concept of the UcompOS Continuum should also be somewhat clearer now as well as the roles of the UcompOS Portal and the UcompOS SDK in the context of the UcompOS Continuum.

Despite the obvious significance of the UcompOS Portal, in the context of the UcompOS Continuum, it is just another entity with the UcompOS SDK implemented that publishes a Services Dictionary of public API methods exposed for other entities.

To take advantage of this fact, the UcompOS SDK has a host of Proxy Components built into it that can be thought of as client interfaces to the public API methods exposed by the UcompOS Portal.

Understanding the mechanics of building your own UcompOS public API methods and Proxy Components to those public API methods is the key to unleashing the true power of the UcompOS RPF and creating the most compelling rich experiences for users of your Rich Portal Application.

But even a basic exploration of the SDK’s built-in UcompOS Portal Proxy Components is a fun way to explore and learn.

In this post, I’ll introduce you briefly to the UcompOS Portal Proxy Components.  I won’t spend a lot of time detailing them as you’ll likely see some dedicated blog postings from me covering the individual Proxy Components and their nuances in the coming weeks.

Each Proxy Component covered is built into all 3 UcompOS SDKs – AIR, Flex/Flash, and JavaScript.

The implementation details of using the AIR and Flash/Flex (ActionScript 3.0) Proxy Components versus the JavaScript Proxy Components are very subtle and of course full SDK documentation is online for the ActionScript 3.0 SDK as well as the JavaScript SDK.

Since the SDK documentation is online, I won’t spend a lot of time covering the methods, properties, and events of the Proxy Components (as you can get all this information in the docs), rather I’ll just give a first-person synopsis of what you can do with each of the Proxy Components.

UcompOSAIRProxy

The UcompOSAIRProxy class allows you to create a virtual representation of a UcompOS AIR application in an entity.  Once you create this virtual representation, you then use this class’s launchApplication(); and quitApplication(); method to control the start and stop of the AIR application.  Then any communication with the AIR application is handled via the traditional means of Proxy Components and public API methods.  The UcompOSAIRProxy class would be used when you wanted to launch a UcompOS AIR application as a sub-application.  If the UcompOS AIR application was to be a base application, you would just have the network URL to the air package in the application manifest and the AIR application would be launchable from the UcompOS application dock.  See my tutorial entitled A Simple HTML Digital Camera Browser for an example of this.

UcompOSArtifactContainerProxy

The UcompOSArtifactContainerProxy class lets you create a container for UcompOS Artifacts on the UcompOS Portal.  A UcompOS Artifact is essentially a “widget” that can be an image or SWF application that can have functionality attached to it (drag and drop, double click, click, rollover, context menu, etc.).

A UcompOS Artifact Container then is a visual layout container for these artifacts.  I gave an example of this in my tutorial entitled Building a UcompOS Weather Channel Widget.

An example may be a taskbar.  Suppose I want to layout a number of widgets each with its own specific functionality attached to it along the bottom right corner of my UcompOS Portal interface.

To do this I could create a UcompOS Artifact Container via the UcompOSArtifactContainerProxy class.  Then when I create my UcompOS Artifact, I would pass a reference to my UcompOSArtifactContainerProxy instance and the artifact would be placed into the relevant container.

There are 3 layout options at present with the UcompOS Artifact Container: HBox, VBox, and Tile

These are parallel to the classes of the same name in the mx.containers package from the Flex 3 framework (FYI the UcompOS Portal is built on Flex 4).

UcompOSArtifactProxy

The UcompOSArtifactProxy is a class used to create UcompOS Artifacts on the UcompOS Portal.

A UcompOS Artifact can be thought of as a widget.  The widget can be purely presentational, or it can have functionality attached to it as my Weather Channel Widget example demonstrated.

The visual content of a UcompOS Artifact can articulated as one of three forms:

  1. The network URL to an image (PNG, GIF, JPG)
  2. The network URL to a SWF appication
  3. A ByteArray representation of an image

You then attach functionality to a UcompOS Artifact by calling the UcompOSArtifactProxy‘s many public methods and attaching various event listeners to it to handle click, double click, rollover, rollout, drag and drop, and other various events.

If the visual content of your artifact is a SWF, this SWF can be a UcompOS sub-application for even more exciting interactive possibilities.

At this point, HTML-type applications cannot be used as artifacts

As described above in my discussion of the UcompOSArtifactContainerProxy class, you can add a UcompOS Artifact to a container so that groups of similar artifacts can be arranged together in a logical presentation.

One cool thing you can do, if you don’t add an artifact to a container and just position it at specified coordinates on the UcompOS Portal, you can make it draggable.  And because you can configure artifacts to accept drops, the ability to drag and drop one artifact to another to create some desired behavior or functionality exists.

I’ll likely devote a tutorial to this interesting capability in the near future.

UcompOSBrowserWindowProxy

The UcompOSBrowserWindowProxy class lets you launch a satellite browser window from the UcompOS Portal.  You can add generic content to the browser window, or you can load a UcompOS sub-application.

The ability to communicate with a UcompOS sub-application loaded in a satellite browser window is the exact same as if the sub-application was loaded in the UcompOS Portal run-time, in a UcompOS Window, or in a UcompOS Artifact.

UcompOSDockProxy

The UcompOSDockProxy class lets you exert control over the UcompOS Portal’s Application Dock.

You can do things such as set context menus to the application icon an entity is associated with.  You can also change the size of the icons on the dock as well as control the “genie” effect (the effect where the dock icons expand and then contract as the mouse passes over them).

You can also hide the dock completely using the showDock(visible:Boolean):void; method.

And one of the more important capabilities is you can set an alert for the icon on the dock an entity is associated with using the setAlert(); method.  This would be useful perhaps in e-mail or instant messaging applications to alert the user of receipt of a new e-mail or instant message.

UcompOSGlobalManagerProxy

The UcompOSGlobalManagerProxy class provides an interface to a number of important visual and data features  of the UcompOS Portal.

For instance, if you wanted the UcompOS Portal to throw a generic Flex-style Alert, you could use the createAlert(); method.

If you wanted to dispatch an event to all entities in the UcompOS Continuum, you could use the dispatchContinuumEvent(); method.

Suppose you wanted to launch another UcompOS application from within an entity.  You could call the launchApplication(); method and pass the manifest URL of the target application’s application manifest.

These are only a few of the important duties the UcompOSGlobalManagerProxy facilitates.

UcompOSHTMLProxy

The UcompOS Portal is a Flex 4 application embedded in an HTML wrapper.

The UcompOSHTMLProxy class lets you call JavaScript functions in the HTML wrapper.

The class provides the alert();, confirm(); and prompt(); methods which invoke the JavaScript functionality of the same name.

You can then add event listeners such as UcompOSHTMLProxy.CONFIRM_SUBMIT and UcompOSHTMLProxy.PROMPT_SUBMIT to capture user-input.

You can also use the javascript(); method to pass pure JavaScript code.

So one possibility here, in the ucompos/local/LocalLib.js JavaScript file in the UcompOS Developers Package that you customize to create your own authentication, you can implement your own JavaScript methods that perform specific tasks and then access these methods from the UcompOSHTMLProxy.

UcompOSMenuBarProxy

The UcompOSMenuBarProxy lets you set the dataProvider for the UcompOS Menu Bar and your particular menu bar implementation comes into view when the UcompOS application associated with the entity that set the menu bar model comes into focus.

You can even associated a menu bar model with an individual UcompOS Window instance.

You then attach event listeners to capture user menu selections.

Two cool random quick points is that you can pass a baseMenu=true value to the second parameter of the setMenuBar(); method and it will remove the default UcompOS menu bar item so you can 100% customize the menu.  Also, in your dataProvider to the menu you can attach an icon property with the network URL of images you want to use for the individual menu bar nodes.

UcompOSStyleProxy

The UcompOSStyleProxy class lets you take control over the portal’s visual presentation including the background image (wallpaper) that appears on the UcompOS portal.

With the setTheme(); method, you can set the MDI window theme to one of 3 different pre-existing window themes.  Right now, I just have the 3 that come packaged with the flexlib.mdi package implemented (Windows XP, Mac OS 9, and the default style) but it is my intention to expand this.

There is also a setEffects(); method that let you control the visual effects that occur when UcompOS Windows are closed or minimized/maximized.  The options are Default, Linear, and Vista which are the effects built into the flexlib.mdi package.

There is also a generic setStyle(); method that lets you set a generic CSS style property to the UcompOS Portal.

One important point about this method.  When you call setStyle();, the UcompOS Portal dispatches a UcompOS Continuum Event – meaning that all entities get notified about the style change.

So if you did something like this:

UcompOSStyleProxy.getInstance().setStyle("Button","color",0xFF0000);

Every entity would be notified that the Button selector’s color property was just given a red value on the UcompOS Portal.

You could then listen for this UcompOSStyleProxy.STYLE_CHANGE event and change the visual presentation of an entity’s internal controls accordingly.

UcompOSWindowProxy

The UcompOSWindowProxy class is used to create MDI window instances on the UcompOS Portal and then load generic web content or a UcompOS sub-application into them.

The class documentation is definitely worth a look as there are a lot of really cool features you can employ with UcompOS Window instances.

So that’s it.  A brief look at all the UcompOS Portal Proxy Components built into the UcompOS SDK.

I invite you to view the source code of the the JavaScript SDK and you can check the UcompOS Flash/Flex SDK written in ActionScript 3 out of the UcompOS SVN Repository.  Viewing this code will give you some better ideas of how to construct Proxy Components.

I have not yet made the source code of the UcompOS Portal publicly viewable and do not have a timeline for doing so but if you have questions about how I have built the public API methods on the UcompOS Portal, please bring questions to me in the UcompOS Forum and I’ll share relevant strategies and code examples.

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.