Archive for the ‘ajax’ Category

Comet: Reverse Ajax for streaming data from the server

Sunday, April 20th, 2008

Daniel Rubio (who maintains the blogs section for TSS.com) has written an article called “Comet: Reverse Ajax for streaming data from the server,” describing ‘Comet,’ a technology to push events from the server side to a browser client. Comet manages to avoid the issues related to having a browser poll a server to check for new events.

The first thing you need to realize is that the data service on the serverside needs to be designed to hold state on behalf of browsers clients, a process that can either be very difficult or very easy, depending on the platform and language you are using. Once again, this takes us to the stateless nature of Web applications and the way a browser needs to identify itself constantly either via cookies or session IDs, or what some characterize as the Hollywood principle – “don’t call us we’ll call you” – referring that only a browser is equipped to make calls and never vice-versa.

This last issue takes us down the road of building an asynchronous server application, or if you prefer a fancier name, an HTTP-based event routing bus, or in other words, a latent application on the serverside able to keep track of clients wishing to receive updates, a design very much in line with the messaging systems used in enterprise systems that are based on publish/subscribe channels.

However, since this last mechanism represents a departure from the “bread and butter” approach used in most Web platforms, it is a big reason why most Comet applications today rely on either custom adapted application-servers or embeddable versions that can tackle these issues. In the particular case of Java, Jetty and Grizzly are two servers that currently have out-of-the box support for Comet-type designs, with varying support in other languages like Python and other popular Java servers like Tomcat, for what is technically known as “continuation support,” a paradigm by which applications are shielded from the stateless nature of the Web. Continuation support also is a touted feature of higher-level language Web frameworks written in Smalltalk and Lisp that have this capability.

Turning our attention to the client side of things, a browser can take various routes to stay in contact with these type of server applications. Among these approaches are long-polling, dynamic script tags and inclusively a workaround using IFrames, none are standard approaches by any means, which is yet another reason why many client side Comet designs rely on the use of frameworks to abstract away incompatibilities between browser implementations – similar to Ajax – with one such framework being Dojo, which in itself now serves as both an Ajax/Comet framework.

Of course, the term Comet itself is something to wonder about. AJAX’ meaning is fairly well-known, as “Asynchronous Javascript and XML,” but what about Comet?

As far as the actual term is concerned, Comet emerged as a pun to Ajax’s meaning outside IT circles as a household cleaner. But quirky name or not, Comet is serving the purpose of an umbrella name for delivering data onto browsers as it becomes available on the serverside, a technique that will surely be of the same impact and go hand in hand with what we know today as Ajax. (theserverside)

Beyond Ajax: Software Development, Two Years from Now

Sunday, April 20th, 2008

Ajax has dramatically changed the lives of Web developers during the past two years, but the next two may be even more interesting. Developers—spurred by user expectations, rapidly evolving business models and ever-changing development processes—will need to do things they can’t even imagine today. And how can a forward-thinking IT department or entrepreneur—who is so dependent on innovative software developers—prepare for that future?

In a set of five articles, beginning with Beyond Ajax, CIO.com interviewed the tool builders. Their vision of the computing future will shape the tools they build, which means those are the programming tools you’ll use in a few years to build your own applications. But while CIO.com spoke with vendors, it was the techies, not the marketroids: folks like Tim Bray, Scott Guthrie, David Intersimone. Input was solicited from both vendors of proprietary software (such as Microsoft and Adobe) and open source projects (such as the Dojo Toolkit, and Open Laszlo).

Their predictions address the next round of developer opportunities, problems—and consequences. The articles cover a range of subjects, from The Convergence of Desktop, Web and Mobile Clients to UI changes (the immersive, cinematic interface) to evolving development tools which should make software development easier (what Dojo’s Alex Russell called “Interceding with the Browser gods”).

But Are Web Browsers Ready for the Next Generation of Internet Applications? Probably not, according to Tim Bray, who said, “The people who make a living building Web apps and tools for them live on a different planet than the people who build browsers.” All those problems… er, challenges were packaged up and handed to the folks who run Mozilla and IE, and the Browser dudes responded about making the Internet trustworthy, standards-compatible and innovative.

What kinds of developer tools would you like to see a few years from now? What are the toughest developer pain points you’d like tool vendors to address?

AJAX Google Pagerank Tool

Sunday, April 20th, 2008

