ServiceCapture

AMFPHP, Flash 1 Comment »

Just in case you missed the news, ServiceCapture is a great tool for debugging Flash Remoting applications.

What is it?

ServiceCapture runs on your pc and captures all HTTP traffic sent from your browser or IDE. It is designed to help Rich Internet Application(RIA) developers in the debugging, analysis, and testing of their applications.

ServiceCapture is the only tool of its kind to deserialize and display all Flash Remoting or AMF traffic in a simple-to-use interface.

ServiceCapture also has a unique bandwidth simulation feature. This allows engineers to throttle their bandwidth to simulate dial-up, dsl, and cable connection speeds, even when your entire application is being served locally.

I’ve been using it over the last week and really enjoy it. I personally replaced it with Charles HTTP debugger. It does not have that many features (yet?) as Charles, but the Remoting support is what I needed the most so…enjoy!


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 

AMFPHP class mapping

AMFPHP, Flash, PHP 2 Comments »

Here are some good things to know when using class mapping with AMFPHP. As an example, imagine working on an application that handles users through a UserVO value object. Here's what the PHP and the AS2 class look like.

The UserVO class in PHP

This class is in a "vo" subfolder of the "services" folder (in your AMFPHP installation dir).

PHP:
  1. class UserVO{
  2.   var $firstname;
  3.   var $lastname;
  4.   var $age;
  5.  
  6.   function UserVO(){
  7.   }
  8. }

The UserVO class in AS2

This class is in the namespace "com.domain.vo.UserVO".

Actionscript:
  1. class com.domain.vo.UserVO{
  2.   public var firstname:String;
  3.   public var lastname:String;
  4.   public var age:Number;
  5.  
  6.   function UserVO(){
  7.   }
  8. }

Flash to PHP

Sending VO's from Flash to PHP is quite simple. Just add the parameters in the "arguments" key. Use the fully qualified classpath of the class on the server side and make sure you set "required" to true;

PHP:
  1. "saveUser" => array(
  2.   "description" => "Inserts or updates the user in de database.",
  3.   "access" => "remote",
  4.   "arguments" => array(
  5.     "aboutVO" => array("type" => "vo.UserVO", "required" => true)
  6.   )      
  7. )

PHP to Flash

Watch out here! You can leave out the "returns" key from the method entry in the methodtable. When you do that, AMFPHP will return the name of the class for you. The thing to know here is that in PHP4 the classname will be returned in lowercase, while in PHP5 it will be returned in its original format of lower- and uppercases. Note that this does not return the fully qualified classpath, but just the classname. "uservo" vs. "UserVO".

Here's a quote from the "get_class" function docs.

In PHP 4 get_class() returns a user defined class name in lowercase, but in PHP 5 it will return the class name in it's original notation.
http://be.php.net/manual/en/function.get-class.php

This is not recommended because Object.registerClass() will fail because it is case-sensitive. The best way to get Object.registerClass() to work is to pass in the name of the class in the "returns" key and then use that same name in lowercase to register the class in Flash.

PHP:
  1. "getUserVO" => array(
  2.   "description" => "Returns a user.",
  3.   "access" => "remote",
  4.   "returns" => "vo.UserVO",
  5.   "arguments" => array()
  6. )

And then in Flash...

Actionscript:
  1. Object.registerClass("vo.uservo", com.domain.vo.UserVO);

That's it, cheers!

[Update] I must have missed something here: the "returns" string is always passed to Flash in lowercase. So remember that when you use Object.registerClass().


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 

Localizing your ARP application.

ARP, Flash 3 Comments »

Another update to my ARP lab. I have been thinking about localization for a while but didn't really have the time to work something out untill now. Continuing on the e-learning project we are working on, we came to the point where we needed to have multi-lingual user interfaces. So why not write a generic way in the ARP framework instead of having a custom implementation for our project.

Download the sample files here.

