Flash Remoting.com
Home Book Examples Blog Resources About
Search

You are using an out-of-date browser so the pages will not display properly. Please update your browser.

Random thoughts on Flash Remoting:

This is where I get to ramble when I feel like it. Kind of like a blog, but it's not a blog. This is a blog. ;-).

6 posts in December 2003.

[ALL] 1/06 | 9/05 | 8/05 | 7/05 | 10/04 | 8/04 | 7/04 | 6/04 | 4/04 | 3/04 | 2/04 | 1/04 | 12/03 | 11/03 | 10/03 | 9/03 | 8/03 | 7/03 | 6/03 | 5/03 | 4/03 | 3/03 | 1/03 | 12/02 | 11/02

1-5 | 6-6

Putting a RecordSet into a SharedObject

Friday, December 19, 2003 12:05:20 PM

In response to an email I received, I began looking at putting a RecordSet object into a SharedObject. It is not as easy as you would think, and actually requires a bit of a kludge. This code works, and populates a grid:

// Responder function for result
function getSearchResult_Result (result_rs) {
  mySharedObject = SharedObject.getLocal("products");
  mySharedObject.data.myResults = result_rs;
  // The following line binds the recordset to the grid gr
  gr.dataProvider = mySharedObject.data.myResults;
}

The last line actually sets the dataProvider for the grid to the RecordSet stored in the SharedObject. However, this code should work just as well, without calling the remote service on load:

mySharedObject = SharedObject.getLocal("products");
mySharedObject.data.myResults = result_rs;
// The following line binds the recordset to the grid gr
gr.dataProvider = mySharedObject.data.myResults;

It doesn't. The headings are placed in the grid, but no data is shown. As it turns out, the only change required to make the SharedObject work with a RecordSet object is to use the items property of the RecordSet as the DataProvider:

mySharedObject = SharedObject.getLocal("products");
mySharedObject.data.myResults = result_rs;
// The following line binds the recordset to the grid gr
gr.dataProvider = mySharedObject.data.myResults.items;

The cool thing about SharedObjects is that properties and methods of the class that you are storing in the object are still available. The following is the full code for the .fla using the same interface that I used for the example at http://www.flash-remoting.com/examples/fr2004pt1/. (The example on that page does not have the SharedObject functionality). In the code, I'm calling the getLength() property of the RecordSet on the SharedObject.

#include "NetServices.as"

// Connect to the gateway and create a service object
if (connected == null) {
  connected = true;
  NetServices.setDefaultGatewayUrl("http://localhost/flashservices/gateway");
  var my_conn = NetServices.createGatewayConnection();
  var myService = my_conn.getService("com.oreilly.frdg.SearchProducts", this);
}

var simpleListener = new Object();
submit_pb.addEventListener("click", onSubmit);

// Event handler for button
function onSubmit () {
  myService.getSearchResult({search:search_txt.text});
}

// Responder function for result
function getSearchResult_Result (result_rs) {
  var temp = "";
  temp += "There were " + result_rs.getLength();
  temp += " records returned.";
  results_txt.text = temp;
  mySharedObject = SharedObject.getLocal("products");
  mySharedObject.data.myResults = result_rs;
  // The following line binds the recordset to the grid
  gr.dataProvider = mySharedObject.data.myResults.items;
}

// Responder function for errors
function getSearchResult_Status (error) {
  results_txt.text = "There was an error: " + error.description;
}

// If the shared object exists, use it to set up the grid on load
// with data from its last use. Calling getLength() demonstrates
// that methods of the RecordSet class work

mySharedObject = SharedObject.getLocal("products");
gr.dataProvider = mySharedObject.data.myResults.items;
var temp = "";
temp += "There were " + mySharedObject.data.myResults.getLength();
temp += " records returned.";
results_txt.text = temp;

Using a SharedObject would allow you to use an application offline using data stored in the object rather than tripping to the server.

Add comment (3)
View comments

New blog on RIAs

Monday, December 15, 2003 11:59:05 AM

