ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
Flash Remoting & FlashCom Server
http://www.actionscript.org/resources/articles/581/1/Flash-Remoting--FlashCom-Server/Page1.html
ActionScript.org Staff
The http://ActionScript.org Staff are Jesse Stratford and Evgueni Strok. The original founders of this site in 2000, Strok and Jesse live thousands of miles from each other and have never met in person...
 
By ActionScript.org Staff
Published on April 20, 2007
 
In this excellent article extracted from O'Reilly's Programming Flash Communication Server (Chapter 11), the authors delve into Flash Remoting and highlight it's role in Flash Communication Server applications. A great read even for non-FlashCom people who want to learn about Flash Remoting.

Flash Remoting & FlashCom Applications

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

Table of Contents

11.1. The Remoting Gateway
11.2. Remoting Basics
11.2.1. Remoting Classes
11.2.2. Passing Datatypes
11.2.3. Action Message Format
11.3. Role of Remoting in FlashCom Applications
11.4. Securing Access
11.5. Conclusion

Server-Side ActionScript (SSAS) supported by FlashCom 1.5.2 does not offer all the same features as client-side ActionScript. SSAS does not support the LoadVars or XML " name="progflashcs-CHP-11-ITERM-3596">Flash Remoting to communicate with an application server to accomplish these necessary tasks.

Flash Remoting has two parts: the client-side API used to create a connection to an application server and a server gateway that acts as the bridge between the client logic and the application server. The client-side APIs are built into the FlashCom Server as well as the Flash Player. This chapter discusses the entire Flash Remoting process but will focus on the client-side API used to connect to the application server. Throughout this chapter, the term client refers to either a SWF running in the Flash Player or a FlashCom application. That is, when using Flash Remoting with FlashCom, the FlashCom Server acts as the client. The techniques provided are valid for either situation.

The Remoting Gateway

The rest of this chapter focuses on the client code and techniques used in Flash Remoting, but let's take a moment to discuss the entire process. Flash Remoting enables you to make a request to the application server, have the server process the data using business logic, and return the results back to the client. The request/response system of Remoting works similarly to the technique of calling a remote FlashCom method, as discussed in Chapter 9. The process is asynchronous as well, so the results are not immediately returned but trigger an event in the client. However, unlike FlashCom remote methods, Flash Remoting calls use a non-persistent connection and use the HTTP protocol to communicate. Instead of sending RTMP data over the network, Remoting uses Action Message Format (AMF).

AMF is a binary message format modeled after SOAP, a protocol designed to exchange structured data in a distributed environment. SOAP uses XML tags to describe and package data and was designed to be abstract and versatile, which unfortunately resulted in the schema being complex and verbose. AMF was designed to be an efficient, compact format to pass ActionScript datatypes over the network. AMF uses binary flags to describe and package data. An AMF packet will always be smaller than an equivalent SOAP packet, which translates to faster response times and faster processing times when creating and processing AMF packets instead of SOAP.

Figure 11-1 depicts the process performed during a remoting call.

Figure 11-1. The process performed in response to a remoting call

The process performed in response to a remoting call

When a request is made to an application server:

  1. The client serializes data—including the parameters that the remote process expects—into AMF data. That binary data is wrapped in an HTTP packet and sent over the network to the destination server.

  2. The application server receives the request and passes it on to the Flash Remoting gateway, which converts the AMF data into native datatypes of the application server (something that the server can understand).

  3. The application server performs the necessary processing and generates a response. The response is serialized back into AMF by the remoting gateway and wrapped in an HTTP packet and sent back to the client.

  4. The client receives the results and deserializes the response AMF data into ActionScript objects.

There are several server-side implementations of the Flash Remoting gateway. Although Flash Remoting is not included with FlashCom, Macromedia bundles it with ColdFusion and JRun. Macromedia also offers Flash Remoting for separate purchase for J2EE and .NET. There are several open source implementations of Flash Remoting for PHP, Java, and Perl such as AMFPHP (http://www.amfphp.org), OpenAMF (http://www.openamf.org), and AMF::Perl (the remoting gateway formerly known as FLAP at http://simonf.com/amfpython). FlashORB (http://www.flashorb.com) is a third-party alternative. For extensive details on Flash Remoting, including its use with ColdFusion, Java, PHP, .NET, and Server-Side ActionScript—a version that differs slightly from the SSAS supported by FlashCom—see Flash Remoting: The Definitive Guide (O'Reilly).


Remoting Basics

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

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

[as]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");[/as]

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:

[as]NetConnection.call(remoteMethod, resultObject | null [, p1, ...pn])[/as]

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:

[as]topfolder.subfolder.file_no_extension.method[/as]

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



Remoting Classes

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

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 ActionScript—equivalent to JavaScript 1.5—are very similar).

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

