•
We’ve released support for video playback within Sharendipity and we’re eager to see what you can do with it!
Included in this feature are three core integration points for video:
- Native support of the YouTube video player inside your apps
- Support for sharing of Flash Video (FLV) files within the community
- Support for Flash Video (FLV) specified by URL
YouTube support
Google recently announced the addition of native, ActionScript3 support for the YouTube Player API. This enabled Flash developers to add support for embedding the YouTube player inside their Flash applications.
And now we’ve provided an abstracted interface to the YouTube player for you, our Sharendipity creators. You can now add a YouTube video to any primitive actor in the system by simply providing the URL. There are base actions that let you play, pause and rewind the video within the logic builder.

With these four basic primitives, you can quickly build complete YouTube playback applications with UI controls to pause, play, and surf video content.
Check out these fun little mini TVs for an example of how you can create new ways of surfing YouTube videos.
Sharing FLVs just like images
Just like images, FLV files can be shared and re-used by everyone in the Sharendipity community. The work flow for adding FLV files is identical to the one used for images and sounds except there is now a new category in the asset manager called “Video”. Please read the post on sharing images to learn more.
To reuse the FLVs found in the asset manager, simply drag a thumbnail from the manager and drop it on the desired actor in your application.
Flash video support by URL
If you would prefer to access existing Flash video on the web, you can simply drop the URL into the image property for any primitive actor in your application. We’ve implemented the ActionScript 3 video player and it will play any video simply by pointing to its URL.
If the URL points to a YouTube video, we will automatically insert the YouTube player.

