Section 11.2. Remoting Basics


11.2. Remoting Basics

All of the processing and conversion of AMF is handled internally by the FlashCom Server (or Flash Player) and the Flash Remoting gateway, so you never have to deal with it. The NetConnection class, the base class for RTMP communications, also serves as the foundation for Remoting. A NetConnection instance on the client provides the developer interface to create the binary data and transmit it to the destination server.

Let's start with a simple example in which the Flash Player is the client. You could also run this example script inside a FlashCom application if the path to the imaginary service were correct. Example 11-1 shows how to use a NetConnection object to call a remote method on an application server with the remoting gateway installed.

Example 11-1. Flash Remoting with NetConnection
 my_conn = new NetConnection(  ); my_conn.connect("http://localhost/flashservices/gateway"); response = new Object( ); response.onResult = function (result) {   trace(result); }; my_conn.call("services.TestService.dataEcho", response, "test message"); 

The first two lines should look familiar to anyone building a FlashCom connection. In this case, the URI passed to the connect( ) method refers to the remoting gateway that comes bundled with ColdFusion residing on the local host. Unlike an RTMP connection, the call to connect( ) does not actually make a connection to the server, so the call will always return TRue . Internally, the client (in this case, the Flash Player) checks the protocol used for the connection. If the protocol is rtmp:// , rtmpt:// , or rtmps:// , the Flash Player immediately tries to establish a socket connection with the remote host, and the connect( ) method returns a Boolean value indicating whether the URI is valid. If the protocol is unspecified or is anything other than rtmp , rtmpt , or rtmps , the Flash Player doesn't try to make a connection to the remote host and always returns true .

The next segment of code creates a response object (also known as a responder ), named response , with an onResult( ) method to handle the response to the remote method call. When the server sends back a response, the Player automatically calls the onResult( ) method of the specified object and passes the results as a single argument. Within this body of this method is where you would either process the result or forward the result to another object for processing.

The final line uses NetConnection.call( ) to invoke the remote procedure, using the following format:

 NetConnection.call(   remoteMethod   ,   resultObject   null [, p1, ...p   n   ]) 

The remoteMethod parameter is a dot-delimited path to the file, in which the method name is the last part of the string. Depending on the server configuration, the full path from the server root will have to be specified. The remote method format is:

   topfolder.subfolder.file_no_extension.method   

In Example 11-1, remoteMethod is "services.TestService.dataEcho". This means that the remote method named dataEcho( ) exists in a file named TestService.cfc (for ColdFusion) within a directory named services , which resides in the server root directory.

The resultObject parameter is the object that receives the results from the remote call. If the object has an onResult( ) method defined, it receives a single argument containing results returned by the remote method. If the remote method fails for any reason, the onStatus( ) method, if any, is called instead of onResult( ) . The onStatus( ) method receives a single argument, an information object, which has a minimum of three properties: level , code , and description . These properties describe the nature of the error as well as a description of the problem. If the remote procedure does not return any results or you do not need to receive the results, you can pass null as resultObject .

In Example 11-1, resultObject was the response object previously created. The response object's onResult( ) handler simply traces the results returned from the remote method. The response object did not define an onStatus( ) method and therefore will ignore any errors returned by the method call.

The last group of arguments, (p1,...pn) , are the optional parameters to supply to the remote method. In Example 11-1, the only argument was a string with the value "test message".

11.2.1. Remoting Classes

Flash Remoting offers features beyond the ability to perform remote method calls. Remoting supports pageable recordsets, session management, adding and responding to special headers, and more. The Flash Remoting components bring even these advanced features, such as navigating through a pageable recordset, to all Flash developers. The components hide the underlying implementation and make implementing a remoting connection easier.

Although the Flash Remoting components include many classes, the NetServices and RecordSet classes are used for almost every remoting application. NetServices is the main interface for creating remoting connections. The RecordSet class represents the results from a database query and provides the implementation to manipulate and negotiate pageable recordsets. The components were originally developed for Flash MX and ported over for FlashCom, so the code to communicate with a remote service can be used in both environments with little or no modifications (client-side ActionScript 1.0 and Server-Side ActionScriptequivalent to JavaScript 1.5are very similar).