A new blog by Steven Webster and Alistair McLeod has started up this month that features information on rich Internet applications. Steven is the author of several books, including Reality J2EE: Architecting for Macromedia Flash MX, which shows Flash Remoting at it's best--powering enterprise-level rich Internet applications. There is already some outstanding content on the blog: http://www.richinternetapps.com/

Add comment (0)
View comments

Overriding the gatewayUrl

Friday, December 12, 2003 1:03:21 PM

There are an awful lot of problems in the forums dealing with the Flash Remoting gateway URL. If you are developing on a local machine, you might be using http://localhost/flashservices/gateway. If you are using the built-in ColdFusion web server, it might be http://localhost:8500/flashservices/gateway. When you upload to a server, you'll have to change this to the server URL, like http://www.myserver.com/flashservices/gateway and recompile the movie.

One way around the problem is to dynamically populate the gatewayUrl variable using server-side code in the object tag. In your Flash movie, you'll need to use the setDefaultGatewayUrl() method (note that it is Url and not URL for compatibility with Flash Player 7):

var myURL = "http://localhost/flashservices/gateway";
var servicePath = "com.flash-remoting.someService";
// Connection hasn't been initialized; create connection and service objects
if (initialized == null) {
  initialized = true;
  NetServices.setDefaultGatewayUrl(myURL);
  var myConnection_conn = NetServices.createGatewayConnection();
  var myService = myConnection_conn.getService(servicePath);
}

And then on your HTML page (must be a server-side page -- ColdFusion version shown here), use flashvars to pass the gatewayUrl variable to the Flash movie. The gatewayUrl variable will override your settings in the .fla. Using this method, the movie can be transported from one server to another without recompiling the movie or changing code:

<!--- Use the cgi variable http_host to get current domain --->
<cfset variables.gatewayUrl = "http://#cgi.http_host#/flashservices/gateway" />

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase= "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab
#version=6,0,65,0" width="190" height="270">
<param name="movie" value="/assets/myFlashFile.swf" />
<param name="flashvars" value="gatewayUrl=<cfoutput>#variables.gatewayUrl#</cfoutput>" />
<param name=quality value=high />
<embed flashvars="gatewayUrl=<cfoutput>#variables.gatewayUrl#</cfoutput>"
src="assets/myFlashFile.swf"
quality=high
pluginspage= "http://www.macromedia.com/shockwave/download/index.cgi?
P1_Prod_Version=ShockwaveFlash"
type="application/x-shockwave-flash"
width="190" height="270"></embed>
</object>

You can take this a step further to work with https or http by using some more server code -- testing the cgi.https variable in ColdFusion:

<cfparam name="variables.http" default="http://" />
<cfif cgi.https EQ "on">
  <cfset variables.http = "https://" />
</cfif>


<!--- Use the cgi variable http_host to get current domain --->
<cfset variables.gatewayUrl = "#variables.http##cgi.http_host#/flashservices/gateway" />


<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab
#version=6,0,65,0" width="190" height="270">
<param name="movie" value="/assets/myFlashFile.swf" />
<param name="flashvars" value="gatewayUrl=<cfoutput>#variables.gatewayUrl#</cfoutput>" />
<param name=quality value=high />
<embed flashvars="gatewayUrl=<cfoutput>#variables.gatewayUrl#</cfoutput>"
src="assets/myFlashFile.swf"
quality=high
pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?
P1_Prod_Version=ShockwaveFlash"
type="application/x-shockwave-flash"
width="190" height="270"></embed>
</object>

Using this method, I can develop locally and upload to my server without changing a thing.

Add comment (8)
View comments

Clearing a CFQUERY cache

Friday, December 05, 2003 1:57:41 PM

One thing I like to do when building queries that don't change a lot (such as a query feeding a dropdown list, or one feeding an RSS feed) is to set the cachedwithin attribute of the <cfquery> tag. This allows for the server memory to hold the results of the query, rather than hitting the database every time a user requests a query (through a Flash Remoting call or a ColdFusion page). This can speed up a page considerably -- especially in a RIA where every millisecond counts. One problem with this is that if you add new data to the database table, the query that is displayed will be out of date. If you change the structure of the query -- or the stored procedure or view that feeds the query -- your page may throw an error. To avoid this, what I usually do is set up a page with this bit of code and name it clearcache.cfm:

