UcompOS Compiled with Flex SDK 4.9.0

The UcompOS and all associated SDKs and components have been recompiled with the Apache Flex SDK 4.9.0.

UcompOS 2.0.0 Released

Version 2.0.0 of the UcompOS Rich Productivity Framework has been officially released.

The entire build (the UcompOS Portal and SDK) has been migrated to the latest release of the Apache Flex SDK 4.8.0.

UcompOS Rich Productivity Framework is Now in Beta

Over the last 6 weeks, we have been diligently working to move the UcompOS RPF project from Alpha to Beta and as of this morning, that effort has come to completion.

There are numerous enhancements and bug fixes that are introduced into the Beta release. Also, we are compiling the project against the Adobe Flex 4.1 SDK nightly builds.

An MXML Image Component That Loads Images With No Associated Policy Files

In a major UcompOS project I am working on, I am finding the need more and more to load images from various different servers where the destination servers often have no crossdomain.xml policy file.

I don’t want to use a back-end proxy to deal with this as that would be chewing up my back-end resources and bandwidth which goes against my grain especially when targeting a product for wide deployment.

I will post the code of the component below which should be very self-explanatory:

<?xml version="1.0" encoding="utf-8"?>
<mx:Image xmlns:fx="http://ns.adobe.com/mxml/2009" 
		  xmlns:s="library://ns.adobe.com/flex/spark" 
		  xmlns:mx="library://ns.adobe.com/flex/mx" 
		  securityError="securityErrorHandler(event)" 
		  trustContent="true">
	<fx:Script>
		<![CDATA[
 
			private var _legal:Boolean = true; 
			private var _url:String;
 
			public function get legal():Boolean
			{
				return _legal;
			}
 
			private function securityErrorHandler(event:SecurityErrorEvent):void
			{
				this.removeEventListener(SecurityErrorEvent.SECURITY_ERROR,securityErrorHandler);
				_legal = false;
				var sprite:Sprite = new Sprite();
				var loader:Loader = new Loader();
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE,load_handler);
				sprite.addChild(loader);
				var loaderContext:LoaderContext = new LoaderContext();
				loaderContext.checkPolicyFile = false;
				loader.load(new URLRequest(url),loaderContext);
			}
 
			private function load_handler(event:Event):void
			{
				var loaderInfo:LoaderInfo = event.target as LoaderInfo;
				loaderInfo.removeEventListener(Event.COMPLETE,load_handler);
				var bitmapData:BitmapData = new BitmapData(loaderInfo.width,loaderInfo.height);
				var matrix:Matrix = new Matrix();
				bitmapData.draw(loaderInfo.content,matrix);
				var bitmap:Bitmap = new Bitmap(bitmapData);
				source = bitmap;
			}
 
			public function get url():String
			{
				return _url;
			}
 
			public function set url(value:String):void
			{
				loaderContext = new LoaderContext(false);
				_url = value;
				source = value;
			}
		]]>
	</fx:Script>
</mx:Image>

Some things to point out about the component in no particular order:

  • You set a value of a URL to the image to the url property instead of the source property
  • A Boolean named legal has a false value if the content of the image was loaded using an assisting Sprite and Loader instance
  • The source property on an Image control is of a wildcard (*) type – if the value of legal is true, then source is a String and will have the same value as url. If the value of legal is false, then source will be an Object of type Bitmap

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.

Auto-Updating the UcompOS Portal

As you know, at the Downloads portion of the UcompOS Project site, you can download the UcompOS Developers Package which contains the UcompOS Portal run-time, as well as the UcompOS SDK for JavaScript, Flash/Flex, and AIR 2.0.

This enables you to host a full UcompOS implementation on your local workstation for testing and development, or to host a public UcompOS implementation from your own webservers.

With the UcompOS project being updated frequently, the physical process of updating the UcompOS RPF and its associated components can be tedious.

There are ways you can automate the process, but it requires some simple scripting that can be accomplished in a variety of languages.

There are some static URLs to know about first of all.