11.2.1.1 Google web service

Let's see how to use the Remoting classes to accomplish some common goals. Example 11-2 shows how to consume the Google web service with the NetServices package, allowing you to add a Google search capability to your application. This example assumes that you have Flash Remoting installed and configured to accept web services. The client-side ActionScript in the example should be entered in the first frame of the Actions layer of a Flash movie. Look over the code, and we'll discuss it momentarily.

Example 11-2. Implementing the Google search web service
 // To run this example from a FlashCom appication,  // use   load("netservices.asc")   instead of   #include "NetServices.as"   . #include "NetServices.as" // To run this example from a FlashCom appication, wrap the rest of this // example in an   application.onAppStart( )   function. NetServices.setDefaultGatewayUrl("http://localhost/flashservices/gateway"); my_conn = NetServices.createGatewayConnection( ); GoogleService = my_conn.getService("http://api.google.com/GoogleSearch.wsdl", this); this.doGoogleSearch_Result = function (data) {   trace("we have data");   searchdata = data; }; this.doGoogleSearch_Status = function (error) {   for (var i in error) {     trace(i + " : " + error[i]);   } }; // You need to insert your Google developer key as a string for the   key   property. params = {   key:"   Your developer key goes here   ",   q:"amfphp",   start:0,   maxResults:10,   filter:true,   restrict:"",   safeSearch:false,   lr:"",   ie:"UTF-8",   oe:"UTF-8" } GoogleService.doGoogleSearch(params); 

As in the first line of the example, you must include NetServices.as to use the Flash Remoting components. This loads the NetServices class and several other classes. In a FlashCom application, the SSAS syntax to load the NetServices class is:

 load ("netservices.asc"); 

The setDefaultGatewayUrl( ) method provides a means to set a URL to use for all calls to createGatewayConnection( ) . The createGatewayConnection( ) method also accepts a URL that overrides the default gateway URL.

You can use either of the following to create the gateway connection:

 NetServices.setDefaultGatewayUrl("http://localhost/flashservices/gateway"); my_conn = NetServices.createGatewayConnection( ); 

or:

 my_conn = NetServices.createGatewayConnection(              "http://localhost/flashservices/gateway"); 

Using setDefaultGatewayUrl( ) to set the default gateway avoids having to specify the connection path every time you create a gateway connection with createGatewayConnection( ) .

The createGatewayConnection( ) method returns a NetConnection object that is used to communicate with the remote server. (The NetServices.as file adds several remoting-specific methods to the NetConnection class.) You must assign the results of createGatewayConnection( ) to a variable, or the connection object will be destroyed ; it is not cached locally within the NetServices class.

The getService( ) method, one of the methods of NetConnection added by NetServices.as , builds and returns an object that acts as a proxy to the remote service definition:

 myService = NetConnection.getService(   serviceName   [,   responseObject   ]); 

The serviceName parameter is the path to the service definition for the remote server. Its format is the same as the first parameter for the NetConnection.call( ) method without the method name included in the string. In Example 11-2, its value is "http://api.google.com/GoogleSearch.wsdl".

The responseObject is the object that should respond to all methods called through this service object. This parameter is optional, and in most applications not practical. Typically, unless there is a specific reason to do so, using a single object to respond to all remote calls will end in an unnecessarily complicated result definition. Instead, you'll usually implement separate responders for each method called through the service.

Example 11-2 shows one way to handle the results of a remote method invocation. The doGoogleSearch_Result( ) method handles the results returned by the call to doGoogleSearch( ) (The Flash Remoting components automatically look for a handler of the same name with "_Result" appended for this purpose.) The example simply traces a message stating that results were returned by the call and stores the result data in a variable named searchdata . You can use the Debug List Variables command in the Flash authoring tool's Test Player to inspect the format of the returned results. The NetConnection Debugger, discussed in Chapter 3, is also useful for analyzing data transmitted via Flash Remoting.

