OpenLaszlo Performance Tip: Attributes, Not Nodes

OpenLaszlo applications typically access numerous web services that respond with XML. That XML must be loaded over HTTP. Many developers overlook the effect that the format of the XML in those services can have on the performance of an application.

Most XML guides suggest that an ideal XML format should look something like this:

<contact>

    <id>0</id>

    <city>Bedrock</city>

    <zip>90210</zip>

    <firstname>Fred</firstname>

    <lastname>Flintstone</lastname>

    <phone>415-555-0999</phone>

    <state>CA</state>

    <address>1234 Stone Lane</address>

    <country>USA</country>

    <email>fred@example.com</email>

</contact>

Note how each property of the contact is represented by an XML node, with a text node inside, representing the value of that property. That may be very readable to humans, but it wreaks hell on rich Internet applications (RIAs). Note that I said RIAs, not just OpenLaszlo applications. As you’ll see, this tip holds true for various platforms, including OpenLaszlo, Flex and DHTML. When that data is parsed by the client – it needs to be parsed, so the data can be accessed easily – the XML parser has to create a separate runtime object for each of those subnodes. In OpenLaszlo, that class is lz.DataElement. So our contact above cost us 11 nodes. No wait – it actually cost us 21 nodes. Remember that each text node is treated as a separate object too.

What we’re dealing with is not so much data loading, but data initialization. Loading the above contact isn’t going to take much time at all, but loading an address book with 500 contacts formatted as above will. With 500 contacts, the application will be initializing 5,500 nodes (i.e. 11 * 500). The effect this will have for the user is a noticeable delay after the web service is loaded. The application will consume a lot of CPU and feel sluggish (probably unusable) while the data is being parsed.

Happily, there’s an easy fix. Simply reformat your data to rely on attributes for property values where practical. The above contact would therefore look like this:

<contact id="0"

         city="Bedrock"

         zip="90210"

         firstname="Fred"

         lastname="Flintstone"

         phone="415-555-0999"

         state="CA"

         address="1234

         Stone

         Lane"

         country="USA"

         email="fred@example.com"/>