How it works (Nils, you won't like this!)

Each locale has its own XML file that holds the localized strings. In the application, there is a LocaleManager class that knows what the current locale is and, when a new locale is set, will load and parse the localized strings. This loading and parsing happens in a class called ResourceBundle, which "bundles" the "resources", the localized strings, into a collection.

The XML files look like this.

XML:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <resources>
  3.     <resource key="firstname" value="Firstname"/>
  4.     <resource key="lastname" value="Name"/>
  5.     <resource key="submit" value="Submit"/>
  6. </resources>

XML:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <resources>
  3.     <resource key="firstname" value="Voornaam"/>
  4.     <resource key="lastname" value="Familienaam"/>
  5.     <resource key="submit" value="Verzenden"/>
  6. </resources>

This is pretty much the same idea as the XML files to configure your ARP application with the AppSettings class. Each string has a key and a value. Notice that the keys should be the same for the different resource files. The XML files are saved with the following naming convention: they start with "resources_" and a string representation of the locale is appended to it. Example names are "resources_en.xml", "resources_du_BE.xml" or "resources_du_NL.xml". As you can see, we have a common resource file for English strings and 2 more specific ones for Dutch. One for Belgium and one for The Netherlands.

When the application starts, each view/form that is interested in localized content should:
- register as a listener with the LocaleManager
- implement the LocaleListener interface which makes it possible to be added as a listener to the LocaleManager and which forces the form to implement the localeChanged() event handler.

From the example, here is what the RegistrationForm class looks like.

Actionscript:
  1. import mx.controls.*;
  2. import mx.utils.*;
  3.    
  4. import org.osflash.arp.ArpForm;
  5. import org.osflash.arp.util.*;
  6.  
  7. class com.herrodius.localization.view.RegistrationForm extends ArpForm implements LocaleListener{
  8.   var language_cb:ComboBox;
  9.   var firstname_lbl:Label;
  10.   var lastname_lbl:Label;
  11.   var submit_btn:Button;
  12.  
  13.   public function RegistrationForm(){
  14.   }
  15.  
  16.   /**
  17.     * toString.
  18.     */
  19.   public function toString():String{
  20.     return "[com.herrodius.localization.view.RegistrationForm]";
  21.   }
  22.  
  23.   function onLoad():Void{
  24.     TRACE(Flashout.INFO);
  25.  
  26.     //listeners
  27.     LocaleManager.getInstance().addListener(this);
  28.     language_cb.addEventListener("change", Delegate.create(this, languageComboBox_Change));
  29.  
  30.     //selected item in combobox
  31.     language_cb.selectedIndex = 2;
  32.   }
  33.  
  34.   /**
  35.     * The user chooses another language from the combobox.
  36.     * We need to create a new locale and set it in the LocaleManager.
  37.     */
  38.   function languageComboBox_Change(evt:Object):Void{
  39.     var locale:Locale = Locale.fromString(evt.target.selectedItem.data);
  40.     LocaleManager.getInstance().setLocale(locale);
  41.   }
  42.  
  43.   /**
  44.     * The locale has changed.
  45.     * Change the labels text and the button label.
  46.     */
  47.   function localeChanged():Void{
  48.     var localeManager:LocaleManager = LocaleManager.getInstance();
  49.     firstname_lbl.text = localeManager.getString("firstname");
  50.     lastname_lbl.text = localeManager.getString("lastname");
  51.     submit_btn.label = localeManager.getString("submit");
  52.   }
  53. }

Notice that a new locale is created when the user chooses a different language from the combobox. Here the locale is created through a static method called fromString() because we allready have all the locale details we need in a string. You can ofcourse also instantiate a new locale by calling the Locale's constructor and passing in the language and the region. After creating the locale, we assign it to the LocaleManager through the setLocale() method. This will create a new resourcebundle and load the localized content. As you can see, I implemented it in a way so that you don't have to take care of the resourcebundles yourself. The LocaleManager does it for you. Finally, when the content is loaded and parsed, the localeChanged() method gets called. This is the method you use to update your view. You can fetch the localized strings with the getString() method on the LocaleManager. When the string is not found in the resourcebundle, an error is thrown.

Download

You can download the example here. The following classes should be added in the package "org.osflash.arp.util":
- Locale
- LocaleListener
- LocaleManager
- ResourceBundle

Related content:

- Configuring your ARP application


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 

Typesafe ENUM’s

Design Patterns, Flash 4 Comments »

I was discussing the use of typesafe ENUM's with a co-worker today when we got to a point where we couldn't agree on how to implement some of the behavior. We have this AssessmentItemType class that holds different types of assessmentitems like MULTIPLE_CHOICE, FILL_IN_TEXT, DRAG_AND_DROP_WITH_TEXT, etc that looks like this (some of the content is stripped).

Actionscript:
  1. ...
  2.  
  3. private static var TYPES:Array = new Array();
  4.  
  5. private var id:Number;
  6. private var name:String;
  7.  
  8.  
  9. public static var MULTIPLE_CHOICE:AssessmentItemType = new AssessmentItemType("multipleChoice", 1);
  10. public static var FILL_IN_TEXT:AssessmentItemType = new AssessmentItemType("fillInText", 2);
  11. public static var DRAG_AND_DROP_WITH_TEXT:AssessmentItemType = new AssessmentItemType("dragAndDropWithText", 6);
  12. public static var DRAG_AND_DROP_WITH_IMAGES:AssessmentItemType = new AssessmentItemType("dragAndDropWithImages", 7);
  13.  
  14.  
  15. private function AssessmentItemType(name:String, id:Number){
  16.   setName(name);
  17.   setId(id);
  18.  
  19.   TYPES.push(this);
  20. }
  21.  
  22. ...

These types are assigned to an instance of the AssessmentItem class when we are parsing the assessmentitems from XML files. But during the parsing, we need a way to look up the correct assessmentitemtype in the ENUM. All we know about the type of the assessmentitem is its name, "multipleChoice" for instance, or its id, "1" for instance. The id is used for backward compatibility with the previous system.

The first solution was to create a separate helper class to look up the assessmentitemtype by looking into the available types, exposing the TYPES array. We figured we needed a getByName() and a getById() method in order to look up the type both ways. The second solution was to add these 2 methods to the AssessmentItemType class itself and not to create a separate class. I personally thought that the second solution was the best because creating a separate class to look up values would be overkill in my opinion. We were also showing some the class' internals by making the TYPES array public in order to access it from the helper class. We couldn't end the discussion because my co-worker had to catch a train, so I was wondering what you guys were thinking.

PS: This might not be a critical design question, but both solutions might have there pros and cons where we didn't think of.


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 

Configuring your ARP application

ARP, Flash 2 Comments »

There was a recent post on the ARP mailinglist about how an application could be configured. Since there is (still) not a uniform way of doing so in ARP I thought I'd share the solution I came up with. The whole idea is based on an XML file that contains key/value pairs, pretty much like the appsettings implementation in .NET. The XML file, called "appsettings.xml", gets loaded in the ArpApplication class. This is a new class I introduced to the framework that all Application forms extend. The Application form being the applications point of entry.

Before diving into any code examples, please note that these are my personal additions to the framework and that they are not in any official release. Other additions from the ARP Advisory Committee members are available as well: Peter Hall, Jesse Warden, Shannon Jackson and the ARP labs overview.

appsettings.xml

Here's an example of the appsettings.xml file. As you can see all entries consist of a key/value pair. In order for your application to find the appsettings file, you should either:
- name it "appsettings.xml" and put it in a folder where your swf can read it without changing folders.
- use flashvars in the html file that embeds the swf and create a var called "appSettingsPath". Point its value to the appsettings file in any directory. Note that the name "appsettings.xml" can be changed then and that it can even be a serverside page that generates a dynamic config.

XML:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <appsettings>
  3.     <add key="applicationBackground" value="0x999999"/>
  4.     <add key="menuItems" value="Home,News,Projects,Contact"/>
  5.     <add key="menuBackground" value="0xCCCCCC"/>
  6.     <add key="content" value="Lorem Ipsum is simply ..."/>
  7. </appsettings>

To access one of the values, use the AppSettings class.

Actionscript:
  1. var menuItems:String = AppSettings.getInstance().getValue("menuItems");
  2. var menuBackground:Number = Number(AppSettings.getInstance().getValue("menuBackground"));

Note that these values can only be fetched when the appsettings file has been loaded and parsed. Therefore your Application class needs to extend the ArpApplication class. To know when the loading and parsing is done, you need to implement the onAppSettingsLoad() method. This is a (abstract) method in ArpApplication that gets called when the values have been parsed.

In the following code we set the backgroundcolor of the application to a value in the appsettings and then call the show() method on 2 subforms: menuForm and contentForm.

Actionscript:
  1. /**  
  2. * Overwritten from ArpApplication.
  3. */
  4. function onAppSettingsLoad(){
  5.   trace(toString() + " - onAppSettingsLoad");
  6.  
  7.   var applicationBackgroundColor:Color = new Color(background_mc);
  8.   applicationBackgroundColor.setRGB(Number(AppSettings.getInstance().getValue("applicationBackground")));
  9.            
  10.   menuForm.show();
  11.   contentForm.show();   
  12. }

I overwrote the show() method in these subclasses because they also need values from the appsettings file. And now that I think about it, doing so isn't the best idea. I can see how pretty intense operations are called everytime we hide/show the forms. Either letting the application form dispatch events when the settings are loaded could be a better solution or if there was any way of intercepting the onLoad() handler of the subforms, that could be a good solution too. That way, we could trigger the onLoad() handler on the subforms only when the appsettings are loaded. (In fact, I have been trying to catch the onLoad() before it fires without success. So if anyone knows, please let me know.)

Here is a zip file with a small example and the ArpApplication and the AppSettings class.
Put the AppSettings class in the package org.osflash.arp.config.* and the ArpApplication class in org.osflash.arp.view.*


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 
WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Login