InstantPageRanker.com is designed to give webmasters and web marketing professionals an SEO tool to instantly determine a website’s Google PageRank.

Type a website address in the box below to see the pagerank instantly (ie. www.tmtbox.com or tmtbox.com).

DWR 2.0 RC4 Released

Sunday, April 20th, 2008

DWR has a new release that should be pretty stable, with a final release coming soon.

Features

  • The biggy is Guice support. If it wasn’t for the fact that we could add this in without touching the core of DWR, I’d say this was too big a change at this point in the release cycle, however Tim Peierls (who you might know from this project) has done a stack of work to make DWR and Guice play really well together. You can read more about the background on Tim’s blog.
  • Security: The Fortify review highlighted some areas where DWR was lacking. You can read more about what DWR now does to protect you in the DWR security documentation.
  • Reverse Ajax: There have been some cases where reverse ajax has not been as stable as it should be. I hope that most of those are now behind us.

The reverse Ajax features are really quite something. If you haven’t checked them out yet, do so.

Getting Started with Ajax

Sunday, April 20th, 2008

The start of 2005 saw the rise of a relatively new technology, dubbed “Ajax” by Jesse James Garrett of Adaptive Path. Ajax stands for Asynchronous JavaScript and XML. In a nutshell, it is the use of the nonstandard XMLHttpRequest() object to communicate with server-side scripts. It can send as well as receive information in a variety of formats, including XML, HTML, and even text files. Ajax’s most appealing characteristic, however, is its “asynchronous” nature, which means it can do all of this without having to refresh the page. This allows you to update portions of a page based upon user events and provides one of the cornerstones of Rich Internet Applications (RIA) referred to in discussions of “Web 2.0.”

 

The DOM plays into Ajax in a number of ways. How you use the DOM depends a good deal on how you handle the content returned from the server. You can treat the con­tent as simple text using the responseText property of the server response, or you can treat it as XML using responseXML. Assuming the content you pull back from the server is an (X)HTML snippet and you’ve gotten it as responseText, you could drop that content into a particular spot on the page using innerHTML. On the flip side, if the content you pull back is XML and you’ve gotten it as responseXML, you can traverse its DOM, cherry-picking or performing functions on the elements, attributes, and text nodes.This probably sounds very confusing, but it is pretty easy once we go over a few simple examples. For these examples, we are using the XHConn library for simplifying our interaction with XMLHttpRequest(). The XHConn library is freely available at xkr.us/code/javascript/XHConn/ and allows simple access to XMLHttpRequest() by creating a new XHConn object and then initiating its connect() method as you will soon see.

As with the DOM Scripting examples (above), for a blow-by-blow of what the script is doing, read the JavaScript comments.

Example 1: Ajax with innerHTML

For a simple innerHTML-based Ajax example, we’ll create a quasi-functional address book application. We’ll start with the XHTML page (line wraps marked » —Ed.):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" »
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" »
  xml:lang="en" lang="en">
<head>
  <title>Ajax Address Book</title>
  <meta http-equiv="content-type" content="text/html; »
    charset=iso-8859-1" />
  <meta http-equiv="Content-Language" content="en-us" />
  <script type="text/javascript" src="XHConn.js"></script>
  <script type="text/javascript" src="addressBook.js"></script>
</head>
<body>
  <h1>Simple Ajax Address Book</h1>
  <form action="getAddress.php" method="POST">
    <fieldset>
      <legend>Please Choose a Person</legend>
      <select id="person" name="person">
        <option value="">Choose Someone</option>
        <option value="1">Bob Smith</option>
        <option value="2">Janet Jones</option>
      </select>
      <input type="submit" id="submit" name="submit" »
        value="Get the Address" />
    </fieldset>
  </form>
  <pre id="address"></pre>
</body>
</html>

As you can see, we have a simple form with a select, from which to choose a person. Again, we are providing a fallback action for the form, in case our JavaScript cannot run. Below the form, we have a simple pre element that will be displaying the address information from the database.

And now for the JavaScript. Basically, we will be commandeering the select and using its onchange event handler to trigger an XMLHttpRequest() call to obtain the address information for the selected individual. The server will be returning this information as a string like this:

Bob Smith
123 School Street
Anytown, NY 12345

We will take this return as a string and dump it into the pre element using innerHTML. Take a look at the code (line wraps marked » —Ed.):