The doGoogleSearch_Status( ) method is triggered if the service returns any errors (again, Flash automatically looks for a handler of the same name with "_Status" appended for this purpose). We will come back to handling errors later; the method here simply traces the error message if something goes wrong.

Finally, the remote method is executed. The Google web service requires many parameters, which are passed in a single parameters object. The two important properties of the parameters object are key and q . The key property is a required string assigned to each developer. A developer obtains a key by registering to use the Google search web service at http://www.google.com/apis. The q property is the string for which you want to search. The other parameters manipulate how the search is processed and returned. Consult Google's documentation at the preceding URL for details of each parameter. Finally, doGoogleSearch( ) is invoked on the GoogleService service to execute the remote procedure.

11.2.1.2 Services

The syntax to access remote services varies slightly depending on the Flash Remoting gateway version (ColdFusion, Java, .NET, etc.). Furthermore, the types of services available via Remoting vary slightly as well. For example, accessing a remote web service via Java or JRun requires a wrapper, which is not necessary with ColdFusion or .NET. Once connected to a service, however, the service's methods are accessed from the client code in a uniform way that is independent of the Flash Remoting gateway or the server-side technology implementing the remote services.

To provide access to its services, the remote application server supports a service class , which provides access to one or more remote methods. The techniques required to define a service class vary, so check the documentation of your server (ColdFusion, .NET, Java, etc.) or consult Flash Remoting: The Definitive Guide . For our purposes, we assume you have created a remote application and properly configured your application server to allow remote access to it.

Connecting to a remote service class (or simply a service) is accomplished by supplying the service's dot-delimited path to the getService( ) method. This path is typically the full path from the web root of the server. Some server implementations such as ColdFusion, JRun, and AMFPHP provide a mechanism to specify a classpath or a service directory, in which case the service path supplied can be relative to that location.

The syntax for most of the remote services requires that you omit the file extension of the service class file. For example, here, we omit the .cfml or .cfc extension of a ColdFusion service:

 UtilityService = my_conn.getService("cfcs.jwatkins.CommonUtils"); 

Web services are supported by many of the remoting implementations. Example 11-2 illustrated how to connect to the Google search web service. Connecting to a web service is as simple as specifying the .wsdl file as the service name passed to getService( ) :

 TempService = my_conn.getService(            "http://www.xmethods.net/sd/2001/TemperatureService.wsdl"); 

A single connection object can be shared for all services located at a gateway URL.

Flash Remoting calls are batched together when the Flash client makes multiple remote calls on the same frame or when FlashCom makes multiple remote calls from within the same function. When calls are batched, you do not receive a response from any method calls until all of the remote methods have finished.


The following two remote calls are batched together even though one is mapped to a local service class and the other is a web service. The results are not returned from the remoting server until both of the methods have completed processing:

 someFunction = function (  ) {   NetServices.setDefaultGatewayUrl("http://localhost/flashservices/gateway");   my_conn = NetServices.createGatewayConnection(  );   UtilityService = my_conn.getService("cfcs.jwatkins.CommonUtils");   TempService = my_conn.getService(            "http://www.xmethods.net/sd/2001/TemperatureService.wsdl");   UtilityService.searchString(needle, haystack);   TempService.getTemp("61310"); }; 

This automated batching of remote calls is an important issue that may impact your implementation of performing remote calls. If a remote method takes a long time to execute or returns a large amount of data, it will slow other processes down. So you should ensure that such methods execute separately from other methods. This can be accomplished by chaining the remote calls (i.e., waiting for the results of one before executing another) or by using separate connection objects for each method call. Here is an example using separate connections:

 someFunction = function (  ) {   NetServices.setDefaultGatewayUrl("http://localhost/flashservices/gateway");   my_conn1 = NetServices.createGatewayConnection(  );   my_conn2 = NetServices.createGatewayConnection( );   UtilityService = my_conn1.getService("cfcs.jwatkins.CommonUtils");   TempService = my_conn2.getService(            "http://www.xmethods.net/sd/2001/TemperatureService.wsdl");   UtilityService.searchString(needle, haystack);   TempService.getTemp("61310"); }; 

