6.2 The CF Object

The CF object allows SSAS to perform queries and HTTP calls through the ColdFusion server.

6.2.1 Using CF.http( )

ColdFusion supports the <cfhttp> tag, which allows ColdFusion applications to post to and retrieve content from remote web servers?or from your own web server. The CF.http( ) method mimics the functionality of this tag, as well as its child tag <cfhttpparam>.

CF.http( ) doesn't include all of the functionality of the <cfhttp> tag. The ability to dynamically create queries using a .csv file is conspicuously absent from the CF.http( ) arsenal.

CF.http( ) has many possible uses:

  • Post searches and retrieve search results from different search engines

  • Access web services, such as stock services

  • Load XML files from remote locations

  • Create downloadable links that don't reveal the file location to the end user

  • Dynamically create and save to the server HTML documents that can later be browsed as static pages

There are many more uses as well. CF.http( ) can be called like this:

var myVar = CF.http(method, url, username, password,
                    resolveurl, params, path, file);

The CF.http( ) method accepts up to eight arguments, as listed in Table 6-1.

Table 6-1. Arguments of the CF.http( ) method




"get" or "post". The "get" option retrieves a file, and the "post" option posts data to a server.


The URL of the server where you are getting the file or posting the data. This needs to be a fully qualified URL (including the http:// or other protocol).


Username (if required) for authentication.


Password (if required) for authentication.


"yes" or "no" (defaults to "no"). If the file content you are retrieving has links or URLs inside of certain tags, they will be resolved. See Table 6-2.


Array of parameter objects that can be passed to the http operation. Each object can contain name, type, and value properties.


If storing a file, use both the path and file properties.


Filename of file. In "get" operations this defaults to the filename in the url argument.

[1] Required

The params array deserves a little further explanation. This array should contain one or more objects with the following properties:


The name of the field that you are posting


One of the following five types:


URL-encoded data


Indicates a value to be passed as a field in a form


Cookie data


CGI script to execute


File to be uploaded


Any value that conforms to the limitations of the type of field you are passing (you shouldn't pass a 10 KB cookie field, for example)

You should build the array of parameter objects before sending it to the CF.http( ) method, as shown in the following examples.

Table 6-2 shows HTML tags resolved by passing "yes" in the resolveurl argument to CF.http( )

Table 6-2. HTML tags resolved by using "yes" in the resolveurl argument of CF.http( )
































You can call CF.http( ) using the standard technique in which the arguments must be specified in the expected order. Here, only the required arguments are passed:

var myObj = CF.http("get","http://www.flash-remoting.com/feeds/rss.cfm");

Named arguments can be passed to CF.http( ), shown here using an object literal, in which case the position of the arguments is irrelevant:

var myObj = CF.http(

Here is an example using the "post" method and passing an array of parameters:

// Define the parameters to pass
var myParams = new Array( );
// Pass the myParams array along with the other parameters
var myObj = CF.http(

The CF.http( ) method returns an object that contains seven built-in properties. You can access the properties of this object on the client side as you would any other ActionScript object:


The character set used in the document that is returned


The contents of the requested file


The response header


The MIME type of the file that is returned, such as "text/xml"


Response header from the server, in the form of a single header or array of headers


HTTP error code and error string from the remote call


The value "true" if the file content is textual; otherwise, "false"

The filecontent property is the most useful, allowing you to access the contents of the file you requested with the CF.http( ) method.

The next section shows an example of a possible use of the CF.http( ) functionality. Creating a proxy for a remote service

One of the limitations of Flash is that it can't access content outside of the Flash movie's domain. For example, a Flash movie hosted on www.communitymx.com can't load content from www.flash-remoting.com. One way around this is to use a proxy, a middleman that allows communication between two different servers. The proxy can be written with a few simple lines of Server-Side ActionScript code in a remote function. The code in Example 6-1 can be saved as Proxy.asr in the webroot\com\oreilly\frdg directory.

Example 6-1. Remote service proxy code in Proxy.asr
function proxy (location) {
  // Request the data
  var theFile = CF.http (location);
  // Return the filecontent property of the object returned by CF.http( )
  return theFile.get("filecontent");

In this code, the CF.http( ) method grabs the file content from the specified URL (location). The proxy( ) method simply passes back the contents of the requested file to the Flash movie, which can do whatever it wants with the data.

Example 6-2 shows the client-side ActionScript necessary to display a remote XML file through the Proxy service set up in Example 6-1. In this case, the XML document is an RSS feed for my weblog located at http://www.flash-remoting.com. It will load through the proxy to a movie served from any domain. The text field is created dynamically, so no interface is needed. To get the dynamic scrollbar to work with the movie, you'll have to drag an instance of the ScrollBar component from the Components panel to the Stage and then delete it. This populates the Library with the symbols needed for the component.

Example 6-2. Retrieving a URL via a SSAS proxy
#include "NetServices.as"

// You must set the myURL and servicePath variables to
// your own Flash Remoting path and service path
var myURL = "http://localhost/flashservices/gateway";
var servicePath = "com.oreilly.frdg.Proxy";

// Create a text field to show the results
myTextfield.multiline = true;
myTextfield.wordWrap = true;
myTextfield.html = true;
myTextfield.border = 1;

// Add the ScrollBar component to the dynamic text field.
// This assumes you've added the FScrollBarSymbol symbol
// to the library by dragging a ScrollBar instance to the
// Stage and deleting it.
init = {_targetInstanceName:"myTextfield", horizontal:false};
_root.attachMovie("FScrollBarSymbol", "myScrollbar", 2, init);
myScrollbar._x = myTextfield._width + 10; // put it next to textfield
myScrollbar._y = myTextfield._y ;         // put it next to textfield


myTextfield.htmlText = "Reading blog...";

// Perform initialization only once
if (!initialized) {
  initialized = true;
  var my_conn = NetServices.createGatewayConnection( );
  var myService = my_conn.getService(servicePath);

function textfieldNews (xml) {
  // Extract news items in item nodes of channel node
  var channelTag = xml.childNodes[1].nextSibling.childNodes[1];
  var temp = "";
  var newsitem, currentTag, link, newsdate;
  myTextfield.htmlText = "";
  for (var i=0; i < channelTag.childNodes.length; i++) {
    newsitem = channelTag.childNodes[i];
    newsitem.ignoreWhite = true;
    for (var j=0; j<newsitem.childNodes.length; j++) {
      currentTag = newsitem.childNodes[j];
      currentText = currentTag.firstChild.nodeValue;
      switch (currentTag.nodeName) {
        case "title":
          title = currentText;
        case "link":
          link = "<font color='#9966CC'>";
          link += "<a href='" + currentText + "'>" + title + "</a></font>";
        case "pubDate":
          newsdate = currentText;
          temp += newsdate + "<br>";
          temp += link + "<br><br>";
    } // end for j
  } // end for i
  myTextfield.htmlText = temp;

// Responder object to displays the result or an error
function MyResponder ( ) {}
MyResponder.prototype.onResult = function (myResult) {
  var fr_news = new XML(myResult);

MyResponder.prototype.onStatus = function (myStatus) {
  trace("Error: "+ myStatus.description);
myService.proxy(new MyResponder( ), "http://www.flash-remoting.com/rss.xml");

6.2.2 Using CF.query( )

ColdFusion developers have always had access to a simple tag that creates database connections, executes SQL statements, and returns resultsets to the caller. The <cfquery> tag is simple to use and simple to understand. The ColdFusion implementation of SSAS contains a method, CF.query( ), that works in a fashion similar to the <cfquery> tag. CF.query( ) properties

The CF.query( ) method accepts up to six arguments, as listed in Table 6-3. Only the datasource and sql arguments are required. A ColdFusion Server's database connections are defined in the CF Administrator. These connections are known as datasource names and are the basis of all data operations in ColdFusion. Once you have a datasource name set up, you can access the database to select, update, insert, or delete the data; invoke stored procedures calls; create tables; or perform any other database operation. All of this is accessible through SSAS.

Table 6-3. Arguments of the CF.query( ) method




ColdFusion datasource set up in the CF Administrator


SQL statement that you are sending to the database


Login name for the database connection, which overrides the datasource username from the CF Administrator


Password for the database connection


Number of rows to deliver to the Flash movie


Number of seconds to wait for the query to finish before returning an error

[2] Required

The sql argument is the SQL statement that you want to send to the database. If this is a simple SELECT statement, the CF.query( ) method returns a resultset, or Query object as it is known to ColdFusion programmers.

Just like the CF.http( ) method, you can pass your arguments to the CF.query( ) method in several different ways. This is how the method is called using the basic function call:

var myVar = CF.query(datasource, sql, username, password, maxrows);

You cannot use the timeout argument when calling CF.query( ) with sequential arguments. To use timeout, you must use the named argument style:

var myVar = CF.query(
); The SQL argument

Common questions about Flash Remoting and SSAS involve the sql argument in the CF.query( ) method. The important thing to remember is that the sql argument is just a SQL statement in the form of a string; there is nothing magical about it. You can build a SQL statement manually, create a loop to add fields, or concatenate several parts together. The resulting string must be a valid SQL statement that can be sent to the database for processing. For example, you might pass an object to your Server-Side ActionScript containing the parameters for the query:


Then, your SSAS code can build the SQL statement string using the object properties:

function searchProducts (searchobj) {
  var sql = "SELECT * FROM Products WHERE ";
  sql += "ProductName LIKE '" + searchobj.get("productname") + '";
  sql += " AND UnitPrice > " + searchobj.get("unitprice");
  return CF.query("northwind", sql);

The variable sql in the previous example would contain the following SQL statement:

SELECT * FROM Products WHERE ProductName LIKE 's%' AND UnitPrice > 15

When you are creating your SQL statements, make sure to use single quotes for string or character delimiters and no quotes for numeric data. If you're using a Microsoft Access database, you should use # for date and time data. Retrieving results

The most basic form of database interaction involves the SELECT statement to retrieve results from the server. This is easily implemented in SSAS using CF.query( ), as in the following code:

function getProducts ( ) {
  var sql = "SELECT ProductID, ProductName FROM Products";
  var myResults = CF.query("northwind", sql);
  return myResults;

This code returns an entire resultset back to the Flash movie in the form of an ActionScript RecordSet object. This is the same as calling a <cfquery> tag in a ColdFusion Component or ColdFusion page, as shown in Chapter 3. Inserting, updating, and deleting results

When you perform a database SELECT, you retrieve a resultset. When you do other database operations such as inserting, updating, or deleting from a database, nothing is returned. These types of statements can also be executed from SSAS, as can other types of SQL statements that create and drop database objects, set permissions, or perform any other valid form of database transaction.

To demonstrate, I'll use the client-side code that was set up in Example 5-14. The functions in the SSAS file all work in a fashion similar to the ColdFusion example. If you set up the ProductsAdmin.cfc file in Example 5-13, you'll have to rename it to SomethingElse.cfc in order to allow the SSAS .asr file to take precedence.

The code in Example 6-3 is the full source listing for ProductsAdmin.asr. It should be saved in the webroot\com\oreilly\frdg\admin directory in order to allow it to work with the ProductsAdmin.fla file.

Example 6-3. Updating, inserting, and deleting data using SSAS in ProductsAdmin.asr
function getSearchResult (search) {
  // Retrieves records that match the search criteria
  var sql = "SELECT ProductID, ProductName, UnitPrice,";
  sql += " QuantityPerUnit, CategoryID, SupplierID";
  sql += " FROM Products"
  // If no argument is passed, all records are returned
  if (search)
    sql += " WHERE ProductName LIKE '%" + search + "%'";
  try { // Execute the query and capture errors
    var rsGetProducts = CF.query("northwind", sql);
  } catch (e) {
    throw "There was a database error";
  return rsGetProducts;
function addProduct (Product) {
  var sql = "INSERT INTO Products (";
  sql += " ProductName";
  sql += " , UnitPrice";
  sql += " , QuantityPerUnit";
  sql += " , CategoryID";
  sql += " , SupplierID ";
  sql += ") VALUES (";
  sql += " '" + Product.get("ProductName") + "'";
  sql += " , " + Product.get("UnitPrice");
  sql += " , '" + Product.get("QuantityPerUnit") + "'";
  sql += " , " + Product.get("CategoryID");
  sql += " , " + Product.get("SupplierID");
  sql += ")";
  try { // Execute the query and capture errors
    CF.query("northwind", sql);
  } catch (e) {
    throw "There was a database error";

function updateProduct (Product) {
  var sql = "UPDATE Products";
  sql += " SET ProductName='" + Product.get("ProductName") + "'";
  sql += " , UnitPrice=" + Product.get("UnitPrice");
  sql += " , QuantityPerUnit='" + Product.get("QuantityPerUnit") + "'";
  sql += " , CategoryID=" + Product.get("CategoryID");
  sql += " , SupplierID=" + Product.get("SupplierID");
  sql += " WHERE ProductID = " + Product.get("ProductID");
  try { // Execute the query and capture errors
    CF.query("northwind", sql);
  } catch (e) {
    throw "There was a database error";

function deleteProducts (ProductIDs) {
  // Delete one or more products. ProductIDs can be one ProductID or
  // a comma-separated list of ProductIDs.
  // The next statement is the delete statement. It is commented out
  // so that you can use the Discontinued column to delete products.
  // var sql = "DELETE FROM Products WHERE ProductID IN (" + ProductIDs + ")";
  var sql= "UPDATE Products SET Discontinued = 1
  sql += "WHERE ProductID IN (" + ProductIDs + ")";
  try { // Execute the query and capture errors
    CF.query("northwind", sql);
  } catch (e) {
    throw "There was a database error";

function getSuppliers ( ) {
  // Retrieve a list of suppliers for a ComboBox.
  var sql = "SELECT SupplierID, CompanyName FROM Suppliers";
  try {  // Execute the query and capture errors
    var rsSuppliers = CF.query("northwind", sql);
  } catch (e) {
    throw "There was a database error";
  return rsSuppliers;

function getCategories ( ) {
  // Retrieve a list of categories for a ComboBox.
  var sql = "SELECT CategoryID, CategoryName FROM Categories";
  try {  // Execute the query and capture errors
    var rsCategories = CF.query("northwind", sql);
  } catch(e) {
    throw "There was a database error";
  return rsCategories;

The remote methods operate exactly as the methods from the CFML in Example 5-13. Following are a few comments about the code.

To access properties of objects passed to remote methods, you have to use objectName.get("propertyName"), as in this line from Example 6-3:

sql += " SET ProductName='" + Product.get("ProductName") + "'";

This is because the ActionScript objects coming from the client are actually Java objects of type ASObject when they are parsed by your SSAS file.

The SQL statements in Example 6-3 are built up using the preceding-comma approach of building SQL strings, as in this code:

  var sql = "UPDATE Products";
  sql += " SET ProductName='" + Product.get("ProductName") + "'";
  sql += " , UnitPrice=" + Product.get("UnitPrice");
  sql += " , QuantityPerUnit='" + Product.get("QuantityPerUnit") + "'";
  sql += " , CategoryID=" + Product.get("CategoryID");
  sql += " , SupplierID=" + Product.get("SupplierID");
  sql += " WHERE ProductID = " + Product.get("ProductID");

The code might look funny, but when you are debugging complex SQL statements, this style of coding makes it easy to comment out individual lines of SQL code without having to reformat the rest of the SQL statement.

SQL statements in Server-Side ActionScript must be contained on one line with no line breaks. For that reason, it is wise to build your SQL statement as a string before sending it to the database.

    Part III: Advanced Flash Remoting