The latest release of the UcompOS Developers package is always found at a URL of http://ucompos.ucompass.com/UcompOS.zip.  That zip package expands into a folder named bin-release and within that folder are the contents of the UcompOS Portal.  Also inside that folder is a file UcompOSSDK.zip which expands into an sdk folder, inside of which are an html, air, and flashOrFlex folder with each of the three respective SDKs for those different platforms.

In my current large scale UcompOS implementation, what I am doing is setting it up so that I have one and only one copy of the different SDK files  – UcompOSSDK.swc (Flash/Flex), UcompOSSDKAIR.swc (AIR), and UcompOSSDK.js and UcompOSSDK.swf (JavaScript).

I then establish relative symlinks to the various locations on my local file system where those files need to be placed – libs folders in Flex projects and root webserver paths for JavaScript applications.  For Flash applications I simply embed the UcompOSSDK.swc file from the singular location where the file exists on my workstation.

As far as updating the UcompOS Portal, the developers package bin-release folder contains a simple XML file named release.xml.

This is what the current one looks like as of this morning:

<release>
     <portal>
          <version>0.4.5</version>
          <packaged>Tue Mar 23 08:47:44 2010</packaged>
     </portal>
     <sdk>
          <version>0.4.5</version>
          <packaged>Tue Mar 23 02:02:53 2010</packaged>
     </sdk>
</release>

Also, a file exists at the URL http://ucompos.ucompass.com/release.xml of the same format which you can test against to determine if you are running the same version of the UcompOS Portal or if there is an update available.

Note there IS an SVN Repository for the UcompOS Project but at this time it is just meant as a means to distribute the UcompOS SDK source code. Eventually, I plan to make all of the UcompOS RPF project open source and there will be a model for accessing the full source code of all the associated UcompOS technologies and you’d be able to structure your updates according to check-outs from SVN. (My timeline for this by the way is to coincide the open-sourcing of the UcompOS Portal with the production 1.0 release of the UcompOS RPF which I am trying to coincide with Adobe MAX 2010 in October).

In the meantime, there are still a number of simple ways you can go about coordinating an auto-update.

Below is a very simple PERL script I wrote that auto-updates the UcompOS Portal in my Educator 2 project:

#!/usr/local/bin/perl
 
use strict;
 
use LWP::Simple;
use XML::LibXML;
 
my $myVersion;
if(!-e "../../frontend/release.xml")
{
	$myVersion = 0;
}
else
{
	open(FILE,"../../frontend/release.xml");
	my @line = <FILE>;
	close(FILE);
 
	my $myReleaseInfo = join("",@line);
	$myVersion = getVersion($myReleaseInfo);
 
 
}
 
my $latestVersion = getVersion(get("http://ucompos.ucompass.com/release.xml"));
 
if($myVersion ne $latestVersion)
{
	update();
}
 
sub getTextNode {
 
	my $thisNode = $_[0];
	my @thisChild = $thisNode->getChildNodes;
	my $textNode;
	eval {
		$textNode = $thisChild[0]->getNodeValue;
	};
 
	if(!$textNode) {
		eval {
		$textNode = $thisChild[0]->nodeValue;
		};
	}
 
	return $textNode;
 
}
 
sub getVersion
{
	my $releaseInfo = $_[0];
	my $xml = XML::LibXML->new;
	my $string = $xml->parse_string($releaseInfo);
	my $xp = XML::LibXML::XPathContext->new($string);
	my @nodeSet = $xp->findnodes('//portal/version');
	my $version = getTextNode($nodeSet[0]);
	return $version;
}
 
sub update
{
 
	chdir('cache');
	my $content = get("http://ucompos.ucompass.com/UcompOS.zip");
	open(FILE,">UcompOS.zip");
	print FILE $content;
	close(FILE);
 
	system("unzip -qq 'UcompOS.zip'");
	unlink("UcompOS.zip");
	system("rsync -a --delete --exclude=\"LocalLib.js\" --exclude=\"styles.css\" bin-release ../../../frontend");
	system("\\rm -rf bin-release");
 
}

In my example above, I basically have my UcompOS Portal code housed in a bin-release folder. I check the latest release version and see if it matches my local version, and if it doesn’t, I retrieve the latest package, unzip it, and overwrite my existing copy with rsync excluding the LocalLib.js and styles.css files – which are the only files in the UcompOS Developers package you would typically need to update with your own implementation specific information.

Embedding Application Manifests Inside the Dock Manifest

As of UcompOS RPF build 0.4.3, you can now embed Application Manifests inside of your Dock Manifest.

The element of a Dock Manifest houses child elements, each of which point to the unique URL of a UcompOS Application Manifest file as shown in the following example:

<applications>
     <application>http://applications.ucompass.com/myApplication.xml</applications>
</applications>

Now, you can embed a element inside of an element in the dock manifest and include the full application manifest inside the element as shown in the following simple example:

<applications>
     <manifestURL>http://applications.ucompass.com/myApplication.xml</manifestURL>
     <manifest>
             <source>
                  <base>http://applications.ucompass.com/mySource.swf</base>
             </source>
     <manifest>
</applications>

Notice you also need to articulate a unique URL for the manifest file in a element – even if there is nothing at the indicated URL.

Also, the UcompOSGlobalManagerProxy‘s launchApplication() method now accepts an optional third manifest parameter of type XML that can be a dynamically generated application manifest.

Therefore, the possibility to generate UcompOS applications on the fly exists.

Instantiating UcompOS Global (Continuum) Variables at Startup

In my post about UcompOS Shared Objects, I described how the UcompOS Portal furnishes a Shared Object Implementation that can be written to and read by any UcompOS entity in the UcompOS Continuum.

In a large-scale UcompOS Rich Portal Application, you very likely may find a need to share complex data across multiple UcompOS entities.

One effective approach to this challenge is to use the UcompOSGlobalManagerProxy class’s setSharedObject(), getSharedObject(), and getSharedObjects() methods.

These methods get/set shared objects on the UcompOS Portal at run-time.

But what if you want to populate the UcompOS Portal’s shared Object at start-up even before any UcompOS applications are launched?

As of the version 0.4.1 Milestone release of UcompOS RPF, there is a way to do this.

The key is a new <globalVariables/> element that can be added as a child element to the root <applications/> element in a dock manifest and as a child element to the root <application/> element in a UcompOS application manifest.

Below is a simple example of this in action in the dock manifest of my Educator 2 software application being built entirely on top of the UcompOS RPF:

<?xml version="1.0" encoding="utf-8"?>
<applications>
	<globalVariables>
		<globalVariable>
			<key>_DOMAIN_</key>
			<value>applications.ucompass.com</value>
		</globalVariable>
		<globalVariable>
			<key>_PROTOCOL_</key>
			<value>http</value>
		</globalVariable>
		<globalVariable>
			<key>_GATEWAY_</key>
			<value>http://pilotfish2.ucompass.com/apps/gateway</value>
		</globalVariable>
	</globalVariables>
	<application background="true" default="true">
		_PROTOCOL_://_DOMAIN_/Educator2PortalFoundation/manifest.xml
	</application>
</applications>

Each global variable is wrapped in a <globalVariable/> element with child <key/> and <value/> elements.

All global variables in the dock manifest will automatically be added to the UcompOS Portal’s Shared Object implementation and will immediately be available to all UcompOS entities.

String Substitutions in Manifest Files

In the above example, notice I am instantiating global variable named _PROTOCOL and _DOMAIN_. And then notice that those strings appear in my <application/> element.

A string substitution will automatically take place here such that the <application/> value will be http://applications.ucompass.com/Educator2PortalFoundation/manifest.xml after the substitution.

As mentioned earlier, the <globalVariables> element is supported in both application manifests and dock manifests so you can also establish global variables in this fashion when launching a UcompOS application.

Typing Shared Objects

The <value/> element supports an optional type attribute such that you can articulate the data type of a Shared Object.

The best way to show how this is accomplished is with examples:

Array

<globalVariable>
	<key>groceryList</key>
	<value type="Array">
		<item>Bananas</item>
		<item>Cereal</item>
		<item>Diapers</item>
	</value>
</globalVariable>

Object

<globalVariable>
	<key>contacts</key>
	<value type="Object">
		<item>
			<key>Joe</key>
			<value>555-1212</value>
		</item>
		<item>
			<key>Bob</key>
			<value>555-2121</value>
		</item>
	</value>
</globalVariable>

The type attribute can also be of type uint, int, Boolean, Number and String. The default data type is String. Also, the <item/> element supports the type attribute for Arrays and Objects.

Also, nesting of complex data structures is supported, so you can implement an Array of Arrays, or an Array of Objects, etc.

Introducing 3 New UcompOS Portal Proxy Components

The UcompOS SDK in the latest milestone release of the UcompOS Rich Productivity Framework, Public Alpha 0.3.1, contains 3 new UcompOS Portal Proxy Components that open up a host of new capabilities.

In this article, I’ll briefly introduce each of these 3 new components and show some examples of how they can be used and I plan to build some new tutorial content in the near future to cover these 3 new components.

UcompOSKeyboardProxy

Within the scope of an individual UcompOS application or sub-application, you can certainly implement your own logic to handle keyboard events.

However, suppose you want to capture keyboard events that occur in the scope of the UcompOS Portal and pass them to other UcompOS entities such as those that may be running as AIR applications on the desktop, in separate UcompOSBrowserWindowProxy instances, or in sandboxed SWF implementations.

You can now use the new UcompOSKeyboardProxy class to do this.

The class is a Singleton with a single property named listen.

When you set the listen property to true, any keyboard events that occur in the scope of the UcompOS Portal will be dispatched by the UcompOSKeyboardProxy Singleton.

Let’s look at a simple code-based example of this:

package
{
 
	import flash.display.Sprite;
	import com.ucompass.ucompos.sdk.SDKClient;
	import com.ucompass.ucompos.sdk.proxycomponents.UcompOSKeyboardProxy;
	import com.ucompass.ucompos.sdk.events.SDKEvent;
 
	public class KeyboardExample extends Sprite
	{
 
		public function KeyboardExample()
		{
			SDKClient.getInstance(this);
			UcompOSKeyboardProxy.getInstance().listen = true;
			UcompOSKeyboardProxy.getInstance().addEventListener(UcompOSKeyboardProxy.KEY_DOWN,eventHandler);
			UcompOSKeyboardProxy.getInstance().addEventListener(UcompOSKeyboardProxy.KEY_UP,eventHandler);
		}
 
		private function eventHandler(event:SDKEvent):void
		{
			trace("Type of event: "+event.type);
			trace("Character code: "+event.data.charCode);
			trace("Alt key pressed: "+event.data.altKey);
			trace("Shift key pressed: "+event.data.shiftKey);
			trace("Control key pressed: "+event.data.ctrlKey);
			trace("Key code: "+event.data.keyCode);
		}
 
	}
 
 
}

As you can see, the properties in the event dispatched by the UcompOSKeyboardProxy Singleton are very similar to those of the Flash KeyboardEvent class.

UcompOSAlertProxy

The Flex Alert class is a modal dialogue.  It prevents the user from doing anything until they click a button control on the Alert dialogue.

The UcompOSAlertProxy class lets you throw a Flex Alert onto the UcompOS Portal.

When the user clicks a button on the Alert class, instances of UcompOSAlertProxy dispatch an SDKEvent instance.

The UcompOSAlertProxy class has two methods: confirm() and simpleAlert().

confirm() throws a confirmation style dialogue onto the UcompOS Portal.

Below is the signature of the confirm() method:

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

As you can see, you can customize the alert title, the message of the Alert body, and the labels used on the “OK” and “Cancel” buttons.  You can also indicate which button should be the default button.

Let’s look at a code-based example:

package
{
 
	import flash.display.Sprite;
	import com.ucompass.ucompos.sdk.SDKClient;
	import com.ucompass.ucompos.sdk.proxycomponents.UcompOSAlertProxy;
	import com.ucompass.ucompos.sdk.events.SDKEvent;
 
	public class AlertExample extends Sprite
	{
 
		public function AlertExample()
		{
			SDKClient.getInstance(this);
			var a:UcompOSAlertProxy = new UcompOSAlertProxy();
			a.addEventListener(UcompOSAlertProxy.ALERT_SUBMIT,eventHandler);
			a.confirm("Confirm","Are you sure you want to delete this file?","Yes!","Hell No!",UcompOSAlertProxy.CANCEL);
		}
 
		private function eventHandler(event:SDKEvent):void
		{
			switch(event.data.detail)
			{
				case UcompOSAlertProxy.OK:
					trace("The file will be deleted");
					break;
				case UcompOSAlertProxy.CANCEL:
					trace("The file will NOT be deleted");
					break;
			}
		}	
 
	}
 
}

Notice in the example above, the SDKEvent‘s data Object will have a detail property that will be a value of UcompOSAlertProxy.OK or UcompOSAlertProxy.SUBMIT.  This is parallel to the implementation of the Alert in Flex.

The simpleAlert() method simply throws an Alert with a single button of type UcompOSAlertProxy.OK.

UcompOSDialogueProxy

In some instances, you’ll want to set up a modal user interaction dialogue when you want to capture some sort of input from the user.

To address this need, I created the UcompOSDialogueProxy class.

The UcompOSDialogueProxy is used to throw up a few different types of modal user interaction dialogues.

For instance, suppose you have a File Management application and you want to give the user the ability to choose a “Save As” option.

You don’t want the user to be able to do anything else until they either input a file name and press submit, or, cancel the operation.

This would be a perfect place to use the new UcompOSDialogueProxy class.

There are initially 4 different types of dialogues I have set up: TextInput for single line text input; TextArea for multiple line text input; RadioButtons for survey-type interaction; and SWFLoader which enables you to throw your own content into the dialogue and this content can be a UcompOS entity.

Below is the signature of the add() method of UcompOSDialogueProxy:

public function add(controlType:String=TEXT_INPUT,title:String="UcompOS Dialogue",label:String="",width:uint=400,height:uint=0,showCloseButton:Boolean=false,cancelLabel:String=CANCEL,submitLabel:String=SUBMIT,cancelEnabled:Boolean=true,submitEnabled:Boolean=true,initData:Object=null):void

Notice the default height is 0.  What happens is when the width or height is 0, the size of the Dialogue automatically conforms to the content that is placed inside of it.  Otherwise, the width/height is explicitly set.

The initData Object parameter has special meaning.

It is passed to the RadioButtons and SWFLoader types of Dialogues and examples of how initData is constructed in those two scenarios is depicted in the examples below.

Let’s look at a code-based example that shows how to use each of the 4 different types of dialogues:

TextInput Dialogue Example

package
{
 
	import flash.display.Sprite;
	import com.ucompass.ucompos.sdk.SDKClient;
	import com.ucompass.ucompos.sdk.proxycomponents.UcompOSDialogueProxy;
	import com.ucompass.ucompos.sdk.events.SDKEvent;
 
	public class TextInputDialogue extends Sprite
	{
 
		public function TextInputDialogue()
		{
			SDKClient.getInstance(this);
			var d:UcompOSDialogueProxy = new UcompOSDialogueProxy();
			d.add(UcompOSDialogueProxy.TEXT_INPUT,"Sample Dialogue","What is your name?");
			d.addEventListener(UcompOSDialogueProxy.DIALOGUE_SUBMIT,eventHandler);
		}
 
		private function eventHandler(event:SDKEvent):void
		{
			var d:UcompOSDialogueProxy = event.target as UcompOSDialogueProxy;
			trace("Your name is "+event.data.data);
			d.close();
		}
 
	}
 
}

Notice in the above example, in the eventHandler() method, the UcompOSDialogueProxy‘s close() method is called.  The dialogue does not disappear by itself upon a submission.  You have to explicitly remove it with the close() method such that you have much better control over when the dialogue is closed based on the specifics of the user’s input.

TextArea Dialogue Example

package
{
 
	import flash.display.Sprite;
	import com.ucompass.ucompos.sdk.SDKClient;
	import com.ucompass.ucompos.sdk.proxycomponents.UcompOSDialogueProxy;
	import com.ucompass.ucompos.sdk.events.SDKEvent;
 
	public class TextAreaDialogue extends Sprite
	{
 
		public function TextAreaDialogue()
		{
			SDKClient.getInstance(this);
			var d:UcompOSDialogueProxy = new UcompOSDialogueProxy();
			d.add(UcompOSDialogueProxy.TEXT_AREA,"Sample Dialogue","Please tell us why you like the UcompOS in 1,000 words or less:");
			d.addEventListener(UcompOSDialogueProxy.DIALOGUE_SUBMIT,eventHandler);
		}
 
		private function eventHandler(event:SDKEvent):void
		{
			var d:UcompOSDialogueProxy = event.target as UcompOSDialogueProxy;
			trace(event.data.data);
			d.close();
		}
 
	}
 
}

The TextArea example is almost identical to the TextInput example.

RadioButtons Dialogue Example

package
{
 
	import flash.display.Sprite;
	import com.ucompass.ucompos.sdk.SDKClient;
	import com.ucompass.ucompos.sdk.proxycomponents.UcompOSDialogueProxy;
	import com.ucompass.ucompos.sdk.events.SDKEvent;
 
	public class RadioButtonsDialogue extends Sprite
	{
 
		public function RadioButtonsDialogue()
		{
			SDKClient.getInstance(this);
			var d:UcompOSDialogueProxy = new UcompOSDialogueProxy();
			var choices:Array = ["ActionScript 3","JavaScript","PERL","C++"];
			d.add(UcompOSDialogueProxy.RADIO_BUTTONS,"Sample Dialogue","What is your favorite programming language?",0,0,false,UcompOSDialogueProxy.CANCEL,UcompOSDialogueProxy.SUBMIT,true,true,{choices:choices});
			d.addEventListener(UcompOSDialogueProxy.DIALOGUE_SUBMIT,eventHandler);
		}
 
		private function eventHandler(event:SDKEvent):void
		{
			var d:UcompOSDialogueProxy = event.target as UcompOSDialogueProxy;
			trace("Your favorite programming language is: "+event.data.data);
			d.close();
		}
 
	}
 
}

Notice in the example above, we are building an Array of choices to give to the user where a Radio Button will be associated with each choice.  The Array is passed as a property named choices in the initData parameter passed to the UcompOSDialogueProxy‘s add() method.

SWFLoader Dialogue Example

package
{
 
	import flash.display.Sprite;
	import com.ucompass.ucompos.sdk.SDKClient;
	import com.ucompass.ucompos.sdk.proxycomponents.UcompOSDialogueProxy;
	import com.ucompass.ucompos.sdk.events.SDKEvent;
 
	public class SWFLoaderDialogue extends Sprite
	{
 
		public function SWFLoaderDialogue()
		{
			SDKClient.getInstance(this);
			var d:UcompOSDialogueProxy = new UcompOSDialogueProxy();
			var source:String = "http://applications.ucompass.com/MyCustomDialogue.swf":
			d.add(UcompOSDialogueProxy.SWF_LOADER,"Sample Dialogue","",0,0,false,UcompOSDialogueProxy.CANCEL,UcompOSDialogueProxy.SUBMIT,true,true,{source:source});
			d.addEventListener(UcompOSDialogueProxy.DIALOGUE_SUBMIT,eventHandler);
		}
 
		private function eventHandler(event:SDKEvent):void
		{
			var d:UcompOSDialogueProxy = event.target as UcompOSDialogueProxy;
			trace("The Connection Id of your SWF content is: "+event.data.data);
			d.close();
		}
 
	}
 
}

In this case, we are passing the URL of a SWF to the dialogue.  When the user presses the Submit button for the dialogue, the connection id of the SWF content is returned in the SDKEvent dispatched by the UcompOSDialogueProxy instance.

From here, UcompOS SDK transactions could be used to communicate directly with the SWF content and retrieve special information from it.

In-Depth Coverage of the UcompOS Menu Bar

The menu bar feature on the UcompOS Portal can be customized in a number of different ways.  This article will discuss the basics of the UcompOS menu bar, and also provide a look at some of the features that have been recently added to the menu bar including support for keyboard shortcuts.

Attaching a Menu Bar to a UcompOS Application

The common paradigm of using the menu bar is to have a custom menu bar implementation appear while a particular UcompOS application is in focus.

There are two ways to go about doing this.

The first is to attach an XML model for the menu bar to the particular UcompOS application’s manifest file.

Below is an example of a simple menu bar model that would be placed in the UcompOS application manifest file as a child of the root application element.

	<menu>
		<menuitem label="File">
			<menuitem label="Open"/>
			<menuitem label="Close"/>
			<menuitem label="Quit"/>
		</menuitem>
		<menuitem label="Edit">
			<menuitem label="Copy"/>
			<menuitem label="Paste"/>
		</menuitem>
	</menu>

You can also add a custom menu bar implementation to a UcompOS application at run-time.

This is accomplished using the UcompOSMenuBarProxy class that is built into the UcompOS SDK.

UcompOSMenuBarProxy is a Singleton, meaning it is instantiated via a static method.

It offers a setMenuBar() method that accepts a parameter model of type XML (String in the JavaScript SDK).

Below is a simple example of the UcompOSMenuBarProxy‘s setMenuBar() method at work:

var menuBarModel:XML = new XML("<menu><menuitem label='File'><menuitem label='Open' data='open'/><menuitem label='Close' data='close'/></menuitem></menu>");
UcompOSMenuBarProxy.getInstance().setMenuBar(menuBarModel);

If you have done any coding in Flex and added your own XML dataProvider to a Flex MenuBar implementation, the above example should look familiar.  The XML data model we are using is based on the model that is used inside of Flex.

The Base UcompOS Menu Item

By default, UcompOS Portal implementations will have a base menu bar item that is perpetually viewable throughout the user’s session.  This is analogous to the Mac OS X Operating System’s menu bar implementation that has a base menu bar item on the left of the menu bar represented by Apple’s trademark logo.

BaseMenuBar

The base menu bar option is shown above.

Overriding the Base Menu Item

You can replace the built-in UcompOS menu bar item with your own custom implementation in one of two ways.

One such way is by adding a baseMenu element to one of your UcompOS application’s manifest files.

Below is an example of this:

<baseMenu>
	<menuitem label="Company X">
		<menuitem label="About Our Company" data="about"/>
	</menuitem>
</baseMenu>

This would replace the base UcompOS menu bar item with an option labeled “Company X” that has an “About Our Company” sub option.

Below is an example of the custom base menu bar for the Educator 2 software I am building on top of the UcompOS RPF:

Educator2MenuBar

The other way would be to use the UcompOSMenuBarProxy class and to override the base menu item at run-time.

The second parameter of the UcompOSMenuBarProxy‘s setMenuBar() method is an optional Boolean property named baseMenu that defaults to false.

When you pass in a true value for this parameter, the menu bar model you pass to setMenuBar() will become the base menu item.

There can only be one base menu item at a time throughout your entire UcompOS implementation.  If UcompOS Application A sets the base menu item, then UcompOS Application B sets the base menu item later, it will override the base menu item set by UcompOS Application A.

It is planned at some point that the UcompOS Dock Manifest will indicate which UcompOS Applications have the privilege of setting the base menu item which could be an important consideration in large collaborative development environments.

Sharing a Menu Bar Across Multiple UcompOS Applications

In some implementations, you may want one menu bar implementation to be used across multiple applications.

To do this, you would declare one of your applications as the default application.  This is accomplished in one of two ways: in the Dock Manifest by passing a default=”true” attribute to an <application/> element, or at run time with the UcompOSGlobalManagerProxy‘s isDefaultApplication property.

When a default application is set on the UcompOS Portal, then any UcompOS Applications that have the following menu bar models:

	<menu default="true"/>

will use the Menu Bar implementation that is assigned to the application that has been declared as the default application.

As a note of caution, only one application can be declared as the default at a time on the UcompOS Portal.  If you try to declare an application as the default while another application has already been defined as the default, a run-time error will occur.  This is by design, and you must set the isDefaultApplication property of the UcompOSGlobalManagerProxy to false before you can set it to true for another application.

As is the case with setting base menu items, I am considering setting it up at the Dock Manifest level such that it is articulated ahead of time which applications can declare themselves as the default.

Menu Bar Icons

The model for the UcompOS menu bar supports the icon attribute for menuitem elements.  The value of the icon attribute should be the full URL to an image of type GIF, JPG, or PNG.

You can use any sized icon but it is recommended you use an icon sized at 18×18.

Below is an example of a menu bar implementation with icons:

MenuBarIcons

Menu Bar Separators

In the image above, notice there is a separator between the “Delete” and “Close” options.

This is accomplished with the following menuitem element:

	<menuitem type="separator"/>

Window-Specific Menu Bars

In some UcompOS applications, you may spawn many different UcompOS windows and load a variety of different sub-applications into each window instance.

Each window instance may need their own unique menu bar implementation.

The UcompOSWindowProxy class offers a setMenuBar() method that allows you to attach a custom menu bar implementation to individual UcompOS Window instances.

The menu bar will come into view whenever the window it is attached to comes into focus.  When the window closes, the menu bar will return to the existing menu bar implementation attached to the UcompOS application in focus.

Menu Bar Events

Obviously, if you go through the trouble of implementing a custom menu bar, you want to know when the user has selected an option on the menu bar.

When an item is selected on the menu bar, an event of type UcompOSMenuBarProxy.ITEM_CLICK is dispatched to any listening UcompOSMenuBarProxy instances.

A strict protocol that must be recognized is that only menuitem elements that have a data property will dispatch a UcompOSMenuBarProxy.ITEM_CLICK event.

Let’s look at a very simple code-based example:

package
{
 
	import com.ucompass.ucompos.sdk.proxycomponents.UcompOSMenuBarProxy;
	import com.ucompass.ucompos.sdk.events.SDKEvent;
	import com.ucompass.ucompos.sdk.SDKClient;
 
	public class MenuBarExample extends Sprite
	{
 
		public function MenuBarExample()
		{
			var menuBarModel:XML = new XML("<menu><menuitem label='File'><menuitem label='Select Me' data='testData'/></menuitem></menu>");
			SDKClient.getInstance(this);
			UcompOSMenuBarProxy.getInstance().setMenuBar(menuBarModel);
			UcompOSMenuBarProxy.getInstance().addEventListener(UcompOSMenuBarProxy.ITEM_CLICK,eventHandler);
		}
 
		private function eventHandler(event:SDKEvent):void
		{
			trace("The user said "+event.data.label);
			trace("The associaed data is "+event.data.data);
		}
 
	}
 
 
}

UcompOSMenuBarProxy.ITEM_CLICK events are only dispatched to UcompOS entities in the scope of the UcompOS application in focus when the menu item was selected.  So if UcompOS Application B has implemented a custom menu bar, and UcompOS Application A is in focus, no menu events will be dispatched to UcompOS Application B.

Keyboard Shortcut Commands

In applications where you load a lot of functionality onto the menu bar, keyboard shortcut commands can be a very convenient feature for your users, and, perhaps as importantly, they can help your applications address important accessibility standards crucial for many public-use applications.

To add a keyboard shortcut command to a menu item, you use the shortcutKey attribute to the menuitem element in a menu bar model.

For instance:

	<menu>
		<menuitem label="File">
			<menuitem label="Print" data="print" shortcutKey="ALT-P"/>
		</menuitem>
	</menu>

In the above example, when the user presses the ALT key and the P key simultaneously, the action that will take place will be exactly the same as if the user would have chosen the Print option with the mouse.

Below is an example of a similar implementation from Educator 2:

PrintOption