Thursday, November 20, 2008

ADO Timeouts: Connection vs. Command vs. RecordSet

The Problem

An interesting bit I learned today is that if you need to extend the time limit for an intensive SQL query or procedure executed using ADO, setting only the commandTimeout property of your ADODB.Connection instance is not sufficient. You will see that you have extended the connection time limit, but queries will still time out within the default limit of 30 seconds.

Example
Using VBScript in ASP 3:
set con = createObject("ADODB.Connection")
con.open connectionString
con.commandTimeout = 60

set command = createObject("ADODB.Command")
command.activeConnection = con
command.commandType = adCmdText
command.commandText = sql
command.execute
response.write command.commandTimeout 'Actually 30 (the default).

The Solution

You must also set the commandTimeout property on the ADODB.Command or ADODB.Recordset being used. Otherwise those objects will use the default time limit of 30 seconds because they do not inherit the time limit from the associated ADODB.Connection instance.

Example
Using VBScript in ASP 3:
set con = createObject("ADODB.Connection")
con.open connectionString
con.commandTimeout = 60

set command = createObject("ADODB.Command")
command.activeConnection = con
command.commandType = adCmdText
command.commandText = sql
command.commandTimeout = 60
command.execute
response.write command.commandTimeout 'This is now 60 seconds.

See this Microsoft Tech Note for more.

Friday, November 14, 2008

AS3 Tween class randomly stops during animation

I gave the new AS3 Tween class a whirl to perform some simple animation entirely via ActionScript, rather than sharing the responsibilities between ActionScript and the Timeline.

It worked great...most of the time. The rest of the time, the Tweens would randomly decide to stop -- mid-animation -- without throwing any error as to why. "Most of the time" just doesn't cut it.

The Problem

Here is a simplified example of this situation:

package
{
   import flash.display.*;
   import fl.transitions.*;
   import fl.transitions.easing.*;

   public class SomeContainer() extends Sprite
   {
      ...
      public function animate(o:DisplayObject, x2:int, duration:uint)
      {
         var tween:Tween = new Tween(
               o,
               "x",
               Regular.easeOut,
               someDisplayObject.x,
               x2),
               duration);

      }
   }
}

When invoking animate(), the tween works most of the time, but randomly it stops.

There is no warning of this problem in the ActionScript 3 reference manual, but this Adobe Devnet article contains some fine print that reads:

Note: Consider variable scope when using the Tween class. If a tween is created in a function, it is important that the variable's scope exists beyond the function itself. If a tween is stored to a variable of local scope, ActionScript garbage collection removes the tween as the function completes, which will likely be before the tween has even begun.

So the problem with this scenario is that the Flash Garbage Collector does not care whether the function-scoped variable is still working asynchronously or not - it destroys objects simply by reference counts and in this case nothing outside of the function references this Tween instance.

The Solution

To fix this, simply scope the Tween instance to a class-level variable (a private attribute) rather than a function-level variable. For example:

package
{
   import flash.display.*;
   import fl.transitions.*;
   import fl.transitions.easing.*;

   public class SomeContainer() extends Sprite
   {
      ...
      public function animate(o:DisplayObject, x2:int, duration:uint)
      {
         tween = new Tween(
               o,
               "x",
               Regular.easeOut,
               someDisplayObject.x,
               x2),
               duration);
      }

      private var tween:Tween;
   }
}

This way, the garbage collector sees that something outside of the scope of the function still references the Tween instance created within the function, so it does not destroy the instance.

Wednesday, November 5, 2008

Installing CS4 - Flash 10!

As if it weren't enough of a treat to find out today that Barack Obama was elected as our 44th US President, my day got even better because Adobe CS4 just arrived at the office! I know there's no comparison here, but being given so much in one day is overwhelming!

I'm looking forward to playing with all of the new features in Flash 10 including the new z-axis for 3d transformations, the bones tool for creating skeleton-based animations, and the object motion editor (ripped from After Effects) to replace somewhat clunky keyframe motion.

And to turn it up another notch (BAM!) a free Zinc 3.0 upgrade to 3.0.11 was released to include Flash 10 SWF support.

Tuesday, November 4, 2008

Inter-database Communication is Easy in T-SQL

Problem

You need to obtain data from one data source to process and store in another. You don't want your server-side-script to use two connection objects and be the slow middle-man between them, as in the diagram on the left.

Slow with two SQL Server connections and scripting vs. Optimal with only one connection.