11.2.1.3 Methods

Once you've established a connection and created a service object, you can make calls on that object to access methods of the service. The getService( ) method returns a proxy object to the service. The proxy object uses the NetConnection.call( ) syntax internally but provides a familiar way to invoke a remote method. The syntax to call a remote method is similar to any other method invocation:

 serviceProxy.   methodname   ([   responseObject   ] [,   arg1   , ...arg   n   ]) 

The first parameter, responseObject , is an optional response object, which overrides the default response object passed to the getService( ) method. This approach allows you to use different responders for each method call instead of using the same handler for all methods invoked on the service. In most situations, this is the preferred approach. It lets you handle the results differently for each type of method invoked, or even for each invocation of a given method.

If the first argument is an object defining an onResult( ) method, Flash strips it from the argument list passed to the remote service and uses it as a response object instead (the response object parameter is not passed to the remote method).

However, if you set a response object via getService( ) and attempt to specify another response object when invoking a remote function, it won't work. The response object will be passed as a parameter to the remote function instead of being stripped out of the argument list. See "Creating Responder Functions" in Chapter 4 of Flash Remoting: The Definitive Guide for many more details.


The remaining parameters in the remote method invocation are the arguments that the remote method expects. You can pass the arguments in two ways. The first approach is to pass the parameters as individual arguments separated by commas. Here is an example in which the optional response object is included as the first parameter:

 serviceProxy.someMethod(someResponseObj, "one", "two", "three"); 

Here is the same method invocation without the optional response object:

 serviceProxy.someMethod("one", "two", "three"); 

Passing unnamed parameters is similar to how parameters are passed when invoking any ActionScript method, and the names of the parameters do not need to be known to the client. However, the order that the remote server expects the arguments must be known to and observed by the client code. Normally with remote methods that require a single or only a few parameters, this is not an issue. But with remote methods that require many parameters, such as the Google search service, this can be a major source of problems.

The second approach is to wrap all of the parameters into a single object as name/value pairs and pass the object as the only parameter (besides the optional response object, not used in this example):

 params = {one:"one", two:"two", three:"three"}; serviceProxy.someMethod(params); 

The major advantage to this approach is that the order and number of the arguments becomes irrelevant because they are named values. The disadvantage is that the client must know the names that the server expects for each parameter.

Not all implementations of the Flash Remoting gateway support passing the arguments as properties of a single object. Check your remoting implementation's documentation.


11.2.1.4 Handling results

You have already been introduced to two ways to handle a response to a remoting call: using a methodname_Result ( ) method or using an onResult( ) method attached to a response object. Both approaches handle the results in the same manner.

To handle the results with methodname_Result ( ) , simply define a function using the same name as the remote method call and append "_Result" to the end:

 doGoogleSearch_Result = function (data) {   trace(data); }; 

This approach is the easiest to implement. If you do not pass a default responder to the getService( ) method, the response methods must be defined in the same scope as the service proxy object. However, if you specify a default responder to getService( ) , the response methods must be defined as methods of that object.

To handle the results with an onResult( ) method, you must define an object with an onResult( ) method and register that object as the responder. You can either pass the object to the getService( ) method:

 responder = new Object(  ); responder.onResult = function (data) {   trace(data); }; myService = my_conn.getService("AuthenticationService", responder); 

or you can pass the object as the first parameter of the remote method call:

 myService.authenticateUser(responder, "jwatkins", "abcd"); 

