The Source for Java Technology Collaboration
User: Password:



Hans Muller

Hans Muller's Blog

Data Binding in Laszlo - Lessons for JDNC

Posted by hansmuller on April 07, 2005 at 05:05 PM | Comments (8)

For the past two months or so, I've been working with some of the JDNC developers on the databinding problem. After some false starts, the approach we've taken is to define "data aware" components and some special encapsulation classes for relational data. The overall goal is to make forms and master/detail applications relatively easy to build by automating most of the donkey work involved in interconnecting data sources with Swing GUI components and their attendant data and selection models. All in all not a terribly novel quest, however it's an important one and it's long overdue.

Data binding is an old problem and there are plenty of worthy examples to learn from. The support in ADO.NET and the newer version of that in Avalon certainly qualifies, although the complexity of Microsoft's solution should serve as a warning about the dangers of trading simplicity for generality. The JGoodies data binding system , which is based on the SmallTalk ValueModel idea, is another fine example. The Laszlo platform, which is popular among Flash aficionados and can boast some very beautiful demos, also supports basic data binding. I'd written a short review of Laszlo's databinding support recently and the JDNC developers with whom I'd been working suggested publishing it here.

In case you're already bored I'll provide the punchline first. We've observed that data binding systems that bury the natural syntax for specifying bindings with abstractions can be more trouble than they're worth. If I'm binding to JavaBeans then strings using the usual "bean.property" expression language notation are a nice way to specify bindings. Similarly, if you're binding to an XML document, then an XPath expression is a natural way to define a component's data source. Laszlo's data binding system is designed just for XML data and they employ an XPath subset for specifying bindings. Here's how.

What follows is based on a quick study of the data binding part of the Laszlo developer documentation, chapters 28-30 . The Laszlo designers had about as much flexibility as anyone could want, since they designed a new "language" (an XML schema) for defining applications that targeted Macromedia's Flash player.

Laszlo applications are defined by an XML document. Trivially simple GUIs survive the encoding and remain simple:

<canvas width="500" height="350">
    <text>Hello World</text>
</canvas>

Complex GUIs are probably more compact than a Java version however in my (biased) opinion, one ends up writing too much cryptic JavaScript/unix-shell style line noise like:

<tree datapath="*" text="$path{'@name'}" 
    isleaf="${this.datapath.xpathQuery('@type') == 'file'}"/>

The Laszlo platform includes a modest number of basic GUI controls; behavior is defined with JavaScript. There are a handful of very primitive layout managers however if the documentation is any indication, absolute layout is the norm. Platform look and feel fidelity is not a goal.

Laszlo supports XML data binding with XPath (a small subset) expressions. The XML data can be embedded in the application source code, which is good for examples, or it can be loaded from a URL. The binding system works nicely for simple things however once the world of "hello world" is left behind, Laszlo gets ugly in a hurry. There doesn't appear to be any support for master/detail applications with their pesky connections to selection. Apparently master/detail relationships must be defined at the level of writing "onClick" handlers. Updating a relational database is a similarly do-it-yourself operation.

That said, the basic XML data binding support is tidy enough, particularly if you're familiar with XPath syntax. To bind to an XML document you have to give it a name, and to do that you use the dataset tag:

<canvas>
    <dataset name="customerData">
        <customers>
	    <customer firstName="Fred" lastName="Mertz"/>
	    <customer firstName="Ethel" lastName="Mertz"/>
        </customers>
    </dataset>
    <simplelayout axis="x"/>
    <text datapath="customerData:/customers/customer[1]/@firstName"/>
    <text datapath="customerData:/customers/customer[2]/@firstName"/>
</canvas>

The dataset tag has a "src" attribute, like the HTML anchor or image tags, whose value is a URL. There's adequate support for programatically reconfiguring and and reloading a dataset and one can write handlers that get notified each time the dataset has been completely loaded.

