dojo iconjson icon

Dojo - Using dojo.io.bind

Posted in , , Sun, 04 Jun 2006 04:15:00 GMT

I recently looked into Dojo Toolkit 0.3.0's dojo.io.bind to perform AJAX requests because of it's good handling of memory leaks. I checked out the dojotoolkit.org intro page which was okay but didn't cover how to pass parameters or how to process a JSON response so I thought I'd put some info together here. Here are a few things worth knowing:

  1. A dojo response has a type that is typically set to load or error, though sometimes it may be neither. With dojo, type=="load" means success.
  2. Dojo.io.bind has a few handlers to process the response. The load handler is executed when the response type=="load" and the error handler is executed when the response type=="error". There is also a catch-all handle handler that can accept all response types so you can process a response that has a type that's neither load nor error.
  3. If request parameters are set as a hashref using content, dojo.io.bind will automatically turn them into form post parameters
  4. The response mimetype (or content-type) is set in the client JavaScript. Dojo uses this to determine how to process the response. Dojo ignores content-types set by the server

Here are two examples to help put the above together. The examples cover a plain HTML fragment response as well as a JSON response. Both examples submit a hashref. Dojo can also submit an entire form automatically. This is covered on the Dojo.IO Intro link above and isn't covered here, for now. Thanks to Toby Corkindale who posted his saveHandler function to the catalyst mailing list.

Example 1: HTML processed by load
This first example retrieves a single fragment of HTML in the response body and processes it using the load handler.

dojo.io.bind({
    url: "/binduri",
    method: "post",
    /* optional content. If the content is in the
     * form of a hashref they are converted to
     * post paramters */
    content: {
        username: "George",
        password: "curious"
    },
    load: function(type,data,evt) {
        if (data) alert('Response Data: '+data);
    },
    mimetype:'text/html'
});

Example 2: JSON processed by handle
This second example processes a JSON response using the all-in-one handle handler. The handle is typically used in special situations where load and error are not appropriate such as a progress bar. It is shown here just to provide the syntax. To process a JSON response, set the dojo.io.bind mimetype to text/json and return the JSON object in the response body.

dojo.io.bind({
    url: "/binduri",
    method: "post",
    /* optional content. If the content is in the
     * form of a hashref they are converted to
     * post paramters */
    content: {
        username: "George",
        password: "curious"
    },
    handle: function(type,data,evt) {
        if (type=='load') {
            alert( 'Successful response' );
            if (data.myItem)
                alert('Response JSON Item: '
                +data.myItem);
        } else if (type=='error') {
            alert('A error has occurred');
        } else {
            alert('Some other event has occurred');
        }
    },
    mimetype:'text/json'
});

Conclusion
Dojo.io has a nice interface that has a few conveniences including auto-conversion of a hashref to request form parameters and auto-eval of JSON set in the response body. Along with the good memory leak handling for IE, a very nice implementation.

del.icio.us:Dojo - Using dojo.io.bind digg:Dojo - Using dojo.io.bind reddit:Dojo - Using dojo.io.bind spurl:Dojo - Using dojo.io.bind wists:Dojo - Using dojo.io.bind simpy:Dojo - Using dojo.io.bind newsvine:Dojo - Using dojo.io.bind blinklist:Dojo - Using dojo.io.bind furl:Dojo - Using dojo.io.bind fark:Dojo - Using dojo.io.bind blogmarks:Dojo - Using dojo.io.bind Y!:Dojo - Using dojo.io.bind smarking:Dojo - Using dojo.io.bind magnolia:Dojo - Using dojo.io.bind segnalo:Dojo - Using dojo.io.bind

7 comments

dojo icon

Dojo - Remote Script Problem

Posted in , Sun, 04 Jun 2006 04:11:00 GMT

Dojo Toolkit 0.3.0 seems to have a problem loading it's javascript libraries remotely, i.e. when the Dojo scripts are hosted on a server different than where the HTML is. For example, if the page http://www.mysite.com/index.html includes http://www.mystatic.com/dojo/dojo.js. The main Dojo file, dojo.js, runs fine when loaded remotely, however the following fatal errors occur when it attempts to load its external libraries:

FATAL: Could not load 'dojo.io';
   last tried '__package__.js'
FATAL: Could not load 'dojo.widget.ComboBox';
   last tried '__package__.js'