Tags:
API,
google,
YouTube
•
Sharendipity has had an implementation of the Facebook API for quite a while now. However, you had to be logged in through our Facebook application or have your Sharendipity account synced up with your Facebook account to access your social graph data.
We’re thrilled to announce that we’ve implemented Facebook Connect. Now if you sign in to Sharendipity using your Facebook account, you and the applications you use on sharendipity.com will have full access to your social graph!
In this post, we’ll outline our experience implementing Facebook Connect using the Facebook ActionScript API.
In addition to the login workflow, we also needed to switch our feed stories over from the old templated style to the new stream publish method. Unfortunately this isn’t that straightforward because of the stream publish method requires you to either prompt the user to be able to publish on their behalf, or prompt them to publish the story. Previously, our server could take care of the publishing, but you can’t prompt the user that way. So a lot of the Facebook feed functionality needed to move to the client.
Fortunately, Facebook and Adobe just announced a new Facebook ActionScript API. Cool, right? Well… sort of. I’ll admit that we really only needed it for publishing feeds, so our use case might be a little different than some. However, the documentation is pretty sparse, as are the examples, and the error reporting is nearly non-existent. But you can figure it out if you want. I did, but not before I realized we couldn’t use it to publish feeds the way we wanted to. I thought I’d list what I learned here to help you out, it might prevent you from having to read all the code in the API yourself.
Before You Start
If you want to be able to prompt users for feed stories as you would with FB.Connect.streamPublish through the ActionScript API, you’re out of luck. The ActionScript API uses the REST-based calls for stream.publish, which requires that you prompt the user for rights to publish to their wall on their behalf. We don’t like that and would rather prompt the user, providing an opportunity to add their input every time.
Also, if you are publishing on behalf of the user, you need to build the API yourself, because there’s currently a bug in JSONEncoder (version 3.3) which might prevent anything from happening.
Always use FacebookSessionUtil
It’s possible to create a WebSession directly, just don’t. It should really be package private so you can’t even do it. The problem is that if you create a WebSession and try to post something using it (e.g. using a PublishPost object), the session will never have been set in the IFacebookCall, and you’ll get a null pointer error.
In fact, you don’t even need the WebSession. Once you’ve initialized FacebookSessionUtil using your API Key and the loaderInfo, all you need is the Facebook object to post something. This is important because Facebook.post() will operate on the post passed in, which internally sets the session to avoid that null pointer.
Never Pass Your Application Secret to FacebookSessionUtil
Almost all of the examples I could find used the application’s secret. This is great for debugging, but you don’t want to do it in production because someone can hijack your Facebook application if they can get the secret (e.g. through decompilation of your swf). Instead, create the FacebookSessionUtil and get the Facebook object like this:
var util:FacebookSessionUtil = new FacebookSessionUtil(YOUR_API_KEY, null, loaderInfo);
facebookRef = util.facebook;
|
Note that we’re passsing in null in place of the application secret. Internally, FacebookSessionUtil will look for the correct parameters from the passed in FlashVars to create the session, so:
Make Sure Your FlashVars are Initialized
FacbeookSessionUtil explicitly looks in the loaderInfo that is passed in for the correct signature parameters, which it uses to create a WebSession for you. If those don’t exist then you’ll get a DesktopSession. The WebSession is the only one that uses the Session Secret. This means that if you aren’t setting those parameters before embedding your SWF file, you must set them in the loaderInfo before creating the FacebookSessionUtil object.
In our case, the user may not be logged in to Facebook when they first launch our Application. If they log in using Facebook Connect, then we must get the session information in JavaScript and pass it into our app using the ExternalInterface. So in ActionScript we have something like this:
ExternalInterface.addCallback("fbUserLoggedIn", handleFBUser);
|
Then in JavaScript, our function for handling the user login looks like this:
FB.Connect.requireSession(
function() {
mtSWFObject.fbUserLoggedIn(
FB.Facebook.apiClient.get_session().session_key,
FB.Facebook.apiClient.get_session().secret,
FB.Facebook.apiClient.get_session().uid,
FB.Facebook.apiClient.get_session().expires,
FB.Facebook.apiClient.get_session().sig);
});
|
And the last piece is that we need to implement handleFBUser so that it can write the correct parameters into the loaderInfo object so that the FacebookSessionUtil object can be created correctly:
private function handleFBUser(sSessionKey:String,
sSessionSecret:String,
sUserID:String,
iExpires:int,
sSignature:String):void {
loaderInfo.parameters["fb_sig_session_key"] = sSessionKey;
loaderInfo.parameters["fb_sig_ss"] = sSessionSecret;
loaderInfo.parameters["fb_sig_api_key"] = YOUR_API_KEY;
loaderInfo.parameters["fb_sig_user"] = sUserID;
// now create the FacebookSessionUtil.
}
|
Using the FacebookSessionUtil object, you can then create a PublishPost object, and publish away, provided you have requested the stream.publish right for the user.
Conclusion
We currently provide most of the Facebook information via Web Services in Sharendipity, so we don’t need the ActionScript API right now. It would be more useful to us if we could prompt the user for feeds, but that doesn’t seem to be possible. In addition, it would be fantastic if you could log in via FacebookConnect when Sharendipity is embedded anywhere. You can’t do this via JavaScript for security reasons (you need to be on the domain for your Facebook application to log in correctly). I think that you might be able to login if you create the FacebookSessionUtil using your application secret, but I’m wary of sending that across the wire, and in any case, the dialogs used in the API are implemented using AIR-based NativeWindows, so I don’t think it would work on the web.
Tags:
ActionScript,
Adobe,
API,
Facebook,
Flash
•
Over the past few months we’ve been rapidly evolving the Sharendipity application editor toward a full-featured Integrated Development Environment, or IDE, similar to the environments used by professional programmers. These changes reflect the fact that many of our users today are highly technical, and computer users in general are becoming more and more comfortable with sophisticated environments, such as Microsoft Office or Photoshop.
For instance, we changed our menuing system, replacing the “cute” characters at the bottom of the screen with a more standard set of pulldown menus. While some users may have found the characters less intimidating, the majority of users preferred a standard set of pulldown menus.
We’ve also recently released developer tools including a profiler for optimizing application performance.
Today we’re releasing an additional set of powerful features that simplify application development and debugging.
Tabbed window management
Once an application had a few custom actors or types, the class, method, and behavior editors would become unwieldy, forcing the author to waste time arranging windows.
Editors are now launched in tabbed windows that keep things organized:

New editors are launched on tabs on a single tabbed window. Or tabs can be “torn off” to create new tabbed windows, which can be useful when copying logic statements between methods or behaviors.
In addition, an integrated window manager now places windows in more logical positions, avoiding the player window, remembering previous window positions, and tiling windows that would otherwise launch on top of each other.
Debugging Tools
Previously we released a simple breakpoint capability. Our new release includes full debugging tools, allowing breakpoints to be set and allowing line-by-line stepping through the code as it executes.
To add a breakpoint, simply double-click on the left side of a statement. A stop sign appears to indicate the breakpoint.

When this line of code is executed, execution of the thread will be paused. The “Problems” indicator will turn on when a breakpoint is encountered; if the editor is not already open you can access the breakpoint through the Problem Viewer.
A green arrow indicates where execution is stopped. You can move the mouse over any variable to check its value.

(An exception will produce the same view, except the arrow will be red. And a yellow arrow indicates that execution is stopped within a method called from that line of code.)
The Breakpoints view, accessible from the Advanced… menu, displays all breakpoints and can be used to temporarily disable breakpoints. Double-click on an entry to launch the corresponding editor.