Thanks to the "simplelayout" (like AWT flow) layout tag, this GUI just displays "Fred Ethel". The data binding for each text component is specified by the "datapath" attribute which names the dataset and, on the RHS of the ":", the XPath expression of the data that the component it bound to.

Note: if you're an XPath novice as I am, you might find the datapath expressions in the example a little bit confusing. They look like filesystem paths (and they're called "paths") but their semantics are subtly different. They're really patterns that match XML tag names and properties of XML elements and attributes. The latter are enclosed in square brackets, e.g. "[1]" means the element whose one-based index (relative to its siblings) is 1. So the XPath "/customers" means: all of the elements whose tag is "customers" and "/customers/customer[1]" selects the first child whose tag is "customer", and "/customers/customer[1].@firstName" selects its "firstName" attribute. It took me a while to stop trying to write "/customers[1]/@firstName". I'm over that now.

The Laszlo generic container class is called "view" and you can bind it to data and then use relative data binding paths on the components it contains. This example produces the same output as the previous one:

<canvas>
    <dataset name="customerData">
        <customers>
	    <customer firstName="Fred" lastName="Mertz"/>
	    <customer firstName="Ethel" lastName="Mertz"/>
        </customers>
    </dataset>
    <view datapath="customerData:/customers/">
      <simplelayout axis="x"/>
      <text datapath="customer[1]/@firstName"/>
      <text datapath="customer[2]/@firstName"/>
    </view>
</canvas>

Where Laszlo data binding gets interesting and ugly is in producing tables. There's no explicit table construct, you just bind a view to a list of elements and the GUI components contained by the view are "replicated", once for each list element.

<canvas>
    <dataset name="customerData">
        <customers>
	    <customer firstName="Fred" lastName="Mertz"/>
	    <customer firstName="Ethel" lastName="Mertz"/>
        </customers>
    </dataset>
    <simplelayout/>
    <view datapath="customerData:/customers/customer">
      <simplelayout axis="x"/>
      <text datapath="@firstName"/>
      <text datapath="@lastName"/>
    </view>
</canvas>

The XML above produces a GUI with four elements, like this:

Fred Mertz
Ethel Mertz

In other words, we're not binding firstName and lastName to columns in a special table component. What we've got is just short hand for creating one row of textfields for each customer element in the dataset. There is no selection support and watch out for large data sets. To deal with the latter you can try and configure the special "replication manager" which provides pools of components that can be reused for rows, and the "onclone" JavaScript callback that alerts you when a view has been replicated, and, well, yecch.

There are several other interesting features of the Laszlo databinding system that I don't think are worth diving into here. For example one can bind component attributes to XPath expressions (but be prepared to think hard about when those bindings are evaluated). There are "datapointers" which can be used to create bindings that get moved around with methods like datapointer.selectNext().

What's good about all of this is that, assuming you've got XML data, you can bind to that data using moderately intuitive XPath expressions. Returning to JDNC and given our canonical Customers, Orders, and Parts example, and a quick and dirty schema, you could write the bindings for the three tables (roughly) like this:

customersTable.setDataPath("/customers/customer");
ordersTable.setDataPath("/customers/customer[@selected]/order");
partsTable.setDataPath("/customers/customer[@selected]/order[@selected]/part");

<customers>
    <customer firstName="Fred" lastName="Mertz">
        <order id="o1">
	    <part id="p1"/>
	    <part id="p2"/>
        </order>
        <order id="o2">
	    <part id="p3"/>
        </order>
    </customer>
    <customer firstName="Ethel" lastName="Mertz"/>
        <order id="o3">
	    <part id="p4"/>
	    <part id="p5"/>
        </order>
    </customer>
</customers>