Solution

If both data sources are databases on the same MS SQL Server, it's a piece of cake to do optimally with just one connection object and pure T-SQL.

Just do the following:
  1. Set up Security - Add the user of the destination database as a user of the source database with at least db_datareader access.

  2. Prefix foreign tables with Schema - In your SQL that writes to the destination-database, prefix all tables housed in the source(foreign)-database with their "fully qualified" position in the schema to indicate which database they reside in, as illustrated in the example below.

    Example
    Table tblSource is from of the ForeignDB database, but tblDestination is from the active database.
    insert into tblDestination (colA, colB)
    select col1, col2
    from [ForeignDB].dbo.tblSource

Thursday, October 23, 2008

Zinc COMPort Phone Dialer Freezes

Background

A photo of the building directory kiosk and phone handset which uses my application built with Flash and Zinc.The same touch-screen kiosk I previously wrote about requires phone dialing capabilities since the purpose it serves is a Building Directory in the lobby of a government office building.

I used MDM Zinc because I can retain all source code in Actionscript (Flash), yet utilize the computer's modem to dial phone numbers via the Zinc COMPort API (whose phone numbers are retrieved from an MS SQL database via Zinc's ODBC API).

At the start of this project while evaluating Zinc as an option, the first thing I did was create a phone dialer prototype using Flash and Zinc to prove it would work. It worked perfectly. But when integrating it into the system at the tail end of the project and adding some robustness to it, I ran into a hitch that caused the Zinc-compiled application to crash.

Problem

In order to gracefully recover should the modem throw a "No Carrier" or "No Dialtone" error, I wanted to hang-up the line then alert the user of this error. However, when invoking the hang-up immediately when Flash is asynchronously notified, the Zinc-compiled application freezes indefinitely.

Example
Part of the constructor of my PhoneDialer AS3 class
mdm.COMPort.onCOMPortData = function(e:Object)
{
   var data:String = StringUtil.trim(e.data);

   logger.logLine("onCOMPortData() - timeCode: " +
      e.timeCode + ", data: " + data + ".");

   if (data == "NO CARRIER")
   {
      hangUp(); //freezes here

      dispatchEvent(new PhoneDialerEvent(
         PhoneDialerEvent.NO_CARRIER));
   }
   else if (data == "NO DIALTONE")
   {
      hangUp(); //freezes here

      dispatchEvent(new PhoneDialerEvent(
         PhoneDialerEvent.NO_DIALTONE));
   }
   else if (data == "OK")
   {
      //Dial was successful!
      dispatchEvent(new PhoneDialerEvent(
         PhoneDialerEvent.OK));
   }
};

Method in my PhoneDialer class:
public function hangUp()
{
   if (!pickedUp)
      throw new AlreadyHungUpException();

   logger.logLine("Closing COMPort.");

   mdm.COMPort.close(); //actually freezes here

   pickedUp = false;
}


Solution

The solution was to not invoke mdm.COMPort.close() within the onCOMPortData handler. Instead, I alert the user of the error which also instructs him/her to click the Cancel button on the Dialing screen. Then the cancel button invokes hangUp(), which works without a hitch.