If you aren't very comfortable using objects, the methodname_Result ( ) approach allows you to handle results by simply defining functions with the appropriate names. If you are comfortable with object-oriented programming, you can also implement the methodname_Result ( ) approach by designing a class to handle the results from the remoting calls. You can create all of the response methods in the class and pass an instance of the class as the default response object to the getService( ) method:

 function ResultsClass (  ) {...} ResultsClass.prototype.method1_Result = function ... ResultsClass.prototype.method2_Result = function ... myService = my_conn.getService("TestService", new ResultClass( )); 

There are several drawbacks to using methodname_Result ( ) , however. Because the response handler's name depends on the remote function's name, you must define separate _Result handlers for each method. Furthermore, if the name of a remote function changes, you must change the name of its corresponding _Result handler.

Using an onResult( ) method instead of a _Result handler is cleaner from an object-oriented standpoint. Simply pass an object that defines an onResult( ) method. The object can be either an anonymous object or an instance of a class. This approach makes it easier to share response-handling logic across different remote calls; you can pass the same response object to several remote methods or set up one object as the default responder and override it when necessary.

The NetServices package dispatches the onResult event from a remote call in the following order, stopping when it finds an appropriate handler:

  1. First, it looks for a function named methodname_Result ( ) defined on the response object or the current timeline.

  2. Otherwise, if a response object with an onResult( ) method was specified in the call to getService( ) , results are sent to that onResult( ) method.

  3. Otherwise, if the first argument passed to the remote method invocation is an object that defines an onResult( ) method, results are sent to that onResult( ) method.

  4. Otherwise, if the movie is playing in the authoring environment, results are sent to the Output window.

  5. Otherwise, the results are lost.

Using the onResult( ) approach is also slightly faster. When you do not specify an object with an onResult( ) method, the NetServices classes have to create an additional object to handle the results from the server and forward the request to the methodname_Result ( ) method.

A bug in the NetServices class prevents responder objects with an onResult( ) method from working as expected. This bug existed in prior versions but is fixed in the Updater 2 for FlashCom 1.5.


If you prefer to name your response handler something other than onResult( ) , Example 11-3 defines a custom class that forwards the results to an object and method name of your choosing. The class defines an onResult( ) method that calls the object and method name originally passed to the RelayResponder class constructor.

Example 11-3. Using a RelayResponder
 #include "NetServices.as" NetService.setDefaultGatewayUrl("http://localhost/flashservices/gateway"); function RelayResponder (targetObject, targetMethod) {   this.targetObject = targetObject;   this.targetMethod = targetMethod; } RelayResponder.prototype.onResult = function (data) {   this.targetObject[this.targetMethod](data); }; function FictionalDataClass ( ) { } var o = FictionalDataClass.prototype; o.getData = function ( ) {   this.conn = NetServices.createGatewayConnection( );   this.service = this.conn.getService("DataService");   this.service.getData(new RelayResponder(this, "receiveData")); }; o.receiveData = function (data) {   trace("The request was forwarded here"); }; myData = new FictionalDataClass( ); myData.getData( ); 

11.2.1.5 Handling errors

Up to this point, we have assumed that everything will always work, which is unfortunately not the case during either development or production. When relying on an external resource to perform processing, the external resource may change or be unavailable, or parameters that were once valid may no longer be valid. Remoting has the capability to alert the client that something has gone wrong and provide additional details that may help determine what has happened .

If a remote server fails to process a call, it returns an error object and invokes a status method (in this case, "status" is a euphemism for "error"). Regardless of how you handle the error message, which depends on how you defined your response object, Flash Remoting always passes a single error object to the status method. The error object returned by the remote server includes level and description properties specifying the error severity and an explanation of why the server couldn't perform the request. The values of these properties, while not always completely accurate, are invaluable in debugging the error.