To step through the code line-by-line, use the Thread viewer, which is described below.
Threads
Sharendipity is a multi-threaded environment. When a behavior is triggered, it is executed on its own execution thread. The application executes at a given frame rate, and on each frame the active threads are each executed for a limited amount of time. This keeps the system interactive and allows background processing, for instance a fade effect that occurs as the game continues to play.
The Thread viewer displays all active threads. It also displays threads that are suspended due to a breakpoint or an exception.

In this example a single thread is executing and is suspended due to a breakpoint. The “stack trace” shows exactly where the code is currently executing: the “fetch words” behavior has called the “setup puzzle words” method which has then called “place word randomly”, which is where our breakpoint is positioned.
The Play button will resume execution of the thread, until it hits another breakpoint or finishes execution.
The Step and Step into buttons can be used to step line-by-line through the code, which can be very useful for debugging. The Step function steps to the next line within the method or behavior. the Step Into button will step down into the method that is called from the current line. If the current line does not call a user-defined method, Step Into will simply step to the next line within the method/behavior.
These powerful tools are only possible because Sharendipity is built on a very sophisticated object-oriented architecture and runtime environment. This core architecture and toolset makes Sharendipity a powerful tool for you to build interesting interactive web applications.
•
Several web service interfaces have been built and shared within the Sharendipity community including services for Facebook, Twitter, Flickr, Posterous, and Google Docs. Using these components you can quickly and easily access the data from these sites/services.
But what happens if you can’t find the service you’re looking for? Or if you want to improve on one of the existing services and make a better one yourself?
This post is here to help. We’ll walk you through some of the basic elements for building a new component that interfaces with an external web service. To get started, first launch the Sharendipity editor.
Create new object type
Creating a new type provides you with the ability to define custom assets that perform a particular job or store specific data. They don’t necessarily have to be a displayable actor inside your World. The definitions for these new assets are entirely up to you.
In the case of a web service, you’ll define the location of the service, describe inputs, and then define custom actions that let the users of your service interact with it.
- Open the Explorer dialog and select New from the Types tab.

- Name your new type. For example, “Twitter Service – public timeline”
- Declare that your new type “is a REST Web Service” by clicking the + sign next to its name, and selecting the is a button. You can find the REST Web Service type by selecting Other… and navigating to the Local->Types tab in the Explorer that is launched. The following diagram highlights this navigation.


Default properties
Once you have the REST Web Service type defined, you must specify the details of your web service by initializing a couple of parameters.
Custom properties
Many web services have optional and required parameters. For instance, the Posterous API lets you specify the subdomain of the site you are reading from. In order to define parameters, you must define custom properties in your type that are of type REST Input.
Each REST Input has a name and value pair. The name value should be the parameter name as defined by the web service API you are trying to access. In the Posterous example, the name field is ‘hostname’. The value field carries your parameter value. When the web service is invoked, each REST Input is automatically appended to the end of the URL property.
If you were to look at the full URL when the service is invoked, you’d see something like the following:
http://posterous.com/api/readposts?hostname=gregtracy
As you are making calls to the web service, you can simply manipulate the value parameter of the REST Input to change your query to the respective web service.
Web service actions
By default, there is a single method defined for all web service types called invoke web service. This is the mechanism by which you initiate a call to your web service. It can be called internally as well as externally by users of your component.
Just like other objects in the system, you can create your own behaviors, methods, and properties for your new type. For instance, you may want to create your own invoke method which takes parameters that are passed to the web service. For example, passing in a user ID to a Facebook web service to specify the user whose profile you would like to access.
Referencing the service
Once you’ve defined your web service type, you can share it with the rest of the community with the Save option found in the object builder. Otherwise, the web service will be saved along with the application you’ve defined it in.
Whether or not you share it, the new type can now be accessed from anywhere else in the application.
- If you drag it into your World and drop it, you will be prompted to create a new custom property for the World.
- You can drag it into a behavior or method and drop it to create a local variable inside your logic.
- It will also be accessible from the Other tab when you define new properties anywhere within your application.
Just remember that if you don’t save the service by itself, you can only access is from the Local tab of the Explorer within the current application. If you do save it, it will appear in the Types tab for everyone.
Tips for better reuse
Creating an abstraction of the web services call is a nice feature by itself. However, it becomes most useful when you provide really easy access to the data that is returned. For instance, rather than simply providing the invoke web service call and letting the callers parse the data returned, try creating methods that do that parsing for them.
- The Twitter service has a method that returns an array of Twitter Status types.
- The Posterous service has a method that returns an array of Posterous Blog Post types.
- The Facebook User service has a method that returns an array of Facebook User types.
Each of these services define new methods that call the invoke web service method internally and parse the return data automatically. This way, users of the services don’t have to worry about how any of the data is formatted.
For more details, including specifics for the Facebook integration, check out the web services page on the wiki.
Tags:
create,
howto,
invoke,
web services
•
As Sharendipity continues to mature, we are beginning to add more advanced features to the editor that can aid the developer in building his or her application in a significant way.
Traditional programmers using professional development environments are used to having certain tools available to help them troubleshoot their applications. Creators in Sharendipity, including our non-programmers, also require methods for debugging problems and tracking down performance issues. This post highlights a few of the features we’ve added that will help improve your development experience.
If you have any feedback about how we can continue to improve the tools please let us know. We’re always listening.
The Console Window and Trace Statements
One of the more basic troubleshooting tools developers use is a console window that provides a simple way to display arbitrary information about the program. Sharendipity now has a Console Window that can receive text output from an application. The console can be accessed through the Director menu:
This will bring up the console window, shown here with output from the Teslaformer game:

You can display text on the console window using the “trace” action available in any Behavior or Method of a class in Sharendipity. The trace statement can also take just about any type. You can even concatenate values together using the “+” operator as shown here:

The console can be useful for monitoring all kinds of activity within an application. For example, you can print messages to the console simply to let you know when a particular behavior is running, or you can print out individual property values as they are changing.
The Problem Viewer
The Problem Viewer is a dialog that displays logic errors to the developer that prevent the application from running correctly. When there is a problem in an application, a red notifier saying “Problems” will appear in the top-left corner of the editor. Clicking on this will bring up the Problem Viewer dialog.
The viewer displays basic logic errors that prevent applications from starting (e.g. forgetting to assign a value in a property set action) as well as errors that occur while the application is running (e.g. your logic is expecting objects to be present and they aren’t).
Double-clicking on an item in the Problem Viewer will take you directly to the location of the problem. You don’t need to go searching around for the location of the error.
Below is a view of the Problem Viewer in an application I set up to be broken intentionally. You can see that there are a lot of issues and the Problem Viewer allows me to see exactly which classes and methods they’re coming from.

The Profiler
The Sharendipity editor also includes some new functionality that lets you analyze which parts of your application are taking longer to execute. Similar to the Console Window, the profiler can be accessed from the Director menu:
Clicking on “Performance…” in the director menu will bring up the Performance Management dialog, which looks like this:

In this view, Profiling has already been enabled and data is being collected in the running application. From the menu you can view the current profiling data, and you can also clear the profiling data. Viewing the profiling data will give you a view similar to this:

Similar to the Problem Viewer, double-clicking on one of the rows in the Profiler will allow you to see exactly which calls are taking all of the time, including breakdowns by constructs such as “if” statements:

Breakpoints
Like most debugging tools, Sharendipity also offers a way to halt execution of a thread to examine the current variable data. The current implementation uses a “Breakpoint” statement. Under the hood, this throws an exception that will show up in the Problem Viewer, preventing following statements in the behavior or method from running. Opening the problem viewer and double-clicking on the Breakpoint exception will bring you to the Behavior or Method where the breakpoint was hit.
The really handy part is that now you can mouse over variables in the Method Builder or Behavior Builder to see their values:

The Sharendipity Wiki
I’ll also take a second to mention that a lot of information is documented over at the Sharendipity wiki. If you happen to get stuck, this is a great place to start. There are also forums there that allow you to ask questions about any of the topics on the wiki and we’ll respond as soon as we can.
The Complete Picture
With the addition of these new developer tools, the platform is really starting to display its true potential. Not only is Sharendipity a complete authoring environment for Flash games and applications, it provides distribution as well as monetization opportunities for the developer, all built on a platform designed for sharing and extensibility.
Tags:
breakpoints,
creation,
debugging,
game,
performance,
profile
•
We’ve talked in the past about a creative, non-gaming example that visualized Google spreadsheet data. Since that post, we’ve had a few people inquire about some of the details behind that application. There’s a strong desire to visualize spreadsheet data, and this post outlines not only the Sharendipity components used, but also some of the hidden features of Google Docs that make the web services possible.
Web Service Components
The featured example uses a shared component type, “Google spreadsheet reader”. Internally, this component uses “Google Service – cell spreadsheet reader” to interface with a specific Google Doc. Both components are configured with a URL describing where the spreadsheet has been published. Note that this URL is not the URL you would see in your browser. Rather, it is a specific URL describing the published version. The steps for acquiring the publishing URL are below.