Also one other item of interest: even though Zinc was designed to support Actionscirpt 3, the first line of code above, mdm.COMPort.onCOMPortData = fuction(... triggers a warning when compiling to SWF - "Warning: 1072: Migration issue: Class is not a dynamic class. Instances cannot have members added to them dynamically." Since this is just a warning, it does not cause any problems during run-time, but it's interesting that they did not switch to use the standard addEventListener method of event-handling that has been implemented as a standard across AS3 components.

Conclusion

In a perfect world, this error would never happen if the kiosk were always connected to the phone line and the phone line were to always provide a dial tone. But since those are possibilities, the application is now robust because it properly recovers from those scenarios instead of crashes.

Thursday, October 16, 2008

SharedObjects - "Cookies" that Don't Go Away

Flash SharedObjects are an easy way to preserve application state on the client-side between sessions.

I have used them for Flash CD-ROM applications that need to persist data on the user's local machine and for Flash web applications that needed a "cheap local database".

But Flash SharedObjects pose a serious privacy problem for anyone who may have access to your computer.

Privacy Problem

The default Flash Player settings give 100KB of local data storage to any SWF from any web site or Flash application.

One may expect that since Flash Player runs in the context of a web browser, that when you tell your web browser to clear its cache, cookies, or other private data, that it will also remove the Flash Player SharedObject data - at least the ones added via your active web browser.

Unfortunately, that is not the case - Flash Player keeps all of your SharedObjects until you explicitly remove them.

See for yourself - on a Windows XP machine browse to this folder (Folder #1):

C:\Documents and Settings\<Your Username>\Application Data\Macromedia\Flash Player\#SharedObjects\<Random Letters and Numbers>\

You may be surprised to see that folder is filled with the domain-names of every web site you have ever visited that contained a Flash file that persisted some data.

There is also another folder that houses more SharedObject data (Folder #2):

C:\Documents and Settings\<Your Username>\Application Data\Macromedia\Flash Player\macromedia.com\support\flashplayer\sys\


So how do you remove these SharedObjects and how do you prevent them from getting there in the first place?

Solutions

To remove your existing Shared Objects, follow these steps:
  1. Delete existing SharedObjects

    Go to the Website Storage Settings Panel of the Flash Player Settings Manager (yes, the manager is on a website, not within software). Move the slider down to "None".

    This removes all files from the Folder #1 (above), but for some reason does not remove from the second folder.

  2. Delete Contents of Folder #2

    Since the previous step did not empty Folder #2 (above), you need to manually delete the contents of that folder.
To prevent future SharedObjects from being saved on your system in the future, you can do this globally for all web sites using the Global Storage Settings manager.

Or set your SharedObject storage settings on a site-by-site basis by doing this:
  1. Right-click on a visible Flash object in a web page.
  2. Click settings.
  3. Click on the tab with the "folder" icon - Local Storage.
  4. Use the slider to change the data limits for that particular web site.

    Wednesday, October 15, 2008

    Zinc Crashes on Select from Database

    Background

    I'm using Zinc 3 as a wrapper around a Flash 9 / ActionScript 3 application for a touch-screen kiosk that requires database and comport access.

    Problem

    The Zinc application crashes when calling mdm.Database.ADO.getData() to obtain the results of a query (either SELECT or stored procedure) executed by mdm.Database.ADO.select() IF the query produces an empty result set. I'm connecting to a MS SQL Server 2005 database, but this issue probably happens with any ADO connection.

    Example
    mdm.Database.ADO.select(sql); //if this results in 0 records...

    if (mdm.Database.ADO.error())
       throw("handle error here");
    else
       arr = mdm.Database.ADO.getData(); //crashes here

    Solution

    The undocumented but simple way to prevent the crash is: prior to calling getData(), you must first check ensure that getRecordCount() is not zero.

    Example
    mdm.Database.ADO.select(sql);

    if (mdm.Database.ADO.error())
       throw("handle error here");
    else if (mdm.Database.ADO.getRecordCount() == 0)
       arr = [];

    else
       arr = mdm.Database.ADO.getData();

    Conclusion

    Ideally Zinc would just return an empty array if no records were found, but since it doesn't, it's nice to know there is an easy fix. I am content with minor problems like this because the benefits Zinc offers - including access to databases and the comport directly from Actionscript - far outweighs the bugs it has.

    trace("Hello World!");

    I finally decided to start a blog to record lessons learned from the trials & tribulations along my journey of coding for a living, with the hope that these solutions will save even just one headache for one fellow coder.

    This blog will focus mainly on Flash ActionScript 2 and ActionScript 3 but will cover anything related such as Zinc, JavaScript, SQL, XML, or anything else that causes me grief but results in a helpful solution.

    About the Author
    My name is Ricky Blaha. I am a senior programmer for ICS Learning Group in Severna Park, Maryland, USA, as well as a freelance programmer doing business as Interstellar Multimedia -- both concentrating in the multimedia, web-development, and e-learning arenas.

    Coding professionally since 1999, my journey started with ColdFusion 4.5 with Oracle and XHTML, CSS and JavaScript. It later evolved into ASP3 development with SQL Server, then some PHP with mySQL. Then in 2002 the opportunity arrived to learn and use Flash 5 and Actionscript 1, and ever since, developing CD-ROMs, touch-screen kiosks, e-learning applications, and web applications with Flash have been my major focus and greatest source of enjoyment.

    In 2008 I decided to back up my experience to become an Adobe Certified Flash MX 2004 Developer. In Fall 2009 I will finally complete my BS in Computer Science with a minor in Strategic and Entrepreneurial Management from UMUC.