It was suggested this could be due to XSS protections. Scriptaculous' scriptaculous.js, however, has a way around this since it can be loaded remotely and access it's external files (builder.js, controls.js, etc.). Often it's nice to have static files hosted on a separate server. Is there a way to fix this issue for Dojo?

UPDATE 1: For now, I'm going to stick with dojo.io.bind and Scriptaculous autocomplete. A nice thing about this set up is I can load a remote dojo.js browserio build w/o issues since it doesn't need call any external libraries for just bind.

UPDATE 2: Alex Russell provided a uri for cross domain package loading. You can turn on cross domain support by using a custom build and setting the dojoLoader option to xdomain option:

ant -Dprofile=ajax -DdojoLoader=xdomain
  -Ddocless=true clean release intern-strings

If you don't want to build it yourself, James Burke has done it and made it available as dojo-0.3.1-ajax-xd.tar.gz. This page has some more info.

del.icio.us:Dojo - Remote Script Problem digg:Dojo - Remote Script Problem reddit:Dojo - Remote Script Problem spurl:Dojo - Remote Script Problem wists:Dojo - Remote Script Problem simpy:Dojo - Remote Script Problem newsvine:Dojo - Remote Script Problem blinklist:Dojo - Remote Script Problem furl:Dojo - Remote Script Problem fark:Dojo - Remote Script Problem blogmarks:Dojo - Remote Script Problem Y!:Dojo - Remote Script Problem smarking:Dojo - Remote Script Problem magnolia:Dojo - Remote Script Problem segnalo:Dojo - Remote Script Problem

4 comments

catalyst icon

Catalyst - Flying Camel Mascot and O'Reilly

Posted in , , , Thu, 01 Jun 2006 22:05:00 GMT

A while back the Catalyst framework open source community was working on a mascot for their project. The idea was to have a flying camel made up of Lego-like building blocks. This would convey key characteristics of the project including (a) Catalyst would make your project fly, (b) Catalyst is very modular and (c) Catalyst is written in Perl. There was a lot of excitement and Tim Gould was kind enough to make the following camel for the group:

catalyst lego flying camel

Unfortunately, the idea did not get the approval of O'Reilly Media, Inc. which holds a trademark on the camel image. Their policies are described on their Perl Camel Usage and Trademark Information page. Tim O'Reilly mentioned their Perl Camel policies in his response to the recent "Web 2.0" service mark controversy which caused me to wonder if O'Reilly Media, Inc.'s commercial trademark policies are in the spirit of open source.

In the open source world, you can typically take someone's copyrighted information and modify with attribution, especially for a non-commercial use. If that standard were applied to logos, especially mascot-type logos, then it would seem that the spirit of open source is in line with modifying and giving attribution for mascot logos as well. Two popular mascots that have been altered and published include Tux for Linux and Mozilla originally for Netscape. These alterations have arguably made Tux and Mozilla even more popular and recognizable, thus strengthening the brand, than they would otherwise be. Unlike Netscape and Linux, O'Reilly has chosen to use a strong hand in preventing modification of the Camel logo for use by open source projects such as the Catalyst. Is O'Reilly's policy too stringent for the open source community or acceptable business practices?

del.icio.us:Catalyst - Flying Camel Mascot and O'Reilly digg:Catalyst - Flying Camel Mascot and O'Reilly reddit:Catalyst - Flying Camel Mascot and O'Reilly spurl:Catalyst - Flying Camel Mascot and O'Reilly wists:Catalyst - Flying Camel Mascot and O'Reilly simpy:Catalyst - Flying Camel Mascot and O'Reilly newsvine:Catalyst - Flying Camel Mascot and O'Reilly blinklist:Catalyst - Flying Camel Mascot and O'Reilly furl:Catalyst - Flying Camel Mascot and O'Reilly fark:Catalyst - Flying Camel Mascot and O'Reilly blogmarks:Catalyst - Flying Camel Mascot and O'Reilly Y!:Catalyst - Flying Camel Mascot and O'Reilly smarking:Catalyst - Flying Camel Mascot and O'Reilly magnolia:Catalyst - Flying Camel Mascot and O'Reilly segnalo:Catalyst - Flying Camel Mascot and O'Reilly

3 comments

perl icon