If you use the methodname_Result ( ) approach for your responder, you should specify a methodname_Status ( ) function to catch any errors. There are still yet other options, however. The NetServices package dispatches the onStatus error from a remote call in the following order, stopping when it finds an appropriate handler:

  1. First, it looks for a function named methodname_Status ( ) defined on the response object or the current timeline.

  2. Otherwise, if a response object with an onStatus( ) method was specified in the call to getService( ) , status errors are sent to that onStatus( ) method. (If you pass a response object with an onResult( ) method as the first parameter to the remote method call, an onStatus( ) method is called only if it is attached directly to the response object. If you pass such a response object to each remote method call, the handlers cited in Steps 3 and 4 are never called.)

  3. Otherwise, the _root.onStatus( ) method, if any, is used.

  4. Otherwise, the _global.System.onStatus( ) method, if any, is used.

  5. Otherwise, if the movie is playing in the authoring environment, results are sent to the Output window.

  6. Otherwise, the results are lost.

In many situations, there is not any meaningful action that the client can take to correct the problem at runtime. Depending on the application, you may simply report the error to the user , stating that the remote service is unavailable. In other cases, the error can be corrected by adjusting the parameters that are sent to the remote server. At other times, intermittent connection errors, such as with HTTP calls, can be solved by simply trying again. When an HTTP call fails in Breeze Live, the application typically retries it five times at 1-second intervals. (You should avoid being so aggressive in retrying as to create an inadvertent denial-of-service attack.)

11.2.2. Passing Datatypes

All the basic ActionScript datatypes can be passed through AMF with remoting. A remote server can interact with the passed datatype using its native syntax. The actual translation of datatypes varies by remoting implementation; consult Flash Remoting: The Definitive Guide or your remoting gateway documentation to see how each datatype is deserialized on the server. Passing most ActionScript datatypes requires no configuration or additional code; all you need to do is pass the variable as a parameter to the remote method.

11.2.2.1 Custom classes

You can also send and retrieve an instance of a custom class with Flash Remoting. Some remoting implementations allow you to have a definition for the class available on the server side and have the class restored as an instance of the server-side class. Likewise, you can receive an instance of a custom class and have it constructed back to an instance of the class available in the client code.

Passing an instance of a custom class is a useful tool. Using methods instead of accessing properties directly is an excellent way to hide the internal implementation of the data and is the most flexible approach in case the data structure changes in the future. Any code that accesses the data will not need to be modified if it uses the methods to access the data ( assuming the method definitions are updated correctly). You could also define methods that create unique displays of the data. For example, you could have a firstName and lastName property in the data and have a method that returns the full name as follows :

 DataClass.prototype.getName = function (  ) {   return this.firstName + " " + this.lastName; }; 

The getName( ) method simply returns the firstName and lastName properties joined together with a space. Using such a method is easier than joining the two properties together every time the name needs to be displayed or used in this format.

Having the custom class defined does not automatically deserialize the passed object as an instance of the class. In a FlashCom application, you also need to register the class using application.registerClass( ) :

 application.registerClass(   className   ,   constructor   ); 

The className parameter is the name of the class as a string. The constructor property is the physical function that should be used to reconstruct the instance of the class object.

 function myClass (  ) {} application.registerClass("myClass", myClass); 

This example will register the class myClass as a class that can be deserialized.

Setting properties in the constructor will break any deserialized data!


11.2.2.2 Recordsets

Databases are common tools for storing and organizing data. Databases are also very scalable in terms of performance and the amount of data that can be stored. Often an application will require the use of a database, and FlashCom cannot access a database without Flash Remoting.

RecordSet is a special custom class available in the NetServices package. The RecordSet class represents the query results from a database. Using RecordSet provides many methods to access query results and control how the results (known as a recordset or result set) are returned from the server. The remote server can interface directly with a database by executing either SQL code or stored procedures. The server returns the query results back to the client (in this case, FlashCom). In the FlashCom application, the results can be constructed into an instance of the RecordSet class as shown in Example 11-4.