[as]// 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]

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:

[as]load ("netservices.asc");[/as]

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:

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

or:

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

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:

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

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.


Services

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

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:

[as]UtilityService = my_conn.getService("cfcs.jwatkins.CommonUtils");[/as]

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( ):

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

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

Tip

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:

[as]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"); };[/as]

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:

[as]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"); };[/as]


Methods

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

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:

[as]serviceProxy.methodname([responseObject] [, arg1, ...argn])[/as]

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

Warning

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:

[as]serviceProxy.someMethod(someResponseObj, "one", "two", "three");[/as]

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

[as]serviceProxy.someMethod("one", "two", "three");[/as]

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

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

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.

Warning

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


Handling results

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

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:

[as]doGoogleSearch_Result = function (data) {
trace(data);
};[/as]

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:

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

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

[as]myService.authenticateUser(responder, "jwatkins", "abcd");[/as]

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:

[as]function ResultsClass ( ) {...}
ResultsClass.prototype.method1_Result = function ...
ResultsClass.prototype.method2_Result = function ...

myService = my_conn.getService("TestService", new ResultClass( ));[/as]

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.

Warning

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

[as]#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( );[/as]


Handling errors

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

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

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.

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:

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

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( ):

[as]application.registerClass(className, constructor);[/as]

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.

[as]function myClass ( ) {}
application.registerClass("myClass", myClass);[/as]

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

Warning

Setting properties in the constructor will break any deserialized data!


Recordsets

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

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

[as]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( );
};[/as]

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:

[as]params = new Object( );
params.pagesize = 5;
my_service.getData(params);[/as]


Recordsets Pt 2

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

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.

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

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:

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

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:

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

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:

[as]my_rs.setDeliveryMode("page", 5, 2);[/as]

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 communications—the client request and the server results—take 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.


Action Message Format

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

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.

Tip

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.


Role of Remoting in FlashCom Applications

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

FlashCom is not the most effective environment for storing and manipulating data. Managing large and complicated data structures is better handled by a filesystem or a relational database management system (RDBMS). FlashCom is designed for sharing real-time multimedia information and data across multiple users. Using data, however, is a common need for most applications, and it is important to understand when and how to implement remoting to solve a given problem. As a general rule, if the data should be shared by multiple users, then the remoting implementation should be built in FlashCom. The FlashCom Server has the ability to cache the results from a remoting request into a shared object, which can then be easily distributed to all the listening clients. Using the FlashCom Server to gather the remote data and cache the results will dramatically reduce the load required by the remote server. On the other hand, there are important cases in which remoting should be implemented by the Flash client, such as when personal or private information is involved.

The following sample application demonstrates various examples of when and how to implement remoting. The application is a messaging system that provides users with the ability to maintain a profile and a friend list, have private conversations with another user, and have group conversations with multiple users. The application code and files are too numerous to include here, so only the remoting-specific sections are highlighted and explained. However, the entire application can be downloaded from the book's web site.

The first screen the user sees is the login screen with the option to create a profile. Since the user is not part of the system, she needs to create a profile. The creation of a user profile is a private action and should be handled strictly between the Flash client and the remote server. Once the user data is collected, the application sends it to the remote server to add the user to the system. Example 11-5 shows the client-side Flash ActionScript that handles the user registration event when adding a user's profile to the database.

Example 11-5. Adding a user's profile

[as]#include "NetServices.as"
NetService.setDefaultGatewayUrl("http://www.yourhost.com/flashservices/gateway");

function register (userObj) {
  var remote_conn = NetServices.createGatewayConnection( );
  var messengerService =
           remote_conn.getService("com.oreilly.pfcs.chapter11.fcsmessenger");
  var response = new Object( );
  // Handle the results.
  response.onResult = function (result) {
    // The server could return -1 if the action failed.
    if (result > -1) {
      _root.gotoAndStop("Login");              // Send the user to the login screen
    }
  };
  // Catch any errors
  response.onStatus = function (error) {
    Alert.show(error.description, error.type); // Create a modal alert window
  };
  messengerService.addUser(response, userObj);
}[/as]

The register( ) method accepts an object as its argument. The userObj parameter would store all the local user properties that need to be collected by basic form elements (username, address, telephone number, etc.). The remote addUser( ) method would take the user properties and insert them into the database, successfully registering the user into the system. The onResult( ) handler could then proceed to the login screen by moving the playhead to the Login frame label.

Once the user has established her profile, she needs to log into the application. There are several different techniques to implement the login system. In Example 11-6, the user object is passed off to the FlashCom server; it builds the authentication mechanism in SSAS. This is a convenient approach if your application doesn't require any trusted security measures, because the client can simply establish a connection with the FlashCom Server and let the server manage validation of the user credentials needed to log on.