How much of an improvement could you reasonably expect? It turns out quite a lot, actually. I tested data initialization time on the following platforms:

  • OpenLaszlo 4.2 nightly compiled to SWF8
  • OpenLaszlo 4.2 nightly compiled to DHTML in Firefox 3
  • OpenLaszlo 4.2 nightly compiled to SWF9
  • Flex 3 (using e4x data, since it’s the closest way of handling XML to OpenLaszlo’s)
  • DHTML in Firefox 3 (using the Dojo toolkit and parsing the returned XML with dojox.xml.xmlParser, since the default XML objects don’t have the type of functionality that OpenLaszlo’s or Flex’s do)
  • DHTML in Internet Explorer 6 (same platform options as for Firefox 3.

I compared how long it took to load and initalize a locally-served (over HTTP) XML document that contained 500 contacts with data saved as nodes, versus one that contained 500 contacts with data saved as node attributes.

Platform Data as Nodes (ms) Data as Attributes (ms) Improvement
OpenLaszlo SWF8 1587 253 84%
OpenLaszlo DHTML 1698 335 80%
OpenLaszlo SWF9 419 112 73%
Flex 3 428 331 23%
Firefox 3 DHTML 684 384 44%
IE 6 DHTML 1695 1029 39%

As you can see, using attributes instead of nodes for your XML data is significantly faster when dealing with larger datasets.

I should mention that I’ve been looking forward to trying out the new OpenLaszlo SWF9 runtime, and am pleased to see that it’s so much faster. The SWF9 runtime is present in OpenLaszlo 4.1, but a number of things are broken – datasets don’t work, for example. The 4.2.x nightly build from last night is the first build to have working datasets (hence I was able to run my test).

You can download my sample data and LZX, MXML and HTML files for the various runtimes here.

Passing Arguments to before_filter in a Rails Controller

I’ve been working with Ruby on Rails a lot recently. It’s a great platform for creating both old-fashioned web applications as well as services for RIAs. I especially like the fact that Rails encourages you to think about the right way to do something, before writing any code. For all you know, that complex thing you wanted to add could involve nothing more than one shell command and a tweaked line of Ruby code.

There was one seemingly ubiquitous thing that I had to think about for long time however, so I’m posing it here for posterity: How do you pass arguments to an ActionController method from a filter, while also using filter conditions?

It seems like such a common problem. You buy the Agile Web Development with Rails book, like everybody else, read half the first chapter, then start writing your own application. At some point you need to add user authentication to your application. If you were working with any other language/framework, this would have taken waaayyyy longer than it did to copy-and-paste the authentication example in chapter 11. Here’s the example I’m referring to:

my_app/app/controllers/application.rb
class ApplicationController < ActionController::Base
session :session_key = "_my_session_id"
private
def authorize
unless User.find_by_id(session[:user_id])
flash[:notice] = "Please log in"
redirect_to(:controller => "login", :action => "login")
end
end

This method gets called automatically by specifying so on a filter in the individual controller, e.g.

my_app/app/controllers/item_controller.rb
class ItemController < ApplicationController
before_filter :authorize, :except => [:show, :search]

# ... various methods ...
end

Then, several features later, you realize that you need to have different levels of user (administrator, moderator, gnat, etc.).  The authorize method now needs to take an argument of what type of user is required.  You would have to specify this when you write the filter (in item_controller.rb), but you need to retain the filter conditions (:except). This took me a long time to find. The reference page on filters didn’t help.

Filtes can pass arguments to the methods they call, but the syntax is not obvious:

  • The authorize method you call must be public.
  • Your filter conditions have to be the first argument to the filter.
  • Instead of referencing the authorize method, you will need to call it, but you must do so from a code block, and that must be the last argument to the filter. Note the do … end in the example below.
  •  You can pass as many arguments as you like to the method inside this code block, since you’re actually calling it here.
  • To call the method, you need to define a block variable inside your code block (it can be named anything you like). This will be a reference to the controller. Note the two pipes in the example below.

So here’s the controller class with filter:

my_app/app/controllers/item_controller.rb
class ItemController < ApplicationController
before_filter :except => [:show, :search] do |controller| controller.authorize({"required_user_level" => "administrator"})
end
# ... various methods ...
end

Don’t forget to add an argument to your method declaration in the ActionController, and to make it public:

my_app/app/controllers/application.rb
class ApplicationController < ActionController::Base
session :session_key = "_my_session_id"

def authorize(vars)
puts "Required User Level is " + vars["required_user_level"]
unless User.find_by_id(session[:user_id])
flash[:notice] = "Please log in"
redirect_to(:controller => "login", :action => "login")
end
end

Migrating LZX Code to OpenLaszlo 4.1

I was recently porting some LZX code in OpenLaszlo Training materials from 4.0.12 to 4.1, and stumbled upon a few issues, which I thought I’d post here as a reference.

Don’t use <method event=””> Syntax

The <handler name=””>syntax was introduced to replace the <method event=””> syntax some time ago. With 4.1, I found that the compiler/debugger could get confused if you continued to use the old syntax in some cases. Sometimes the error messages were not useful. In short, replace:

<method event="onevent">
...
</method>

… with:

<handler name="onevent">
...
</handler>

Delegate Method Arguments

Any method you call with a delegate must now have a defined argument. This is in preparation for future compatibility with SWF9. Check these out colabioclipanama2019. In short, if you write:

<script>
new LzDelegate(canvas, "myMethod", ds, "ondata");
</script>

<method name="myMethod">
...
</method>

… you should define your method as shown below:

<method name="myMethod" args="arg">
...
</method>

The New “lz” Namespace

In OpenLaszlo 4.0.x, there was a global object that contained references to classes, colors and global tokens. In OpenLaszlo 4.1, there is now an lz object that replaces this for class definitions. Here’s salbreux-pesage an example for you to better understanding.It creates a virtual namespace. So if you need to procedurally instantiate an OpenLaszlo window, instead of writing:

new window(canvas, {width:300, height:300});

… you now write:

new lz.window(canvas, {width:300, height:300});

If you need to paramaterize the name of a class, you used to write:

var classname = "window";
new global[classname](canvas, {width:300, height:300});

… instead, now you would write:

var classname = "window";
new lz[classname](canvas, {width:300, height:300})
;

Those are the main issues I ran into. Otherwise code written for OpenLaszlo 4.0.12 seems to run fine on 4.1.