var addressBook = {
  myConn:      false, // the XMLHttpRequest
  body:        false, // the body element
  target:      false, // the target container
  loader:      false, // the loader
  init:        function(controlId, sbmtBtnId, targetId){
    /* init() takes three arguments:
       * the id of the controller (select)
       * the id of the submit button
       * the id of the target container */
    // test for methods & elements
    if(!document.getElementById ||
       !document.getElementsByTagName ||
       !document.getElementById(controlId) ||
       !document.getElementById(sbmtBtnId)  ||
       !document.getElementById(targetId)) return;
    // set and test XHConn, quitting silently if it fails
    addressBook.myConn = new XHConn();
    if(!addressBook.myConn) return;
    // get the body
    addressBook.body = document.getElementsByTagName('body')[0];
    // get the controller
    var control = document.getElementById(controlId);
    // get the submit button
    var sbmtBtn = document.getElementById(sbmtBtnId);
    // remove the submit button
    sbmtBtn.parentNode.removeChild(sbmtBtn);
    // get the target
    addressBook.target = document.getElementById(targetId);
    // add the onchange event to the controller,
    addressBook.addEvent(control,
                         'change',
                         function(){
                           if(this.value != ''){
                             /* if there's a value,
                                trigger getAddress */
                             addressBook.getAddress(this.value);
                           } else {
                             // otherwise empty the target
                             addressBook.target.innerHTML = '';
                           }
                         });
  },
  getAddress:  function(id){ // the Ajax call
    // let's let the user know something is happening (see below)
    addressBook.buildLoader();
    /* this is the function that is run
       once the Ajax call completes */
    var fnWhenDone = function(oXML) {
      // get rid of the loader
      addressBook.killLoader();
      // insert the returned address information into the target
      addressBook.target.innerHTML = oXML.responseText;
    };
    // use XHConn's connect method
    addressBook.myConn.connect('index.php', 'POST',
                               'id='+id, fnWhenDone);
  },
  buildLoader: function(){     // builds a loader
    // create a new div
    addressBook.loader = document.createElement('div');
    // give it some style
    addressBook.loader.style.position   = 'absolute';
    addressBook.loader.style.top        = '50%';
    addressBook.loader.style.left       = '50%';
    addressBook.loader.style.width      = '300px';
    addressBook.loader.style.lineHeight = '100px';
    addressBook.loader.style.margin     = '-50px 0 0 - 150px';
    addressBook.loader.style.textAlign  = 'center';
    addressBook.loader.style.border     = '1px solid #870108';
    addressBook.loader.style.background = '#fff';
    // give it some text
    addressBook.loader.appendChild( »
      document.createTextNode( »
        'Loading Data, please wait\u2026'));
    // append it to the body
    addressBook.body.appendChild(addressBook.loader);
  },
  killLoader:  function(){     // kills the loader
    // remove the loader form the body
    addressBook.body.removeChild(addressBook.loader);
  },
  addEvent: function(obj, type, fn){  // the add event function
    if (obj.addEventListener) »
      obj.addEventListener(type, fn, false);
    else if (obj.attachEvent) {
      obj["e"+type+fn] = fn;
      obj[type+fn] = function() {
        obj["e"+type+fn](window.event);
      };
      obj.attachEvent("on"+type, obj[type+fn]);
    }
  }
};
/* run the init() method on page load, passing it
   the required arguments */
addressBook.addEvent(window, 'load',
                     function(){
                       addressBook.init('person',
                                        'submit',
                                        'address');
                     });

See this script in action.

Example 2: Ajax with Nodes

Let’s alter the example, and instead of returning a string from the server, this time, make it XML:

<file>
  <name>
    <first>Bob</first>
    <last>Smith</last>
  </name>
  <address>
    <street>123 School Street</street>
    <city>Anytown</city>
    <state>NY</state>
    <zip>12345</zip>
  </address>
</file>

The XHTML page remains the same, but we need to make some minor adjustments to the JavaScript. To highlight the differences, I will touch on each change individually.

The first change, to the onchange event handler of the select, is pretty simple (line wraps marked » —Ed.):

…
    addressBook.addEvent(addressBook.control,
                         'change',
                         function(){
                            if(this.value != ''){
                              addressBook.getAddress(this.value);
                           } else {
                             addressBook.target.removeChild( »
                               addressBook.target.firstChild);
                           }
                         });
…

Instead of setting the content of the target to empty using innerHTML, the DOM is removing the node that is the target’s first child.

Next up is the getAddress() method (line wraps marked » —Ed.):