Example 11-6. Logging the user into the application

[as]load("netservices.asc");

// trim( ) removes whitespace from the beginning and end of a string.
function trim (str) {
  if (typeof str != "string") return "";  // Make sure str is a string
  str = str.replace(/^\s*/, "");          // Trim leading spaces
  str = str.replace(/\s*$/, "");          // Trim trailing spaces
  str = str.replace(/\n/g,  "");          // Remove new lines
  str = str.replace(/\r/g,  "");          // Remove carriage returns
  str = str.replace(/\t/g,  "");          // Remove tabs
  return str;
}

application.onAppStart = function ( ) {
  userList_so = SharedObject.get("private/userList");
  application.gatewayURI = "http://www.yourhost.com/flashservices/gateway";
  application.service = "com.oreilly.pfcs.chapter11.fcsmessenger";
  NetServices.setDefaultGatewayUrl(application.gatewayURI);
};

application.onConnect = function (client, user) {
  if (typeof user == "undefined" || ! user.userName) { // Validate the user obj
    application.rejectConnection(client, {msg: "Invalid user object."});
    return false;
  }

  user.userName = trim(user.userName);
  if (user.userName.length == 0) {
    application.rejectConnection(client, {msg: "Invalid or empty user name."});
    return false;
  }

  var conn = NetServices.createGatewayConnection( );
  var messengerService = conn.getService(application.service);

  var loginResponse = new Object( );
  loginResponse.onResult = function (userProfile) {
    if (userProfile == -1) {
      application.rejectConnection(client,
        {msg: "The username and password could not be verified"});
      return false;
    }

    var item = userProfile.getItemAt(0);

    var tempUser = userList_so.getProperty(item.userid);
    if (tempUser) {
      application.rejectConnection(client,
        {msg: "Only one simultaneous login is allowed"});
    }

    user.password = "";     // Make sure the password is cleared
    delete user.password;   // Delete the password
    user.web = item.web;
    if (!item.hide_email) {
      user.email = item.email;
    }
    user.firstname = item.firstname;
    user.lastname = item.lastname;
    user.arrival  = new Date( );
    user.__ID__ = item.userid;
    client.user = user;
    userList_so.setProperty(item.userid, user);
    application.acceptConnection(client);
  };

  messengerService.login(loginResponse, user.userName, user.password);
};[/as]

The login process is slightly more complicated than registering a new user. In application.onAppStart( ), we initialize the necessary objects and properties for later. The userList_so shared object is used to ensure that only one login is allowed per user at a time. Once the user has established a connection and we have verified that she has provided the proper login credentials, the script writes an item to the shared object indicating that the user is present. When the user disconnects, the script removes the user record from the shared object so she will be able to log in again.

The first part of the application.onConnect( ) method validates the user object and verifies that a username was passed. Once we know that at least something was passed for the user object and username, we need to verify the user's credentials with the database:

[as]var conn = NetServices.createGatewayConnection(  );
var messengerService = conn.getService(application.service);
messengerService.login(loginResponse, user.userName, user.password);[/as]

Finally, the onResult( ) method checks the results from the login( ) action, adds the additional information to the user object, and accepts the user's connection. The remote procedure verifies the user's credentials and returns either the entire user record or -1 if the process failed. In the handler if the result is -1, we reject the connection:

[as]if (userProfile == -1) {
  application.rejectConnection(client,
    {msg: "The username and password could not be verified"});
  return false;
}[/as]

The rest of the handler grabs the actual RecordSet item, checks to see if the user is already logged in, and adds the missing profile information to the user object.

Using this process to validate a user's credentials and log the user into a FlashCom application is a convenient approach because it creates a logical, linear flow of information. The user information is packaged and shipped to the FlashCom Server. The FlashCom server validates the information with the application server and accepts or denies the connection accordingly.

Because FlashCom doesn't natively support Secure Sockets Layer (SSL) connections and the credentials are sent in clear text over the network, this method doesn't offer any security, only a convenient means to establish a verified connection with a user. Other methods of authentication typically require the Flash client to validate credentials directly with an authenticating server first, then contact the FlashCom Server separately to connect to an application. Using this approach allows you to use SSL encryption for the information over the network. See Chapter 18 for more information.

Now that the user has been authenticated and logged in to the FlashCom Server, we need to request the friend list. The friend list will be similar to a buddy list used in an instant messaging client. The user can request to add and remove friends from his own list. The user can also see whether each friend is online and be notified if the friend's online status changes. To accomplish this, we use an approach similar to the login process. The Flash client requests the friend list from the FlashCom Server. The FlashCom Server grabs the actual list from the database and loops through all the friends to check whether they are currently online.

