Article Source :http://www.adobe.com/devnet/flash/articles/move_to_browser.html
One of the most astounding aspects of building Rich Internet Applications based on Macromedia ColdFusion MX and Macromedia Flash MX, connected through Macromedia Flash Remoting, is the ease with which common desktop software functionalities and complex user interactions can be replicated into web-based applications. The benefits of developing such applications are countless, starting from the clear distinction between business logic (wrapped inside ColdFusion components) and graphical user interface (designed in Macromedia Flash), to reaching a larger audience and many different devices thanks to the ubiquity of a rich client—Macromedia Flash Player.
The following tutorial guides you through the implementation of a simple FTP client that takes advantage of the built-in file transfer capabilities of ColdFusion MX to access FTP servers—and of the Flash Tree component, part of the Flash UI Components Set 2 available from the Macromedia Exchange—to display and handle the data retrieved by ColdFusion MX.
Getting the software and sample files
First make sure you have the required software and that it is correctly installed:
- Macromedia Flash MX
- Macromedia ColdFusion MX
- Flash Remoting Components for Macromedia Flash MX
- Flash UI Components Set 2
Next download the sample files to follow along with this tutorial:
Windows: flash_ftp.zip (200K)
Macintosh: flash_ftp.sit (140K)
Now create a folder at cf_webroot\com\aftershape\ftp and unzip/expand the ftpSpider.cfc ColdFusion MX component into the ftp directory.
Note: The cf_webroot directory path depends on your ColdFusion MX installation.
The flash_ftp.fla file is the finished Flash graphic user interface (GUI). This file will help you follow the tutorial if you’d like to study the finished project.
The flash_ftp_start.fla file contains everything except the ActionScript code—which is explained during this tutorial. Use this file if you’d like to add the ActionScript yourself as it is presented.
How the ftpSpider component works
All the tasks performed on the remote FTP server are handled by the ftpSpider ColdFusion MX component. This component uses the CFFTP tag, so make sure it has been enabled in the ColdFusion Administrator.
The component is composed of two CFFUNCTION tags which define its two methods. The first, named FetchDirectories, handles all the files and directories listing operations. The second, named FetchFiles, handles transferring operations from the remote FTP server to the temporary directory of your ColdFusion MX server. To make these methods available to the Flash GUI, which I build in the second part of the tutorial, you need to set the attribute access to “remote” for both CFFUNCTION tags that form the component.
Using the FetchDirectories method
To use the component’s first method, gather the needed FTP parameters using a succession of CFARGUMENTS tags. Each FTP parameter is collected and sent to the ColdFusion component by the Flash GUI, as you’ll see later on. These parameters are the main attributes required by the CFFTP tag:
<cfargument name="ftpUsername" type="any" required="yes">
<cfargument name="ftpPassword" type="any" required="yes">
<cfargument name="ftpServer" type="any" required="yes">
<cfargument name="ftpPort" type="numeric" required="yes">
<cfargument name="ftpPassivemode" type="boolean" required="yes">
<cfargument name="ftpTimeout" type="numeric" required="yes">
<cfargument name="ftpDirectory" type="any" required="yes">
Once you’ve defined all the FTP parameters, you can start connecting to the remote FTP server using another CFFTP tag, with the action attribute set to OPEN. You will benefit from the connection-caching feature of ColdFusion, which automatically defines a connection name on the connection attribute. This feature enables you to reuse the same connection information on successive CFFTP tags:
<cfftp action="OPEN"
server="#ARGUMENTS.ftpServer#"
username="#ARGUMENTS.ftpUsername#"
password="#ARGUMENTS.ftpPassword#"
stoponerror="No"
passive="#ARGUMENTS.ftpPassivemode#"
port="#ARGUMENTS.ftpPort#"
connection="MyFTPConnection"
retrycount="3"
timeout="#ARGUMENTS.ftpTimeout#">
From the remote FTP server, retrieve all names and attributes of the stored directories and files as a query object using the LISTDIR action of the CFFTP. After that, send this information to the calling Flash interface using the CFRETURN tag. Once you’ve done this, you can close the FTP connection to avoid multiple open connections each time you process the ColdFusion component:
<cfftp action="LISTDIR"
stoponerror="No"
passive="#ARGUMENTS.ftpPassivemode#"
name="FileList"
directory="#ARGUMENTS.ftpDirectory#"
connection="MyFTPConnection">
<cfftp action="CLOSE"
stoponerror="No"
passive="#ARGUMENTS.ftpPassivemode#"
connection="MyFTPConnection">
<cfreturn FileList>
Using the FetchFiles method
The second method of the component works almost the same way as FetchDirectories. The only relevant difference is that now, because the connection has already been established, you will download the file selected on the Flash GUI to your ColdFusion MX temporary folder instead of retrieving a list of directories. You can accomplish this task easily by setting the action attribute of the CFFTP tag to GETFILE. The user will be notified about the final result of the download operation by the CFFTP.
In the code example below, the succeeded variable—which is populated by assigning a value of No to the stoponerror attribute of the CFFTP tag—is subsequently returned to the Flash GUI by the CFRETURN tag:
<cfftp action="GETFILE"
stoponerror="No"
passive="#ARGUMENTS.ftpPassivemode#"
localfile="#GetTempDirectory()##ARGUMENTS.ftpFileLocal#"
remotefile="#ARGUMENTS.ftpFileRemote#"
transfermode="AUTO"
failifexists="Yes"
connection="MyFTPConnection">
<cfreturn CFFTP.Succeeded>
Note: Because of its single-threaded nature, it’s always a good idea to lock the CFFTP tag. However, a digression on locking was beyond the scope of this tutorial. For the sake of simplicity, each FTP operation is not locked and performs on separate CFFTP tags—even if you could, for example, open the connection to the remote FTP server and download the desired file in a single step. For more information on locking, please refer to Macromedia’s TechNote, “ColdFusion Locking Best Practices.”
Building the Flash FTP GUI
Open the flash_ftp_start.fla file and take a second to examine it. As you can see, all the elements appear on the Stage for you. The only blank frame is on the top layer, which is named “actions.”
There are several input text fields at the top right of the Stage. The user enters the login information into these text fields to connect to the remote FTP server.
The PushButton Flash component labeled “Connect” passes the values gathered from the text fields to the ConnectToFTP function you are going to write in a few minutes. That function is responsible for starting the whole application.
Below the PushButton component, there’s another dynamic text field named “FieldServerMsg_txt”; this is where you display custom error messages and the status of each FTP operation.
The left side of the Stage is where the Tree Flash component resides. FtpBrowser_tree is responsible for displaying the remote FTP server files. Each time a tree node is selected, this component calls a function named GetSelection, which is one of the Tree component’s behaviors.
Select the blank top layer and open the Actions panel by pressing F9 or selecting Window > Actions. Once it’s opened, make sure your Script pane is set to Expert Mode. Start by including the NetService.as file, which contains the classes required by Flash Remoting:
#include "NetServices.as"
The first function you implement is the one that changes the status of the selected tree node from open to closed (and vice versa). This function is only called when the selected node is a branch that corresponds to a folder on the remote FTP server.
Note the use of suffixes such as _tn (which stands for “tree node”) and _tree. I recommend using suffix strings like these whenever writing ActionScript because the code completion support built into Macromedia Flash MX displays code hints:
function OpenNode(state) {
CurrentNode_tn.setIsOpen(state);
FtpBrowser_tree.refresh();
}
To handle the returned data from the service call to the FetchDirectories method of your ColdFusion component, set up a default responder. The function will populate the Tree Flash component depending on the query object received from the spiderFtp.cfc file.
First, it will check to see if an empty query has been returned. When the query contains one or more records, it will loop through them and add the tree branch icon (if the processed record is a directory) or a leaf icon (if it is a file). Each tree node will be labeled with the name of the column returned by the ColdFusion component, while the path column will define the node’s data value.
Notice that both the name and path columns are standard CFFTP query object columns. CurrentNode_tn is nothing but the directory used as a base folder for each call to the ColdFusion component. Once the user begins browsing the tree, CurrentNode_tn will be replaced by the selected tree node data value. To provide visual feedback to the user, the selected branch status will be set to open each time the result of the service call would have been processed—even if the returning query object is empty:
function FetchDirectories_Result(result) {
// If the query returns no record...
if (result.getLength() == 0) {
// ...directory is empty. Display message and open the branch.
FieldServerMsg_txt.text = "Directory is empty";
OpenNode(true);
} else {
// Loop through query result...
for (i=0; i<result.getLength(); i++) {
// ...if a directory is found...
if (result.getItemAt(i).isDirectory == "YES") {
// ...add it as a branch.
FtpBrowser_tree.addNode(CurrentNode_tn, new FTreeNode(result.getItemAt(i).name).setData(result.getItemAt(i).path).setIsBranch());
// ...and open parent branch
OpenNode(true);
FieldServerMsg_txt.text = "";
} else {
// Else add it as a leaf...
FtpBrowser_tree.addNode(CurrentNode_tn, new FTreeNode(result.getItemAt(i).name).setData(result.getItemAt(i).path));
// ...and open parent branch
OpenNode(true);
FieldServerMsg_txt.text = "";
}
}
}
}
To handle returned errors from the FetchDirectories service function, set up a simple responder that displays the error messages in the FieldServerMsg_txt dynamic text field on the Stage:
function FetchDirectories_Status(result) {
// Print error messages
FieldServerMsg_txt.text = result.details;
}
The default responder for the FetchFiles service function is straightforward. The FTP connection errors are handled by the FetchDirectories service function error responder, which is very helpful. In fact, users are able to browse the remote FTP server and choose a file that they wish to download as long as the login information they entered to call the FetchDirectories function is correct—you don’t have to worry about connection errors.
The CFFTP variable, which you receive from the ColdFusion components, returns a simple Boolean value depending on the download process result. You only need to display a status message on the FieldServerMsg_txt dynamic text field to provide users with feedback on the process:
function FetchFiles_Result(result) {
if (result) {
FieldServerMsg_txt.text = "File has been downloaded to your ColdFusion temporary directory.";
} else {
FieldServerMsg_txt.text = "Error occurred while trying to download the selected file.";
}
}
The CreateRootNode function is called only once by the PushButton Flash component. It creates the root node of the Tree Flash component and makes the first call to the FetchDirectories service:
function CreateRootNode() {
RootNode_tn = new FTreeNode("/").setData("/");
CurrentNode_tn = RootNode_tn;
CurrentNode_tn.setIsBranch();
FtpBrowser_tree.setRootNode(CurrentNode_tn);
// Retrieve directories list
DirectoryService.FetchDirectories(FieldUsername_txt.text, FieldPassword_txt.text, FieldServer_txt.text, FieldPort_txt.text, PassiveMode_cb.getValue(), FieldTimeout_txt.text, CurrentNode_tn.getData());
FieldServerMsg_txt.text = "Retrieving files list...";
}
The function called by the PushButton Flash component on the Stage simply resets the message text field and calls the CreateRootNode function I discussed above:
function ConnectToFTP() {
// Reset messages window...
FieldServerMsg_txt.text = "";
// ...and call CreateRootNode function
CreateRootNode();
}
The GetSelection function is responsible for the Tree Flash component’s behavior. It sets the value for CurrentNode_tn with the current selected node on the Tree. Also, if the selected node is a branch, it opens or closes depending on the branch’s current status. The function calls the FetchDirectories service if it has no child nodes; otherwise it calls the FetchFiles service if the selected node is a leaf that represents a file on the remote FTP server:
function GetSelection() {
// Define current selected node
CurrentNode_tn = FtpBrowser_tree.getSelectedNode();
// The following routine opens or closes branches depending on their status or number of children
if (CurrentNode_tn.isBranch()) {
if (CurrentNode_tn.getNumChildren() == 0) {
DirectoryService.FetchDirectories(FieldUsername_txt.text, FieldPassword_txt.text, FieldServer_txt.text, FieldPort_txt.text, PassiveMode_cb.getValue(), FieldTimeout_txt.text, CurrentNode_tn.getData());
FieldServerMsg_txt.text = "Retrieving files list...";
} else {
if (CurrentNode_tn.isOpen()) {
OpenNode(false);
} else {
OpenNode(true);
}
}
// If a leaf has been selected instead of a branch, start the download
} else {
DirectoryService.FetchFiles(FieldUsername_txt.text, FieldPassword_txt.text, FieldServer_txt.text, FieldPort_txt.text, PassiveMode_cb.getValue(), FieldTimeout_txt.text, CurrentNode_tn.getLabel(), CurrentNode_tn.getData());
FieldServerMsg_txt.text = "Downloading file. Please wait.";
}
}
Last, but not least, comes the initialization code. I usually leave this task for the end of my ActionScript development so that I’m sure all my functions have been loaded before processing it.
The initialization code simply contains the URL to the default gateway, the construction of the main Service Object, and some customization methods of the assets on the main Stage. Remember that the URL to your default gateway depends on your installation. In this example, the URL points to the default gateway on the stand-alone web server that comes with ColdFusion MX:
if (init == null) {
init = true;
// Set the default gateway
NetServices.setDefaultGatewayUrl("http://localhost:8500/flashservices/gateway");
// Make the Gateway connection
GatewayConnection_nc = NetServices.createGatewayConnection();
// Create Service Object
DirectoryService = GatewayConnection_nc.getService("com.aftershape.ftp.ftpSpider", this);
// Set autohide to tree's scrollbar
FtpBrowser_tree.setAutoHideScrollBar(true);
// ::trick:: remove expander symbol linking to an object that doesn't exist
FtpBrowser_tree.setExpanderSymbolName("null");
// Set default ftp settings
FieldPort_txt.text = 21;
FieldTimeout_txt.text = 50;
// Set tab index order
FieldServer_txt.tabIndex = 1;
FieldPort_txt.tabIndex = 2;
FieldUsername_txt.tabIndex = 3;
FieldPassword_txt.tabIndex = 4;
FieldTimeout_txt.tabIndex = 5;
FieldServerMsg_txt.tabEnabled = false;
}
This tutorial demonstrates how Rich Internet Applications can extend current Internet applications by providing developers with the tools they need to easily replicate common desktop software user interactions and functionalities. You can use this example as a starting point to build a more complete and sophisticated FTP client, or as inspiration for more compelling applications.
April 22, 2009 at 6:45 am |
I follow your blog for quite a long time and should tell that your articles are always valuable to readers.
July 20, 2009 at 4:03 am |
hmm… cognitively