…
  getAddress:  function(id){
    addressBook.buildLoader();
    var fnWhenDone = function(oXML) {
      addressBook.killLoader();
      if(addressBook.target.hasChildNodes()){
        addressBook.target.removeChild( »
          addressBook.target.firstChild);
      }
      xml = oXML.responseXML;
      var name    = addressBook.getNodeValue(xml, 'first')+' '+
                    addressBook.getNodeValue(xml, 'last');
      var address = addressBook.getNodeValue(xml, 'street');
      var csz     = addressBook.getNodeValue(xml, 'city')+', '+
                    addressBook.getNodeValue(xml, 'state')+' '+
                    addressBook.getNodeValue(xml, 'zip');
      var txt = document.createTextNode(name + "\ n" +
                                        address + "\n" + csz);
      addressBook.target.appendChild(txt);
    };
    addressBook.myConn.connect('getAddress.php', 'POST',
                               'id=' + id, fnWhenDone);
  },
…

As we are working with XML, we can use the responseXML property to get the return from the server as a node tree. Then we can traverse that tree, collecting the tidbits of information we need. In this example, we added a new method (getNodeValue()) that makes working with XML returns easier:

…
  getNodeValue: function(tree, el){
    return tree.getElementsByTagName(el)[0].firstChild.nodeValue;
  },
…

This method takes two arguments: the node tree (tree) and the element (el) whose content is wanted. It returns the nodeValue of the firstChild of the first el within tree or, in other words, the text value of the node requested from the node tree.

Once we have collected all of the requested contents from the XML, the text string is rebuilt and generated with the DOM before being appended to the target. The end result can be seen here.

You may be wondering, why do both examples do the exact same thing? It shows how you can work with two completely different backend systems and still get the results you want. In Ajax, as in many things, flexibility is important to get the job done.

Want to read more?

Web Design in a Nutshell, by Jennifer Niederst Robbins and featuring contributions from Darek Featherstone and Aaron Gustafson, has been completely rewritten to reflect the best practices of the web standards world and is on shelves now.

Ajax Resources

For more information on Ajax, consult:

About the Author

 Aaron Gustafson ALA technical editor Aaron Gustafson is the founder and principal consultant at Easy Designs, a web development boutique. He writes and speaks often on the various layers of the web standards cake, and works to improve the usability and accessibility of the web.

Open Ajax Alliance Member

Sunday, April 20th, 2008

 