Here I've created a synthetic attribute called "selected" that's implicitly defined for all tags. If it's present then the corresponding XML DOM node is selected. The implication is that the binding engine that interpreted this binding would the customers JTable's selection model at run time. What's nice about this is that the developer gets to define the bindings using the same syntax as the (XML) data they're binding to.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • I think the JDNC (I can only remember the letter order by linking "JD" to Jack Daniels; please find a real name for it.) is on to something. I look forward to future articles and examples about other data bindings for non-xml data like complex object collections.

    (the comments system is broken: ignores text and html formatting)

    Cheers.

    Posted by: markswanson on April 07, 2005 at 07:04 PM

  • This is also quite like the data binding in XUI.
    We also use expression language like constructs to allow the programmer customize
    the path at runtime via a callback to their own classes.

    For example :
    <Data>
    <Bind target="firstNameEdit" source="users/${getCurrentUser()}/firstName"/>
    </Data>

    where 'getCurrentUser()' is a method in a Java class.

    We found that XPath expressions on their own weren't enough or just weren't
    that natural a way of doing things when programming Java. Being able to callback
    to Java adds alot of flexibility.

    We also added the ability to save the selection state of a component to an
    'output' path. If this output path is then used by more than one data binding
    it allows us to create a master-detail relationship between components.

    Posted by: luano on April 08, 2005 at 01:35 AM

  • Err....I believe you are talking about LASZLO (not Lazlo)..

    www.laszlosystems.com.

    I know it's not a typical English name, but for crying out loud, it can't be that hard to spell it properly over and over again. :-)

    Posted by: jacek on April 08, 2005 at 06:34 AM

  • Good post Luano. XPath expressions on their own are not enough. All of my data modelling has been in XML for many years, but I choose to programatically edit the data using Java because I'm comfortable with Java and creating Java implementations from XSD is so easy.

    A tool like XmlBeans allows me to navigate and modify the xml document and infoset by using XMLCursor, XMLQuery, XPath and it provides a full java interface too.

    Where I'm going with all of this: perhaps a really good solution that works well with X[Cursor,Path,Query], integrates well with the JDNC data bindings and provides a full Java interface is XmlBeans. Maybe the nice Java binding method mentioned by Luano wouldn't be needed because a Java binding is provided by XmlBeans.

    I guess my only question is, how hard would it be to integrate JDNC.
    partsTable.setDataSource(xmlbeansDocument) would be nice and seems naively easy.

    Comments most welcome.


    Posted by: markswanson on April 08, 2005 at 09:33 AM

  • I think a great example Sun could learn from is Apple's WebObjects; particularly Direct to java Client technology. Very amazing way to build 3 tier with rich swing clients.

    Also, for pure java desktop applications, please SUN just copy Apple's Cocoa tools, methodology and frameworks especially this:
    http://developer.apple.com/macosx/tiger/coredata.html

    Posted by: sesuler on April 08, 2005 at 03:49 PM

  • I used OGNL (http://www.ognl.org) to bind components to java objects during development of a web application with Tapestry. Since then, I wondered why I couldn't bind my Swing GUI in such a simple way to application logic objects.
    It would be great if the JDNC project adopted something similar. I think that with IDE integration (Netbeans, Eclipse, ...) data binding would then be really simpler...

    Posted by: nicfagn on April 19, 2005 at 07:52 AM

  • A new framework which also does databinding can be found at:
    www.strandz.org

    With strandz you write code rather than do everything in XML. Strandz supports 'lookups' as well as 'master-detail' and you can use it with the standard Swing gui controls.

    Posted by: cjmurphy on April 29, 2005 at 08:24 AM

  • Hello Hans,

    Maybe i can offer some help here. I have been working on a project called Scope MVC framework (http://scope.sourceforge.net).
    The main idea there was to use a clean model (java beans, xml document, resultset...) and bind them to the view components. In the version 2.0 i was developping until last year, you could use any kind of syntax to access your data (customer.order style for Java beans, xpath for xml docs...)

    This was quite complex to program and in fact i've stopped developement of this framework because of this and lack of time.

    But now i have other ideas, in particular i find the Service Data Object (SDO) JSR from BEA and IBM quite interesting for the binding stuff, you should have a look there.

    Posted by: ludovicc on May 06, 2005 at 04:45 PM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds