Section 14.6. Integrating Components with Your Existing Applications

14.6. Integrating Components with Your Existing Applications

In the previous sections, you learned how communication components work, how to modify existing ones, and how to create new ones.

In this section, we talk about how to integrate communication components into applications that are not fully "componentized" (i.e., applications that have some code in the main.asc or in other libraries that are not communication components).

14.6.1. The onConnectAccept and onConnectReject Events

One of the features of the framework is the ability for developers to create authenticating components, such as the one covered in this chapter. This feature allows each component to have a vote as to whether a client's connection should be accepted or rejected. The framework automatically tallies each component's decision and allows a client to connect only if all the components decided to allow the connection.

If you are not using the framework, you can execute code right after calling application.acceptConnection( ) or application.rejectConnection( ) . However, if using the framework, because the decision is now shared among all the components that are loaded, code following acceptance/ rejection of the connection needs to be moved to two new event handlers introduced by the framework: application.onConnectAccept( ) and application.onConnectReject( ) .

Here's an example of an onConnect( ) handler defined in an application's main.asc file, as it would appear if not using the framework:

 application.onConnect = function (newClient, arg1, arg2) {   // ...some code here.   if (someCondition == true) {     // Accept the connection.     this.acceptConnection(newClient);     // Code to execute upon acceptance.   }   else {     // Reject the connection.     this.rejectConnection(newClient);     // Code to execute upon rejection.   } }; 

When the application includes the framework, however, it introduces explicit onConnectAccept and onConnectReject events. Hence, the preceding code would change to:

 load("components.asc"); application.onConnect = function (newClient, arg1, arg2) {   if (someCondition == true)     this.acceptConnection(newClient);  // Vote to accept the connection.   else     this.rejectConnection(newClient);  // Vote to reject the connection.   // No additional code here; instead,   // use the functions described below. }; application.onConnectAccept = function (newClient, arg1, arg2) {   // Code to execute upon acceptance. }; application.onConnectReject = function (newClient, arg1, arg2) {   // Code to execute upon rejection. }; 

Authentication issues should not affect most applications. You need to modify only applications that explicitly have logic that follows an explicit acceptConnection( ) or rejectConnection( ) call. Such logic should be moved to onConnectAccept( ) or onConnectReject( ), as shown in the preceding example.

14.6.2. Referencing a Component Instance in main.asc

Another common thing to do when using communication components is to call methods on their server-side code. The most common example is when you want to clear the chat history in a Chat component's instance. The clearHistory( ) method is available only on the server side, so we need a way to call it from within our main.asc file.

Let's assume the Chat instance name is chat1_mc . This is how you'd call clearHistory( ) on it from main.asc :

 FCChat.instances.chat1_mc.clearHistory(  ); 

Each server-side class maintains an instances property from which you can access all server-side instances of the class.


For example, the FCChat class has a static property named instances that contains all the server-side class instances. They are named after what you called the component on the client side. So in our case, we use chat1_mc . Once you have addressed the server-side class instance ( FCChat.instances.chat1_mc ), all you have to do is call the clearHistory( ) method on it.

As we will see later, this follows the naming scheme that is such an important part of the framework.

14.6.3. Server-Side Events

Starting with FlashCom 1.5 (and updated with some bug fixes in updater 1.5.2), the Macromedia component framework was enhanced to provide a simple event mechanism.

The event mechanism supports both a throw model and a watch model. With the throw mechanism, components can dispatch events for other scripts to catch. In the watch mechanism, events are not thrown by a component. Rather, each component modifies its own property values and other scripts (components or not) can listen to changes to such properties.

Here's an example of the watch model. The following is a simple component, which we will call ComponentA:

 try {var dummy = ComponentA;} catch (e) { // #ifndef ComponentA   load("components/component.asc");   ComponentA = function (p_name) {     this.init(p_name);     this.currentValue = 0;     this.theInt = setInterval(this, "updateProperty", 5000);   };   ComponentA.prototype = new FCComponent("ComponentA", ComponentA);   // The first method called by a client component.   ComponentA.prototype.connect = function (p_client) {   };   ComponentA.prototype.updateProperty = function ( ) {     this.currentValue++;   };   trace("ComponentA loaded successfully."); } // #endif 

This very simple component has a property named currentValue , which is incremented every 5 seconds by a simple interval.

Now imagine that there are two instances of ComponentAnamed instance1_mc and instance2_mc on the Stage of a sample application.

Now imagine that a main.asc script wants to be notified whenever currentValue of instance1_mc gets updated. In other words, the script would like to catch the event represented by the property change of currentValue . Here's how you could write your main.asc :

 load("components.asc"); load("ComponentA.asc"); var listenerObj = new Object( ); listenerObj.onPropertyChange = function (p_eventSource, p_eventData) {   trace("onPropertyChange: " + p_eventSource.name + "."       + p_eventData.name + " is now "       + p_eventData.newValue + " (was "       + p_eventData.oldValue + ")"); }; ComponentA.instances.instance1_mc.addListener("currentValue", listenerObj); 

First we load the component; then we set up an event catcher (listener) object, with an onPropertyChange( ) method defined on it. Finally, we tell the framework that we want to listen to changes of the property called "currentValue" on the instance1_mc instance of the ComponentA class (note the uses of the static instances property).

Now whenever currentValue is updated, the onPropertyChange( ) method of listenerObj will be triggered, with two parameters. The first, p_eventSource , is a reference to the component instance instance1_mc , so that you could call methods on it or check other properties of it.

The second, more interesting parameter is an object with three properties:


name

The name of the property that changed (you can use the same listener object for more than one property)


oldValue

The old value of the property that changed


newValue

The new value of the property that changed

What if you wanted to listen to changes of currentValue in both instances of ComponentA?

You could do this to listen to both the instance1_mc and instance2_mc instances:

 ComponentA.instances.instance1_mc.addListener("currentValue", listenerObj); ComponentA.instances.instance2_mc.addListener("currentValue", listenerObj); 

Or you could use another syntax provided by the framework. The following triggers onPropertyChange( ) on listenerObj whenever the currentValue property changes in any instance of ComponentA. This is also handy when you don't know the names of the instances of a certain component (when this syntax is used, listenerObj is known as a "class-wide listener"):

 ComponentA.addListener("currentValue", listenerObj); 

The framework also provides the sendUserEvent( ) method so you can throw your own custom events, as shown here, instead of just automatically triggering onPropertyChange( ) on the listener objects:

 chat1.onMyFooEvent = gOnEvent; chat1.onMyBarEvent = gOnEvent; cursor1.addListener("MyFooEvent", chat1); FCCursor.addListener("MyBarEvent", chat1); cursor1.sendUserEvent("MyFooEvent", "Hello Foo"); FCCursor.sendUserEvent("MyBarEvent", "Hello Bar"); 

These two mechanisms for throwing and catching events should be powerful enough to be used within your scripts or your other components. Nonetheless, more and more Flash developers are standardizing on the EventDispatcher class ( mx.events.EventDispatcher ), a client-side class introduced with the v2 UI components architecture. The class is small, clean, and elegant. An explanation of the EventDispatcher class is out of the context of this book, but you can find a lot of documentation about it online. Example 14-9 provides a port of the EventDispatcher class to Server-Side ActionScript for you to use in your server-side code. Note that the "@param" syntax used in some of the comments is used by JavaDoc to automatically generate documentation.

Example 14-9. Server-side port of the EventDispatcher class
 /* EventDispatcher  * ported to ASC by Giacomo 'Peldi' Guilizzoni - http://www.peldi.com/blog/  */ EventDispatcher = function ( ) { }; // Internal function for removing listeners EventDispatcher.prototype._removeEventListener = function (queue, event, handler) {  if (queue != undefined) {     var l = queue.length;     var i;     for (i = 0; i < l; i++) {        var o = queue[i];        if (o == handler) {          queue.splice(i, 1);          return;        }      }   } }; // Make it static by attaching it directly to   EventDispatcher   EvenTDispatcher._removeEventListener =    EventDispatcher.prototype._removeEventListener;   /* Add listening and dispatching methods to an object  * @param object - the object to receive the methods  */ EventDispatcher.prototype.initialize = function (object) {   // This part of the original client-side EventDispatcher code is not used in SSAS.   /* Creating the instance at the bottom instead   if (_fEventDispatcher == undefined) {     _fEventDispatcher = new EventDispatcher( );   }*/   object.addEventListener = _fEventDispatcher.addEventListener;   object.removeEventListener = _fEventDispatcher.removeEventListener;   object.dispatchEvent = _fEventDispatcher.dispatchEvent;   object.dispatchQueue = _fEventDispatcher.dispatchQueue; }; // Make it static EventDispatcher.initialize = EventDispatcher.prototype.initialize; // Internal function for dispatching events EventDispatcher.prototype.dispatchQueue = function (queueObj, eventObj) {   var queueName = "__q_" + eventObj.type;   var queue = queueObj[queueName];   if (queue != undefined) {     var i;     // Loop it as an object so it resists people removing listeners during     // dispatching     for (i in queue) {       var o = queue[i];       var oType = typeof(o);       // A handler can be a function, object, or movie clip       if (oType == "object"  oType == "movieclip") {         // This is a backdoor implementation that         // is not compliant with the standard         if (o.handleEvent == undefined) {           o[eventObj.type](eventObj);         }         else {  // This is the DOM3 way           o.handleEvent(eventObj);         }       }       else {   // It is a function         o.apply(queueObj, [eventObj]);       }     }   } }; /* Dispatch the event to all listeners  * @param eventObj - an instance of   Event   or one of its subclasses  *                    describing the event  */ EventDispatcher.prototype.dispatchEvent = function (eventObj) {   if (eventObj.target == undefined)     eventObj.target = this;   if (this[eventObj.type + "Handler"] != undefined)     this[eventObj.type + "Handler"](eventObj);   // Dispatch to objects that are registered as listeners for this object.   this.dispatchQueue(this, eventObj); }; /* Add a listener for a particular event  * @param event - the name of the event ("click", "change", etc.)  * @param handler - the function or object that should be called  */ EventDispatcher.prototype.addEventListener = function (event, handler) {   var queueName = "__q_" + event;   if (this[queueName] == undefined) {      this[queueName] = new Array( );   }   // Not supported in SSAS so comment it out. We don't need it.   //_global.ASSetPropFlags(this, queueName,1);   EventDispatcher._removeEventListener(this[queueName], event, handler);   this[queueName].push(handler); }; /* Remove a listener for a particular event  * @param event - the name of the event ("click", "change", etc.)  * @param handler - the function or object that should be called  */ EventDispatcher.prototype.removeEventListener = function (event, handler) {   var queueName = "__q_" + event;   EventDispatcher._removeEventListener(this[queueName], event, handler); }; _fEventDispatcher = new EventDispatcher( ); 



Programming Flash Communication Server
Programming Flash Communication Server
ISBN: 0596005040
EAN: 2147483647
Year: 2003
Pages: 203

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net