The goal of Open Ajax is to make the delivery of rich Ajax user interfaces substantially easier than it has been for solutions. At the same time, the Open Ajax Alliance seeks to ensure that there is a compelling Ajax platform that remains independent of

  • Client browser, operating system, and device/hardware
  • Server container/language (Java, PHP, Ruby, C#, etc.), operating system, and hardware

Participants in the Open Ajax Alliance see collaboration through existing open source communities as our best means to preserve the multi-client, multi-server value proposition of the World-wide Web as we deliver richer user interfaces via Ajax and other Web 2.0 technologies.

At the same time, Open Ajax will support other Ajax runtimes, such as the Dojo Toolkit, in addition to Kabuki. The goal is to get a handful of open source Ajax toolkit runtimes to critical mass and ensure they are each well integrated with Eclipse and Mozilla technologies (Think SWT and Swing from the Java days).

DWR version 2.0 milestone 1 is released

Sunday, April 20th, 2008

This is probably the biggest release we’ve ever done in terms of new features.

Reverse Ajax

The biggest new feature is what we call Reverse Ajax. DWR 1.x allowed you to asynchronously call Java code from Javascript. DWR 2.0 builds on this to allow you to asynchronously call Javascript code from Java. Reverse Ajax makes writing interactive applications much easier. It can use polling or Comet (long-lived HTTP) queries.

Our ‘chat’ example contains Java code like this:

// Get the current page

WebContext wctx = WebContextFactory.get();

String currentPage = wctx.getCurrentPage();

// ’messages’ is a List of recent messages for a browser to display

// Java objects converted to Javascript have a declaration and a declared variable name.

OutboundVariable ov = wctx.toJavascript(messages);

// Loop over all the users on the current page

for (ScriptSession otherSession : wctx.getScriptSessionsByPage(currentPage)) {

    otherSession.addScript(ov.getInitCode() );

    otherSession.addScript(“receiveMessages(” + ov.getAssignCode() + “);” );

    //receiveMessages is a Javascript function 

    //that displays the current list of messages

}

In essence we are looping over all the users on the current page and sending them some Javascript to update their display. The Javascript is even simpler. You just turn polling on:

DWREngine.setPolling(true);

Chat example (included in the war download) includes the Javascript source to receiveMessages() which is a 4-liner that uses DWRUtil to put the messages on the screen.

Other uses for this technology include progress bars, online games, stock tickers and any system where server state changes and we need to push updates to a browser or browsers.

Cross Domain Ajax: <script> tag manipulation

Should you need to access servers in a different domain we’ve enabled a new remoting scheme. From DWR 2.0 you can use manipulation of <script> tags in addition to XMLHttpRequest or iframes. To use is you just need to do the following:

DWREngine.setMethod(DWREngine.ScriptTag);

The <signatures> Element

DWR 1.x sometimes needs a <signatures> element to help it get the type conversion right. If you are using DWR 2.0 with JDK5 generic types then you probably don’t need <signatures> any more. DWR will automagically get the right type conversion.

DWRUtil Updates

We’ve updated DWRUtils. There is a new DWRUtil.cloneNode(elementId) method that enables you to use HTML fragments as templates that are repeated. For example:

// Loop over all the beans

for (var i = 0; i < beanArray.length; i++) {

  // Fill in the blanks in the template. 

  DWRUtil.setValue(“someid”, beanArray[i].property);

  // Clone the node so we don’t overwrite it next time

  DWRUtil.cloneNode(“template”);

}

// Finally hide the template

$(“template”).style.display = “none”;

We’re also trying an experimental update to getValues to make it work more like a form. A Checkbox will return its value if checked and false if not. This might break backwards compatibility, it is slight non-obvious depending on your perspective so we need feedback on this one.

New Attribute Scope - Script

There is a new scope. Servlet/JSP developers are familiar with setting attributes at a request, page, session or application level. DWR 2.0 allows you to use “script” scope. With script scope you can persist variables for long-lived pages like single-page Ajax applications. Script scope is a bit like session scope in its longevity, however it does not require cookies. Script scope attributes are available to any Ajax operations within a single page. It is available to creators dwr.xml:

<create creator=“new” javascript=“Test” scope=“script”>

  <param name=“class” value=“com.example.Test”/>

</create>

Script scope is also available programatically:

WebContextFactory.get().getScriptSession().setAttribute(“key”, value);

Examples

Starting with DWR 2.0m1 the downloadable war file is quite a bit bigger than before because we are including some examples. We are working on simple Struts and Spring integration demos.

Refactoring

Refactoring is often a feature in the eyes of developers because the code feels cleaner, but it can just cause backwards compatibility issues for users. We’ve done some refactoring for DWR 2.0, but here is what users get out of it: We now use the org.directwebremoting.* package rather than the more obscure uk.ltd.getahead.dwr.*, but we’ve left stubs behind for backwards compatibility. Please shout if we’ve missed anything out. We’ve also tried to make DWR more embeddable, and it should now be possible to create alternative wire protocols like SOAP or JSON-RPC if desired.

Call Meta-data

You can now pass request attributes from DWR using call meta-data like this:

Remote.getData(42, {

  callback:function(str) { alert(str); },

  customKey:“Fred”,

});

The extra meta-data will then be available to Java in the HttpServletRequest. The following code will return the string “Fred”:

WebContextFactory.get().getHttpServletRequest().getAttribute(“customKey”);

Other Stuff

I very much doubt that anyone will notice, but we’ve removed deprecated.js. It’s been deprecated since around DWR version 0.9.

Security and Stability

We take security very seriously. DWR 1.x has proved to be very secure so far, but that does not mean we rest on our laurels. DWR 2.0 introduces a lot of new code. Reverse ajax and script based session management are places where we could easily slip up.

In addition in milestone 1, Reverse Ajax will create a much heavier load on your webserver than older stable releases. We’ve got 2 answers - the design allows server load-monitoring and dynamic back-off. More excitingly we’re working with Mortbay to allow DWR to use Jetty6 continuations if available to allow long lived HTTP requests without risking resource starvation.

So please do not use DWR 2.0 in a production system until we’ve had more testing and inspections.

Future Releases

This is just the first in an exciting set of milestones that we will be pushing out over the next few weeks. We’ve got more stuff coming!

Download

You can download DWR 2.0 M1 from the usual download page.