Rose::DB::Object - High Performance Perl ORM

Posted in , , Thu, 01 Jun 2006 21:22:00 GMT

In the area of Perl ORM (object relational mappers), there are essentially three players: Class::DBI, DBIx::Class and Rose::DB::Object. Of the three, Rose::DB::Object (a.k.a. RDBO) is known to be the fastest, running just 2-4 times the speed of straight DBI in many tests (albeit using an unloaded database). DBIx::Class is known as the most extensible and flexible. Class::DBI is considered outdated (e.g. it doesn't support JOINs) and to be avoided by many. RDBO is the fastest because speed is it's primary design consideration, implementing many perl and DBI-level optimizations. The design philosophy is described as:

Basically, any work that can be done "up-front" (or at least "infrequently") is done in order to keep the frequently used runtime code path very tight. - John Siracusa

RDBO's implementation accomplishes this feat in several ways:

  1. aggressive code inlining: method calls can be very expensive and RDBO goes to great lenghts to avoid this. The get_objects method in Rose::DB::Object:Manager is 2129 lines long.
  2. extensive caching of "derived metadata", e.g. commonly used SQL query strings, column lists, etc.
  3. extensive use of "the 'fast path' in DBI, such as always using bind_col() and fetch() to retrieve data instead of fetchrow_array(), unbound calls to fetchrow_arrayref(), or fetchrow_hashref()."
  4. "compiling down" accessor and mutator methods, both with and without triggers, to an optimized form in order to shorten the code path.

Achieving this high performance has resulted in some compromises. They include:

  1. the code is harder to maintain and extend, resulting in a smaller community of contributors.
  2. aggregate functions and other queries that do not return table rows (e.g. GROUP BY, HAVING, etc.) are not natively supported yet. A previous entry, Rose::DB::Object - aggregates, describes how to implement aggregates with RDBO.

Perl has a TIMTOWTDI tradition and ORMs are no exception. The primary alternative, DBIx::Class, is designed with extensibility as it's primary consideration and addresses the compromises RDBO has made. The implementation gives up some perl execution speed to RDBO to gain this extensibility while generating roughly equivalent SQL for a similar database load. Both RDBO and DBIC are much faster than Class::DBI. The extensibility philosophy has resulted in an alternative ORM that is more flexible, supports aggregate functions and has a larger community of committers relative to RDBO.

RDBO should be a strong contender if you want the fastest Perl ORM and can accept the design decisions it has made to achieve that performance. If you would like some extra capability and can give up some perl execution speed in your web nodes, it may be worthwhile to evaluate some alternatives.

del.icio.us:Rose::DB::Object - High Performance Perl ORM digg:Rose::DB::Object - High Performance Perl ORM reddit:Rose::DB::Object - High Performance Perl ORM spurl:Rose::DB::Object - High Performance Perl ORM wists:Rose::DB::Object - High Performance Perl ORM simpy:Rose::DB::Object - High Performance Perl ORM newsvine:Rose::DB::Object - High Performance Perl ORM blinklist:Rose::DB::Object - High Performance Perl ORM furl:Rose::DB::Object - High Performance Perl ORM fark:Rose::DB::Object - High Performance Perl ORM blogmarks:Rose::DB::Object - High Performance Perl ORM Y!:Rose::DB::Object - High Performance Perl ORM smarking:Rose::DB::Object - High Performance Perl ORM magnolia:Rose::DB::Object - High Performance Perl ORM segnalo:Rose::DB::Object - High Performance Perl ORM

2 comments

ie iconjson iconprototype icon

Prototype - X-JSON fails on long value in IE

Posted in , , , Thu, 01 Jun 2006 20:14:00 GMT

Unlike Dojo Toolkit and other client-side AJAX libraries that read a JSON object from the response body, prototype.js reads it from the custom X-JSON header. I didn't run into any problems with prototype's approach developing on Firefox but I soon discovered IE 6 has a max header size that will cause prototype 1.5.0 rc0's evalJSON method to silently fail with an unreported [object Error] error. In my case, IE 6 would handle an X-JSON string with length of 138 bytes but would fail with a length of 1659 bytes. Firefox 1.5.0.3 and 1.0.7 worked fine with both strings. I'm not sure what IE 6's exact limit is but the fact there's a limit at all is discouraging IMO.

The argument I've seen for putting the JSON object in X-JSON is that you can put a separate large quanity of HTML in the response body. This design works well when you only have one or zero large quantities of HTML. As soon as you have two, you need to either put them both in the response body using another serialized data notation or put them both in the JSON object and put the JSON object in the response body instead of the X-JSON header. It seems better to simply expect the JSON object in the response body in all cases than in cases when there's only one or zero large return values.

Let's take a look at an example. In the following the one Ajax JSON response can return meta data about the overall response ("Result":"ok") as well as a list of "Posts", say when updating a post list on something like Digg's homepage. Further more a list of "Hot Stories" can simultaneously updated in the same request. Each one of the stories may have a description or overall information that exceeds IE 6's max header length.

{
  "Result":"ok",
  "Posts":[
    {
      "time":1149349580,
      "id":100001,
      "title":"Article 11 title",
      "desc":"Article 11 desc
         (longer than IE header length)",
      "votes":120,
      "comments":5,
      "submitter":"garfield"
    },
    {
      "time":1149349583,
      "id":100002,
      "title":"Article 12 title",
      "desc":"Article 12 desc
         (longer than IE header length)",
      "votes":125,
      "comments":15,
      "submitter":"garfield"
    }
  ],
  "Hot Stories":[
    {
      "time":1149348000,
      "id":1001,
      "title":"Hot Article 1 title",
      "desc":"Hot Article 1 desc
         (longer than IE header length)",
      "votes":1120,
      "comments":115,
      "submitter":"garfield"
    },
    {
      "time":1149349000,
      "id":1002,
      "title":"Hot Article 2 title",
      "desc":"Hot Article 1 desc
         (longer than IE header length)",
      "votes":1120,
      "comments":115,
      "submitter":"garfield"
    }
  ]
}

I understand where having a proprietary X-JSON header and a separate response body is useful however I view those situations as a subset of a more generic, and powerful, use. With more complex return values, putting the JSON object in the response body is ultimately a more flexible and extensible design.

I'll continue to use prototype for now but I'm going to set all my JSON objects in the response body and eval it myself given IE 6's short comings. A bigger concern for me is that I feel Prototype's use of putting the JSON object in X-JSON will encourage inefficient AJAX implementations that end up using more HTTP request/response cycles than necessary. I really hope prototype.js will move their auto-eval feature to operate on the response body due to this problem and to make it more compatible with other JS AJAX libraries at the same time.

del.icio.us:Prototype - X-JSON fails on long value in IE digg:Prototype - X-JSON fails on long value in IE reddit:Prototype - X-JSON fails on long value in IE spurl:Prototype - X-JSON fails on long value in IE wists:Prototype - X-JSON fails on long value in IE simpy:Prototype - X-JSON fails on long value in IE newsvine:Prototype - X-JSON fails on long value in IE blinklist:Prototype - X-JSON fails on long value in IE furl:Prototype - X-JSON fails on long value in IE fark:Prototype - X-JSON fails on long value in IE blogmarks:Prototype - X-JSON fails on long value in IE Y!:Prototype - X-JSON fails on long value in IE smarking:Prototype - X-JSON fails on long value in IE magnolia:Prototype - X-JSON fails on long value in IE segnalo:Prototype - X-JSON fails on long value in IE

8 comments

catalyst iconperl icon

Catalyst - Root controller

Posted in , Thu, 01 Jun 2006 15:52:00 GMT

Catalyst 5.66 introduced the Root controller (e.g. MyApp::Controller::Root) as a best practice. It's purpose is to remove the need for the Application Class (a.k.a. App Class; e.g. MyApp.pm) to have actions or be a controller. Previously, Local top-level actions (e.g. /login) would be put in the App Class; the Root controller replaces this because it's base path is /. I asked mst why the Root controller is important and he told me the following.

Having the Application Class be a controller makes it a controller on a class-based level that can lead to several problems. One problem is name collision between App Class actions and $c methods, for example an App Class login action will cause problems with $c->login used by Catalyst::Plugin::Authentication. This and other problems can now be avoided entirely.

A typical App Class includes:

use Catalyst qw/.../;

This makes the App Class isa Catalyst::Controller because "use Catalyst" automatically injects Catalyst and Catalyst::Controller as base classes if the calling class isn't isa Catalyst. This can be avoided by making the App Class isa Catalyst before calling "use Catalyst" with the following:

use base qw/Catalyst/;
use Catalyst qw/.../;

Once the App Class is no longer isa Catalyst::Controller, it should no longer have any actions or subroutines with attributes, including the auto, default and end subroutines.

The Catalyst helper script will create a MyApp::Controller::Root controller for you, but the name can actually be anything. There's only one line that distinguishes the Root controller from any other one and it's a config setting that sets the name space to ''. You can make any controller the root by simply add the following line, just be sure the action attributes are updated if necessary:

__PACKAGE__->config->{namespace} = '';

Previously, you could avoid actions in the App Class by using Global actions, now you can with Local actions as well.

del.icio.us:Catalyst - Root controller digg:Catalyst - Root controller reddit:Catalyst - Root controller spurl:Catalyst - Root controller wists:Catalyst - Root controller simpy:Catalyst - Root controller newsvine:Catalyst - Root controller blinklist:Catalyst - Root controller furl:Catalyst - Root controller fark:Catalyst - Root controller blogmarks:Catalyst - Root controller Y!:Catalyst - Root controller smarking:Catalyst - Root controller magnolia:Catalyst - Root controller segnalo:Catalyst - Root controller

no comments

json iconperl iconcatalyst iconprototype icon

Prototype, JSON and Catalyst

Posted in , , , , Thu, 01 Jun 2006 00:42:00 GMT

I use the prototype.js library (aka prototype) for AJAX and recently moved to using JSON to return multiple elements instead of a single one. I had to rearchitect my client request code and my server code to handle JSON but it's worth it to minimize the number of HTTP requests. I use Catalyst and JSON::Syck which make generating the JSON response on the server-side very easy.

Prototype.js is interesting in that it auto-evals a JSON object that's placed in the X-JSON header instead of the response body like other libaries such as Dojo Toolkit. This allows you to send HTML in the response body but I'm not convinced this is a good implementation since it supports only one HTML fragment in the response body. I think it would be better to simply put the JSON object in the response body and have all the HTML fragments in the JSON object. I just seems cleaner to put all the HTML fragments in JSON instead of fragment 1 in the response body and fragments 2-n in JSON. Although I have the X-JSON header working, I may just move to the more standard JSON in response body approach and eval the JSON string myself. To read the auto-evaled JSON response, the following example expects a JSON associative array and displays the value of the myItem key (more code is available in the wiki link below):

onComplete: function( request, json ) {
    alert( json.myItem );
}

On the server-side, I use the Catalyst framework to set the header and JSON::Syck to transform Perl data structures to JSON. JSON::Syck is a wrapper around the C libsyck library and very fast. There is a view, Catalyst::View::JSON, however it puts the JSON string in the response body because that is what Dojo and other libraries expect. Since AJAX libraries don't idnetify themselves in anyway to the server (e.g. user agent), the Catalyst View would probably need a patch to with a configuration switch to populate X-JSON instead of the response body. For now, I'm using JSON::Syck directly. The following are the minimal calls to use. If you have UTF-8 output, see C::V::JSON for UTF-8 encoding.

$c->res->header(
    'X-JSON' => JSON::Syck::Dump( \%args );
);

I've put together some example code that I thought would be better placed on the wiki. It can be found at: Prototype.js, JSON and Catalyst.

UPDATE: After running into the IE max header length issue, I've decided to put the JSON object in the response body and manually eval request.responseText on the client.

del.icio.us:Prototype, JSON and Catalyst digg:Prototype, JSON and Catalyst reddit:Prototype, JSON and Catalyst spurl:Prototype, JSON and Catalyst wists:Prototype, JSON and Catalyst simpy:Prototype, JSON and Catalyst newsvine:Prototype, JSON and Catalyst blinklist:Prototype, JSON and Catalyst furl:Prototype, JSON and Catalyst fark:Prototype, JSON and Catalyst blogmarks:Prototype, JSON and Catalyst Y!:Prototype, JSON and Catalyst smarking:Prototype, JSON and Catalyst magnolia:Prototype, JSON and Catalyst segnalo:Prototype, JSON and Catalyst

6 comments

perl icon

Rose::DB::Object - aggregates

Posted in , , Thu, 01 Jun 2006 00:29:00 GMT

One of the advantages DBIx::Class has over Rose::DB::Object (RDBO) is that it natively handles GROUP BY, HAVING, etc. I use GROUP BY a lot so I asked John Siracusa how to do aggregate functions such as count and sum using GROUP BY with RDBO.

RDBO doesn't have native support for aggregates because it's designed to return row objects and the results of aggregate functions are not rows in any table. In the future RDBO may have a built-in get_results() Manager method that returns "data" instead of row objects, but for now there are two alternatives (quotes by Siracusa):

  1. Manager methods: "the RDBO way to do queries that have aggregates is to create a manager method that runs the desired query and returns the results. you can use the RDBO query builder to constrict the SQL if you want, the where part, for example"
  2. Views: "the other way is to make a view and have RDBO front that view as if it were a table letting the db do the aggregating part under the covers [...] big aggregate queries tend to be slow vs. a good view in a database that supports them well"
del.icio.us:Rose::DB::Object - aggregates digg:Rose::DB::Object - aggregates reddit:Rose::DB::Object - aggregates spurl:Rose::DB::Object - aggregates wists:Rose::DB::Object - aggregates simpy:Rose::DB::Object - aggregates newsvine:Rose::DB::Object - aggregates blinklist:Rose::DB::Object - aggregates furl:Rose::DB::Object - aggregates fark:Rose::DB::Object - aggregates blogmarks:Rose::DB::Object - aggregates Y!:Rose::DB::Object - aggregates smarking:Rose::DB::Object - aggregates magnolia:Rose::DB::Object - aggregates segnalo:Rose::DB::Object - aggregates

no comments

templatetoolkit iconperl iconcatalyst icon

Catalyst::View::TT 0.23 - render method

Posted in , , Wed, 31 May 2006 23:54:00 GMT

Catalyst::View::TT 0.23, the Template Toolkit View for the Catalyst MVC framework, was recently released on May 27, 2006 and just in time. It breaks out the render functionality as a separate method from the process method allowing direct rendering of TT templates in addition to handling the overall catalyst response. This is useful when you want to render a template for say an email body or fragments in a JSON response. The render method is accessed as follows:

my $output = $c->view('TT')->render(
    $c, 'mytemplate.tt', \%args
);

Prior to this, Catalyst::Plugin::SubRequest was the recommended way for rendering a TT template when C::V::TT was being used, e.g. the email body example in the SubRequest POD. This method is a kludge because SubRequest is designed to make public action requests, not for just rendering a template. I didn't mind using SubRequest just once to render a TT template for email, however I grew concerned when I starting using it multiple times to render HTML fragments to return via JSON. I was converting more private methods to public actions just so they could be called by SubRequest when I decided this was too kludgy and went to see if I could call TT directly. I went code diving in C::V::TT where I found the render method in 0.23 on search.cpan.org. I had to install 0.23 from the tarball directly since my CPAN shell would only give me 0.22.

SubRequest also seems to have a problem in that it nukes the Catalyst::Request parameters so $c->req->params is no longer populated correctly after a $c->subreq call. This created strange results without errors that were hard to pinpoint for me. On #catalyst, network_ninja mentioned he got around this problem by copying the params to $c->req->parameters and giving that to SubRequest. My solution is to just stop using SubRequest, at least when I only want to render a template.

Thanks to the Cat team for breaking out render and releasing it just when I went looking for it.

del.icio.us:Catalyst::View::TT 0.23 - render method digg:Catalyst::View::TT 0.23 - render method reddit:Catalyst::View::TT 0.23 - render method spurl:Catalyst::View::TT 0.23 - render method wists:Catalyst::View::TT 0.23 - render method simpy:Catalyst::View::TT 0.23 - render method newsvine:Catalyst::View::TT 0.23 - render method blinklist:Catalyst::View::TT 0.23 - render method furl:Catalyst::View::TT 0.23 - render method fark:Catalyst::View::TT 0.23 - render method blogmarks:Catalyst::View::TT 0.23 - render method Y!:Catalyst::View::TT 0.23 - render method smarking:Catalyst::View::TT 0.23 - render method magnolia:Catalyst::View::TT 0.23 - render method segnalo:Catalyst::View::TT 0.23 - render method

1 comment

Older posts: 1 ... 8 9 10