Google spreadsheet reader
This spreadsheet reader was designed specifically for visualizing a two-column layout. It assumes that the first column contains labels and the second column contains values. It is intended to be a convenience interface for these types of data layouts. If you’d like to access arbitrary data layouts, I recommend building new logic around the generic cell spreadsheet reader defined below.
Methods:
- getValue(String label) – Returns the value that corresponds to a specified label.
- getRowTuple(int index) – Returns a string for the specified index into the values. The string returned is of the form “label,value”.
- getValueMap() – Returns the hash map of all the data in the spreadsheet. It is a map of Strings and is keyed by the spreadsheet labels.
Google Service – cell spreadsheet reader
This web service is a raw conduit to your Google spreadsheet. It is the underlying web service used in the above reader as well. It assumes nothing about the layout of your data and provides a single method to access a specific cell. This reader uses a brute force technique for finding data so it is recommended that you cache the values once you’ve extracted them.
Methods:
- getCell(String cellID) – Returns the value for a specified cell. An example cellID would be “A3″ or “D104″, etc.
Accessing Google Doc Feeds
In order to access your Google spreadsheet through these components (or other Sharendipity web services) you must first publish the document. The components described in this post assume the data is published in a particular format as well. The following steps outline how to do this within Google Docs.
- Open up your spreadsheet from Google Docs
- Publish it using the blue “Share” button in the upper right hand corner of the document window. When the publishing dialog appears, click the “Start publishing” button to begin the publishing process.

- Next, change the link type from “Web Page” to “ATOM”

- Change the link type from “List” to “Cells”
The web service URL will be printed in the preview box. This is the URL that you will feed into the Google spreadsheet reader component using the URL property.
Consuming Google Components
The two existing Google components have customization points that make them easy to reuse. Each time you drag one of them out of the Explorer and into your application, you will be prompted to enter information for your spreadsheet, including the URL you configured in the previous section. The one caveat to this is if you define a variable inside a method or behavior that is of one of these types (rather than explicitly dragging it into your application). In that case, you must initialize the properties programmatically.
- The Google spreadsheet reader has the following configuration screen, and assumes a strict layout inside the spreadsheet. The screen has the same general form as other integration steps and was defined by the author of the component.

- The Google Service – cell spreadsheet reader has just one configuration step – describing the URL for your published spreadsheet feed.
These aren’t the only elements in the Food Drive application. However, they are the foundation. Once you have access to the data, it’s just a matter of using it to scale the objects you are using in the graph. In the Food Drive case, the bar graphs were created and their size was calibrated according to the appropriate value in the spreadsheet.
Now you’re ready to start visualizing your Google spreadsheet data! These components don’t meet your needs? You’d like to access the data in a different format? No problem… you can always create your own web service. We”ll follow up later with a post that describes this process in more detail.
Tags:
google,
google docs,
web services
•

We’re really excited to announce the integration of the Kongregate APIs within Sharendipity! This gives you yet another great syndication option for the games you build within Sharendipity and puts your games in front of one of the best Flash gaming communities online today!
Check out Teslaformer, the first game that uses the new integration.
The new Kongregate integration is exciting for a lot of reasons. First, Kongregate has long focused on providing a community where you can play free games, and they’ve done a really good job at it. As a result, there is an opportunity for game developers to get their games in front of a lot more eyeballs. The best games on Kongregate have millions of plays. And those that aren’t the best are provided with valuable feedback about what works and what doesn’t.
In addition, we’ve now provided you with a way to directly monetize your games by participating in the ad revenue sharing model within Kongregate. We want to foster a community of developers and provide them with opportunities to make money off of their creations. We think this feature is another step in this direction.
The Details
If you’re interested in making your game ready for Kongregate, there are really only a few things that you need to do. First of all, the high score action functions the same way on Sharendipity as it does on Kongregate. So if you add this to one of your actions:

your high scores will either be sent to Sharendipity, or to Kongregate, depending on where the file is hosted.
In addition, there is a new method that has been added that will let you report statistics to Kongregate:

When hosted on Kongregate, this will report your statistics through the Kongregate API so that they can be used to create challenges. Like Sharendipity achievements, Kongregate provides challenges that can be awarded to members of the community for playing games. However, the challenges are determined by Kongregate, not by the creator, so their API allows you to report statistics that can be used to create those challenges. For more information about the statistics APIs, check out Kongregate’s API documentation.
•
This week we announced a partnership with HarQen, a leading web telephony company, where HarQen will leverage the Sharendipity collaboration tools to enable its customers to build custom web applications that interface with the HarQen platform. In addition, HarQen will provide premium telephony components to Sharendipity customers through our component sharing architecture.
“Our vision is that HarQen will bring voice to the web across a wide range of diverse applications, and we know our customers will require tools to easily build custom web-based interfaces. Sharendipity helps us towards our goal of creating an ideal solution for businesses in the web-telephony space.”
- Kelly Fitzsimmons, co-founder and CEO of HarQen.
We’re really excited about this! Not only does it provide our customers with the ability to leverage an innovative technology inside their Sharendipity applications, but it gives us another opportunity to show off the depth of our tool set in a new niche. We’re looking forward to seeing what the HarQen customers are able to build.
Check out the full press release!
Tags:
announcements,
harqen,
partners
•
This post could be considered an addendum to our moving to flash series. I decided to post it because of the lack of good examples out there. I hope it helps out.
In moving from a multi-threaded environment to a single-threaded one you will commonly have to address how to handle long-running tasks in Flash. Since ActionScript is single-threaded, this means that we can’t just put the task on a background thread and handle it when it’s complete. If I had a feature request for the ActionScript language, it would be to make some of this easier (although I do understand why it isn’t there now, and I’d rather have real Abstract classes…).
If you happen to be looking for a way to do this, you might have run across a few other posts. All of them will tell you that you have to figure out how to break up your task into smaller bits that can be handled one frame at a time. They’ll probably also tell you that doing this for hierarchical tasks is really hard. I couldn’t find anyone that actually shows you how to do it though, so here goes:
The Hierarchical Operation
We do a lot of operations on XML hierarchies. Some of those hierarchies are fairly deep as well, so we need to be able to break up the task into multiple, smaller tasks. Let’s say that you have a function that looks like this:
public function runActionOnHierarchy(tRoot:IXmlNode, tAction:IXmlHierarchyAction) {
try {
tAction.nodeEncountered(tRoot);
}
catch (tEx:Error) {
// handle error
}
var tChildren:IObjectArray= tRoot.getChildren();
if(tChildren != null) {
var iSize:int= tChildren.size();
var tChild:IXmlNode;
for (var i:int=iSize-1; i>=0; --i) {
tChild = IXmlNode(tChildren.get(i));
runActionOnHierarchy(tChild, tAction);
}
}
}
This code uses some of our own interfaces but you should get the idea. This method just takes an action and applies it to every node in the hierarchy. Ideally, that action doesn’t take longer than a frame, or about 1/30th of a second (depending on your desired framerate, you can change this). If it does, you’ll have to break up the action itself but we’ll address that a little later.
The Pseudo-thread Task
Since we aren’t dealing with threads, we will refer to the operations we want to perform as tasks. Think of them as the separable operations that would have been part of a larger thread. Here is an interface for a task that will be run as part of a Pseudo-thread:
public interface IPseudoThreadTask {
/**
* Run the task.
* @return whether or not the task is finished.
*/
function run(tManager:PseudoThreadManager):Boolean;
}
Obviously, a pretty simple interface. The only part that might get confusing is that the run() method takes the PseudoThreadManager. This is actually pretty important. I don’t like that we have to inject this dependency into our core tasks but if this task is going to spawn other tasks, as will be the case in a hierarchical one, then you’ll need this so that you can add the new tasks to it (unless it’s a singleton and globally accessible, but some people don’t like using those).
The Pseudo-thread Manager
The pseudo-thread manager is pretty simple as well. We’ll use a stack to manage the tasks that need to be executed. As a particular task is running, it may spawn other tasks that will be added to the manager, but the original task itself may not have completed, so we’ll always use the top element of the stack when determining what to execute. A small note however: if the task does complete, you need to be using a data structure that is capable of removing an object from the middle of the structure and compressing the other elements. We do this through our own IMutableObjectArray interface. A linked list is another, potentially better, option.
public class PseudoThreadManager {
private static const THREAD_ALLOTMENT:Number = 1000 / 30; // 1/30th of a second.
/**
* The array of pseudo-thread tasks. This will be used as a stack.
*/
private var mtTasks:IMutableObjectArray = new MutableObjectArray();
/**
* Constructor.
*/
public function PseudoThreadManager() { }
/**
* Add a task to be managed by the task manager.
*/
public function addTask(tTask:IPseudoThreadTask):void {
mtTasks.add(tTask);
}
/**
* Run the Pseudo-thread task. This will execute tasks for an allotted amount of time.
*/
public function run():void {
var iTasks:int = mtTasks.size();
if (iTasks == 0)
return;
var iStartTime:int = getTimer();
// Loop while there is time left.
while (!((getTimer() - iStartTime) < THREAD_ALLOTMENT)) {
// Start with the last task.
var tTask:IPseudoThreadTask = mtTasks.get(iTasks-1) as IPseudoThreadTask;
var bComplete:Boolean = tTask.run(this);
// Note that we need to remove the specific task in some way, we can't
// just pop the task off the end because other tasks may have been added.
if (bComplete)
mtTasks.removeIndex(iTasks-1);
}
}
}
When I originally created our version of the Pseudo-thread manager, it actually operated independently of most of the codebase through the use of the callLater() method, which would call back into the PsuedoThreadManager every frame. I never found out why, but in doing so this would interrupt execution of other parts of the codebase that were listening for ENTER_FRAME events when interacting with other UIComponents. Instead, I just had our main update thread call the pseudo-thread manager’s run() method.
Implementing the Hierarchical Task
Now that we have a task manager, a task interface, and an operation we want to break up, we just need to implement our hierarchical operation as a task.
public class XmlHierarchyTask implements IPseudoThreadTask {
/**
* The root node being operated on.
*/
private var mtRoot:IMutableXmlNode;
/**
* The action operating on the hierarchy.
*/
private var mtAction:IXmlHierarchyAction;
/**
* Data members for the current state of the task.
*/
private var miChildIndex:int = 0;
private var miChildren:int = 0;
private var mtChildren:IObjectArray;
/**
* Constructor.
*/
public function XmlHierarchyTask(tRoot:IMutableXmlNode, tAction:IXmlHierarchyAction) {
mtRoot = tRoot;
mtAction = tAction;
mtChildren = tRoot.getChildren();
if (mtChildren != null) {
miChildIndex = mtChildren.size();
}
}
/**
* Run the task.
* @return whether or not the task is finished.
*/
public function run(tManager:PseudoThreadManager):Boolean {
var bReturn:Boolean = false;
try {
mtAction.nodeEncountered(null, mtRoot);
}
catch (tEx:Error) {
// handle error
}
// We will only process a single child at a time. This is
// effectively a depth-first processing of the hierarchy.
if (miChildIndex < miChildren) {
var tCurrentChild:IMutableXmlNode = IMutableXmlNode(mtChildren.get(miChildIndex));
tManager.addTask(new XmlHierarchyTask(tCurrentChild, mtAction));
++miChildIndex;
}
if (miChildIndex == miChildren) {
bReturn = true;
}
return bReturn;
}
}
Take some time to compare the XmlHierarchyTask with the original hierarchy operation that we started with. Notice that for the most part the same structure is there: we invoke the operation on the specific node and loop over the children. The only difference is that the children are being operated on through successive calls to the run() method. Once the final child has been operated on, the task can return true so that it will be removed from the PseudoThreadManager.
Breaking up the Action
So what if the action that you’re using to operate on the hierarchy takes a long time? Well, you already have an interface for the task, so just implement the action itself as a task. Here’s a quick example of how an action that has three separable operations might be implemented:
public class XmlHierarchyAction implements IPseudoThreadTask {
/**
* The node the action is operating on.
*/
private var mtNode:IXmlNode;
/**
* State variables.
*/
private var mbCompletedFirstPart:Boolean = false;
private var mbCompletedSecondPart:Boolean = false;
/**
* Constuctor.
*/
public function XmlHierarchyAction(tNode:IXmlNode) {
mtNode = tNode;
}
/**
* Run the task.
* @return whether or not the task is finished.
*/
public function run(tManager:PseudoThreadManager):Boolean {
var bComplete:Boolean = false;
if (!mbCompletedFirstPart) {
// Do the first part of the action
mbCompletedFirstPart = true;
}
else if (!mbCompletedSecondPart) {
// Do the first part of the action
mbCompletedSecondPart = true;
}
else {
// Do the third part of the operation.
bComplete = true;
}
return bComplete;
}
}
The XmlHierarchyAction could just create one of these instead of calling nodeEncountered() as it did before. The pseudo-thread manager is unused here, but again, if this action spawned other tasks, it would be required.
Wrap Up
So that’s all we really use to manage our long running operations. It’s not a lot of code, but getting into the actual implementations of some of the actions can get confusing. Refactoring that functionality to work in a pseudo-threaded environment can be difficult for a lot of reasons. You may need to use listeners to know when a particular task has been completed, for example. We do this in Sharendipity so that we know when an entire Application has been initialized, displaying a spinner or progress bar that is updated while the initialization is happening.
I hope that this gives you an idea of how to break up operations in ActionScript. There may be other solutions out there but I wasn’t able to find them. If you have any suggestions, please leave them in the comments.
Tags:
Action,
ActionScript,
chunking,
Flash,
Hierarchy,
multi-threading,
pseudo-threading,
Task,
thread
•
This is part 5 in a series of posts that address the issues involved in porting a large Java RIA to Flash. I recommend reading the previous posts as well:
Part 1: We’re Moving to Flash. Here’s Why
Part 2: Important Differences Between Java and ActionScript 3
Part 3: Beginning the Actual Port
Part 4: Anonymous Classes and the Adapter Pattern
Another main difference between Java and ActionScript is in how data is communicated to and from the server. In just about any Rich Internet Application this is going to be an important part of your architecture, so it’s important that it is handled correctly.
Synchronous vs. Asynchronous Communication
In Java it is possible to make a blocking call when requesting data from the server. Typically this will happen on a background thread and the programmer handles the returned data in the same thread. In ActionScript, it is not possible to block while data is being requested from the server. This can cause some challenges if you’re trying to port a project to ActionScript.
Java Threads
Fundamentally, the only real difference here is where the threading happens. This exact same functionality could be implemented in Java as well, you just need to manage the data yourself. In Java however, there is no guarantee when the remote call will return. The thread on which the request occurs will continue processing in parallel with your main event thread, so you may want to implement a task queue that guarantees that the handling of returned data happens at a particular time. If you don’t do something like this, you will probably have to handle synchronization issues because you will now have two threads running simultaneously. This will be covered in a bit more detail later in the post.
Because of these issues, if you’re using a programming language that has a threading model similar to Java’s, you may want to rework a few things before starting into the port, but it isn’t necessary. We did it afterward so it’s clearly possible.
ActionScript Data Requests
In ActionScript, data can be requested using many different methods. With all of them, you handle returned data by adding event listeners to the object. For example:
public function executeRequest(tHandler:Function, tErrorHandler:Function) {
// Create the URL loader which will perform the actual communication with the server.
var tURLLoader:URLLoader = new URLLoader();
// Register an event listener that will respond to the completion event
// and notify the response handler.
tURLLoader.addEventListener(Event.COMPLETE, function completeHandler(tEvent:Event):void {
// Instantiate a new response object which makes retrieving data
// from the response simple.
var tResponse:ServerResponse = new ServerResponse(tURLLoader.data);
// Pass the response to the handler.
tHandler(tResponse);
});
try {
// Execute the load. A successful callback will be passed to the
// handler, and any Error will be passed to the error handler.
tURLLoader.load(tURLRequest);
} catch (tEx:Error) {
if (tErrorHandler != null)
tErrorHandler(tEx);
}
}
This little piece of code actually has a lot going on, and is indicative of the model we’re using for communicating the server response back to the client. Let’s look at the completeHandler() function first.
When the data is returned to the client, completeHandler() creates a ServerResponse wrapper around the data and passes that off to the handler that was passed in. The URLLoader’s data property holds the byte array that was returned from the server. The ServerResponse is what is used to unwrap that data. It contains functions such as nextInt(), nextString(), etc. that will pull the values out of the array and return them to the caller.
There are also two different anonymous functions passed in to the executeRequest() function. I’ll note that there are much safer ways to do this. In my last post, I described a DynamicImplementation class that would be perfect for passing in data handlers to this method. The handlers are currently very simple only because we know that there is a single parameter to each one.
The important point here is that we are providing the data handler to the exceuteRequest() function so that we can process the returned data when it is returned. In Java, the model was that the ServerResponse itself would be returned as a result of the executeRequest().
Using a Task Manager
I’ve also mentioned in previous posts that you may want to use Runnables for posting tasks to a global task manager. One problem with moving from a multi-threaded to a single-threaded environment is in determining when exactly the data is being processed. If your communication was happening on a separate thread in Java and you were using the above model, then you may need to perform synchronization in your response handler. However, if you guaranteed that data manipulation never happened on any thread other than the event queue you could forget about this.
Using a task manager would allow you to pass in a Runnable to the executeRequest() function which can be posted to the task manager to be processed during the start of your main event thread. This is very similar to the model that Flash uses for when the events are processed as the result of the remote call.
Conclusion
Now that we have our communication architecture in place, we’re pretty much finished. This series of posts describes just about everything that we needed to do in order to get a working prototype up and running and it only took two weeks, including learning ActionScript. There are a few things that I didn’t mention in this series, such as the differences in drawing objects in Java and Flash and our underlying physics engine. If there’s interest, maybe we’ll post some information about this in the future.
We’ve described the big pain points that we’ve encountered along the way and the solutions that we’ve come across. It’s been a very interesting process and really makes me appreciate the work that we did up front to enable this port. If you’re thinking of moving to Flash, hopefully some of these posts will help you save some time yourself.
Tags:
ActionScript,
communication,
Flash,
Java,
network,
port