<cfobjectcache action="clear">
<cflock name="serviceFactory" type="exclusive" timeout="10">
  <cfscript>
    factory = CreateObject("java", "coldfusion.server.ServiceFactory");
    datasource_service = factory.datasourceservice;
    datasource_service.purgeQueryCache();
    factory = '';
  </cfscript>
</cflock>

This has to be run manually and is fine for most purposes, but I finally decided to automate it and put it into a CFC named Services.cfc that can be called by any of my database insert and updates. The CFC is as follows:

<cfcomponent>
  <cffunction name="clearCache" access="public" returntype="boolean">
    <cftry>
      <cfobjectcache action="clear" />
      <cflock name="serviceFactory" type="exclusive" timeout="10">
        <cfscript>
          factory = CreateObject("java", "coldfusion.server.ServiceFactory");
          datasource_service = factory.datasourceservice;
          datasource_service.purgeQueryCache();
          factory = '';
         </cfscript>
        </cflock>
        <cfcatch>
          <cfreturn false />
        </cfcatch>
      </cftry>
    <cfreturn true />
  </cffunction>
</cfcomponent>

Now, whenever I have a cached query that is updated, I make a call with a simple call to the component, usually right after the <cfquery> where the data is inserted or updated:

<cfscript>
  myService=createObject("component","Services");
  myService.clearCache();
</cfscript>

Or simply:

<cfobject component="Services" name="myService" />
<cfset myService.clearCache() />

Add comment (3)
View comments

Debugging ColdFusion. . .or not

Thursday, December 04, 2003 4:27:41 PM

Sean Corfield posted an item about debuggers titled Debuggers: What are they good for? In it, he cited two articles that talked about debuggers in Java, and how there are often better methods of debugging ( Debuggers are a wasteful Timesink by Daniel H. Steinberg and Debuggers: a modern 'Dr. Jekyll and Mr. Hyde' by Andreas Schaefer.) I have to strongly disagree with this viewpoint. For one, the methods that they talk about that they use in place of a debugger are nothing more than workarounds to not having a debugger or not being able to use it to its best advantage. To my mind, an IDE without a debugger is not an IDE. One of the articles talked about sprinkling your code with print statements. That is mind blowing to think that this is somehow better than setting a break point and being able to examine a stack trace, all objects and variables, and execute immediate statements from the break point. If you've ever worked with a proper debugger, it puts you in control of your programming. A good debugger puts you inside of your program, with access to anything you need at any time.

I was going to post a blog item about a new tool I discovered, and this is as good a time as any since it relates to the current topic. I just discovered a PHP IDE called PHPed. You can find a trial version at http://www.phped.com/. This is the kind of tool that would make me switch to PHP from ColdFusion -- it's that good. We ColdFusion developers have never had a really top-notch IDE, and now we don't even have one. Homesite+ eliminated the debugger that was in CF Studio, and DW is more of a wysiwyg design application. . .not much for a coder. There is no code environment with step debugging. Working in PHPed makes it a pleasure to build a web application. You can set a break point, hover your cursor over variables and objects to see their values, execute statements in the immediate window, and view a stack trace that traces the execution path of your code through functions, pages, and include files. Trying to debug ColdFusion code is a lot like debugging Basic on a Commodore 64 -- <cfdump>, <cflog>, and <cfoutput> statements sprinkled in your code. It's cut-and-paste debugging at it's most primitive. It really is a shame that the first web application server (ColdFusion) still does not have an IDE. I can write CF code pretty fast, but I think I could double my output if I had a good debugger.

Debugging in Flash is a bit of a nightmare as well. The debugger is fairly primitive, but it sure beats not having one. My article on debugging in Flash will be on Community MX next week. The NetConnection debugger is not really a debugger: it is a simple log viewer, if nothing else. Still, it's hard to build Flash Remoting applications without it.

Add comment (2)
View comments

1-5 | 6-6