From the client scripts, we initiate the sequence by using the NetConnection.call( ) method:

[as]Client.prototype.getFriendList = function (  ) {
  var conn = NetServices.createGatewayConnection(  );
  var messengerService = conn.getService(application.service);

  var response = new Object( );
  var theClient = this;
  response.onResult = function (friendList) {
    var len = friendList.length;
    for (var i = 0; i < len; i++) {
      var item = friendList.getItemAt(i);
      item.online = userList_so.getProperty(item.userid) == null;
    }
  theClient.call("receiveFriendList", null, friendList);
  };
  messengerService.getFriendList(response, this.user.userid);
};[/as]

The getFriendList( ) method makes the request to the server for the list of friends for the passed userid. Once the results have been returned from the method, the handler loops through all of the results and finds the friends who are online by looking for them in the userList_so shared object. If the friend's userid is present in the shared object, then she is currently online.

Notice that the getFriendList( ) method does not simply return the friendList, but it uses the Client.call( ) method to call the receiveFriendList( ) method on the client. Remoting calls are asynchronous, so the return statement would execute long before the results were actually returned from the server.

The last two remote methods, addFriend( ) and removeFriend( ), are implemented in a similar way. The addFriend( ) method should be sent through FlashCom, because the user who added the friend would like to see if the friend is currently online. The removeFriend( ) method doesn't need to involve the FlashCom Server at all because it simply removes the friend from the list.

Of course, the possible applications are many and varied, but this gives you the basis for understanding how and when to use remoting in a typical scenario. Remember to see the book's web site for the full example files.


Securing Access

Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Programming Flash Communication Server
By Brian Lesser, Giacomo Guilizzoni, Robert Reinhardt, Joey Lott, Justin Watkins
February 2005
ISBN: 0-596-00504-0
http://www.oreilly.com/catalog/progflashcs/index.html
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

Protecting the server resources and the content that is shipped over the network is important to keeping unwanted intruders out of your application. When implementing a remoting method that requires the data to be secure, the best way to encrypt the data is to implement the remoting from the client to the server over an SSL connection. Since remote data that needs to be secure is typically personal information, this should be handled between a client application and an authenticating server, as described in Chapter 18. This can easily be done with a SWF running in the browser and connecting to the gateway with:

[code]https://www.yourserver.com/flashservices/gateway[/code]

Protecting the remote methods on the server is also important. If you enable a remote method for public access, it is likely that those methods can be accessed from outside of your application. Fortunately, most remoting implementations provide a way to protect the methods with roles-based security. In ColdFusion, you can add the roles attribute to the method declaration (the <cffunction> tag) to restrict the access of the method to users who have been authenticated on the server and have been declared with the specific role:

[code]<cffunction name="remoteMethod" access="remote" roles="authenticatedUser">
<!--- method body -->
</cffunction>[/code]

By declaring the role on the method, you force the user to log into the server before he can access the method. This can be done in two ways. The first way is to implement the setCredentials( ) method on the client:

[as]#include "NetServices.as"
NetServices.setDefaultGatewayUrl("http://www.yourhost.com/flashservices/gateway");
my_conn = NetServices.createGatewayConnection( );
my_conn.setCredentials("username", "password");[/as]

The setCredentials( ) method adds a Credentials header to the outbound AMF packet and forces the server to initialize the login routine. In ColdFusion, this is usually defined in the Application.cfm file within a <cflogin> tag. Inside the <cflogin> tag, you define the authentication mechanism to verify the username and password passed in the Credentials header. Alternatively, you can also create your own custom login routine by declaring a public method that is not restricted with a roles attribute that will log in the user with the <cfloginuser> tag.

If your FlashCom application relies heavily upon remoting and you absolutely need the FlashCom application server data to be secure, you can create your network so only the FlashCom Server can access the resources defined on the server. This will guarantee that only the FlashCom Server has access to the remote resources and they cannot be abused by an outside party. See Chapter 18 for more information on security.

Conclusion

This chapter has demonstrated how Flash Remoting can be used to add data connectivity to FlashCom applications. Flash Remoting can access web services, server-side scripts, CGI applications, XML files, or the local filesystem with the help of an application server such as ColdFusion. Just your luck, the next chapter covers ColdFusion to perform numerous utility functions and database queries not possible with FlashCom alone.

We're almost done with our tour of FlashCom internals and associated technologies. By now, you should have a solid theoretical foundation but you may be having trouble seeing the forest for the trees. Don't fret; subsequent chapters deal with component frameworks, application development, performance tuning, security, and more.