Example 11-4. RecordSet example
 load("netservices.asc"); application.onAppStart = function ( ) {   NetServices.setDefaultGatewayUrl("http://www.myhost.com/flashservices/gateway");   var conn = NetServices.createGatewayConnection( );   var dataService = conn.getService(                      "com.oreilly.pfcs.chapter11.PlayListService");   var response = new Object( );   response.onResult = function (result) {     application.playList = result; // Save the playlist to a persistent scope     application.outStream = Stream.get("radiochannel"); // Get a live stream     var l = result.getLength( );                    // Get the recordset length     for (var i = 0; i < l; i++) {       var record = result.getItemAt(i);       // Use the filename from the recordset.       application.outStream.play(record.filename,          record.starttime,                  // Get the start time from the recordset         record.length,                     // Get the length from the recordset         false);                            // Add each record to the playlist     }   };   response.onStatus = function (info) {     trace("The PlayListService is unavailable right now");     for (var i in info) trace(i + " : " + info[i]);   };   // Invoke the method to retrieve the recordset.   dataService.GetPlayList( ); }; 

Example 11-4 assumes that a database table stores the following columns : name , filename , starttime , and length . It uses remoting to retrieve the list of tracks to play and builds a server-side playlist with the Stream object. This example also shows one simple way to interact with recordset data in your application. The most commonly used methods of the RecordSet class are getLength( ) and getItemAt( ) . The getLength( ) method counts the number of records returned by the remoting service, which you can use to loop through the results. The getItemAt( ) method returns the record at the specified index (zero-relative). The returned record is an object with the database columns as the properties. You can retrieve a list of the column names returned by the query with the getColumnNames( ) method. This method returns an array of strings that correspond to the column names.

The results from the server can be broken up into smaller batches and distributed to the client in several ways, as controlled by the RecordSet.setDeliveryMode( ) method. The three modes are "ondemand", " fetchall ", and "page". By default, recordsets operate in fetchall mode, in which all of the results are returned in a single batch. Pageable recordsets can be sent entirely in one batch, sent in multiple smaller batches, or stored on the server until the desired record is requested . For many scenarios, using pageable recordsets is not necessary. Often there are other solutions to limit the amount of data that needs to be displayed. However, there are times when the amount of data is just too large to transfer and display at once.

You can enable recordset paging in ondemand mode by passing a pagesize property in the parameters object when you call the remote method:

 params = new Object(  ); params.pagesize = 5; my_service.getData(params); 

In ondemand mode, only the specified number of records is returned to the client. The remaining records are returned on an as-needed basis when you call getItemAt( ) . If the results contained 50 records and you set the initial page size to 5, if you try to access a record between 6 and 50, the record will need to be fetched from the server. In ondemand mode, the client fetches only a single record when it is requested. You cannot immediately access a record that is still residing on the server after calling getItemAt( ) . You must wait for the server to return the results, which causes it to issue a modelChanged event. If the record still needs to be loaded, the getItemAt( ) method will return the string "in progress". If the record has already been downloaded, you can access the record immediately.

 listener = new Object(  ); listener.modelChanged = function (eventObj) {   // This event is triggered when the data changes. }; my_rs.addView(listener); 

At any time during the ondemand mode, you can change the delivery mode to either fetchall or page using setDeliveryMode( ) . Changing the mode to fetchall requests the server to return the remainder of the recordset in a single batch or optionally in smaller batches. You can set fetchall mode as follows:

 my_rs.setDeliveryMode("fetchall"[, pagesize]); 

Using the same scenario of a 50-record result set, the request mechanism will request only pagesize records at a time until all of the records have been downloaded. If the resultset is large, breaking it up into smaller batches allows the client to display the records that have been downloaded without waiting for the entire resultset.

The page delivery mode is somewhere between ondemand and fetchall. It delivers records when they are requested but optionally returns more than a single record. You can set page mode as follows:

 my_rs.setDeliveryMode("page", pagesize[, prefetch]); 

Setting the mode to "page" sets a delivery mechanism similar to how most search engines work. When you perform a search, the engine returns a limited number of results with the ability to navigate through the additional results. Each set of results returned by the search engine is a page. The pagesize parameter determines how many records should be listed in each collection, and the prefetch parameter determines how many total pages should be downloaded additionally, so they are cached and ready to access.

If you set the mode to "page" after receiving the first five records, the client requests additional records only when you use getItemAt( ) to try to access a record that still resides on the server. If you request a record that has not been loaded locally, the server returns a full page of records starting at the index passed to getItemAt( ) plus the additional number of complete page collections specified by prefetch . To calculate the total number of records that could be downloaded, multiply pagesize by prefetch + 1. This example downloads 15 records every time a record that has not been previously fetched is requested:

 my_rs.setDeliveryMode("page", 5, 2); 

Using page mode is an effective way to manage extremely large results. If the number of returned records is in the thousands, using a paged view of the data will make navigating and interacting with the data an easier task.

Each delivery mode has benefits and drawbacks.

Using fetchall mode to send the data in a single batch is the easiest for the server to perform because it doesn't have to allocate additional memory to store the server-cached records. The fetchall mode uses the least overall bandwidth if you are going to need the entire result set, because only two communicationsthe client request and the server resultstake place. Being able to break the fetchall process into smaller pages makes displaying records to the client faster as well. However, fetchall mode does not work well for very large result sets because it is difficult for the client application and end user to process large amounts of data. It is also wasteful if all the records in the result set are not needed.

The ondemand mode works great for applications in which only one record is viewed at a time. For example, if you have an application that displays contact information, the ondemand mode will minimize the amount of bandwidth necessary to display a single record from a result set. However, if you need to retrieve all the records in a result set, ondemand mode uses the most bandwidth because there is one request and one response for each record. The ondemand mode also consumes additional server memory and processing to store the cached results.

The page mode is effective for displaying smaller groups of results. This usually applies when you are performing a search function and need to show the end user multiple records simultaneously for faster browsing but need to limit the number of records displayed for simplicity and performance reasons. Like ondemand mode, page mode requires additional server memory to store the cached results.

11.2.3. Action Message Format

While AMF is a compact format, it is still important to understand the size implications of each datatype. AMF is used both in remoting and when you embed data into a NetStream . It also is the basis for the format of data stored in shared objects. Since data embedded in a stream has the highest priority and is never dropped, it is important to understand how the size of the data can force a client on a slower connection to drop video and even audio frames .

All AMF packets sent with remoting contain five parts :

  • Packet version header

  • Header count

  • Array of header messages

  • Body message count

  • Array of body messages

The version, header count, and body count add 6 bytes to the packet. The header and body messages vary by the count and the data contained in each. Each type of object passed over AMF carries its own overhead in bytes. The byte counts in Table 11-1 include a 1-byte flag (indicating the datatype) that precedes the data for each type.

Table 11-1. AMF datatypes and byte count

Datatype

Byte count

null

1

undefined

1

Boolean

2

Number

9

Date

10

String

2 + string length

XML

5 + XML.toString( ).length

Array

5 + ( n for each array index value)

Object

4 + (2 + string length for each property name) + ( n for each property value)

Associative array

8 + (2 + string length for each property name) + ( n for each property value)

Custom class

6 + class name length + (2 + string length for each property name) + ( n for each property value)


The table is sorted by byte count to help you manage bandwidth usage, but of course the exact bandwidth varies by the contents of complex datatypes, such as arrays.

As illustrated in Table 11-1, passing the number 1 adds 7 more bytes to the packet than passing the Boolean true ; they are not equivalent! If both the client and server implementations can handle sending and receiving Boolean values, using a Boolean instead of a number can save precious bytes. Of course, multiple Boolean values can be coded as bits in a single number and decoded using bitwise operators.


It is not usually necessary to pay such granular attention the number of bytes in an AMF packet when dealing with remoting from a FlashCom application, since the connection from server to server is usually very fast. It becomes more important to consider the impact of the data packets when you are embedding data into an audio and video stream or when managing SharedObject data.



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