Tuesday, April 9, 2013

Custom Dojo Builds Using Gradle

The Dojo Toolkit provides a build utility that will minify packages of javascript and css source files. While this powerful tool works very well, I have struggled with finding the right set of best practices for more complex projects that depend on other third party modules.

My primary build tool is Gradle and in the past I tried treating third party javascript sources as Maven artifacts. The build would download and unpack the artifacts from my local repository, and then proceed to perform the build. The unpacking of the artifacts involved a lot of disk I/O and was incredibly inefficient. The unpacked artifacts ended up in the build directory and every time, clean was run the source files were removed. This wasn't working and it became time to reevaluate.

The Source Repository

The solution I came up with was to externalize the third party javascript source from the project. The source repository is a place on the file system outside of the project that houses javascript source code. By keeping a centralized source repository, the build no longer needs to retrieve and unpack third party javascript sources. So instead of manually installing the sources into a local maven repository, the sources need to be installed into the source repository. And there are future plans to automate the retrieval of sources and installation into the source repository. An example of a source repository might look as follows:

C:\JS_SOURCE\
    dgrid-0.3.6
    dojo-release-1.7.3-src
    dojo-release-1.8.3-src
    put-selector-0.3.2
    xstyle-0.0.5
The Dojo Gradle Plugin

I have multiple projects and as I refactored, it became clear that had repeated my self and was doing so again. It was time to write a Gradle plugin to support what I was doing. The plugin can use Java or Node to perform the custom Dojo Toolkit build.

The plugin can be loaded right from the Maven central repository:

buildscript {
    repositories {
        mavenCentral()
    }
        
    dependencies {
        classpath 'com.evinceframework:evf-build-gradle:0.1.0'
    }
}

When using the plugin, a build profile (i.e. build.profile.js) is not required. The profile will be generated from what is specified in the Gradle build script. The build script will look similar to:


version = '0.1.0.BUILD-SNAPSHOT'

apply plugin: 'dojo'

dojo {
    dojoVersion='1.8.3'
    sourceRepository=javascriptRepo
    buildWithNode=project.hasProperty('useNode').toBoolean() 
        && project.useNode.toBoolean()

    profile.configure {
        // packages - dojo, dijit added automatically.
        pkg name: 'dojox'
        pkg name: 'evf-example'

        // layers
        layer name: 'evf-example/app', 
          includes: ['evf-example/CustomWidget']
    }
}

With this build script, a build can be executed with the following command

> gradle build -PjavascriptRepo=C:/JS_SOURCE

When a build executes, it will first install the source code from the project into the source repository.

C:\JS_SOURCE\my-webclient-0.1.0.BUILD-SNAPSHOT

The output of the build is put into the project's build directory but can be configured to be written elsewhere.

The source of the plugin is located https://github.com/cswing/evinceframework-build.

A working example project at https://github.com/cswing/evinceframework-build/tree/master/example.

Documentation can be found in the wiki.

Future of the plugin
  • Add the ability to install a specific version of the Dojo Toolkit SDK into the source repository.
  • Add the ability to install a maven artifact into the source repository.
  • Add the ability to install source from GitHub projects into the source repository.
  • Add the ability to install source from Google Code into the source repository.
  • Add the ability to remove a project from the source repository.
  • Add the ability for a project to define it's dependencies, and automatically install them into the source repository if not already installed.
  • Package the source as an artifact that can be published using the Maven plugin.

Monday, April 8, 2013

Base Mixin For Creating Widgets

The use of AMD became the standard way of writing custom widgets in v1.7 of the Dojo Toolkit. With the refactoring to AMD modules, a lot of utility functions that were located off of the root dojo module now need to be included in the require statement. As a result, I found myself writing the following code for each custom widgets I was creating:
define([
    "dojo/_base/config",
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dojo/dom-attr",
    "dojo/dom-class",
    "dojo/dom-construct",
    "dojo/dom-style",
    "dojo/on",
    "dojo/Evented",
    "dijit/_Widget"
], function(config, declare, lang, domAttr, domClass, 
      domConstruct, domStyle, on, Evented, Widget){
    /* widget definition */
});
In an attempt to avoid always having to require these common modules, I have created a ComplexWidget mixin that will require these common modules and make them available as properties on the widget. This widget is released under the Apache License v2.0 and the latest code can be found here.
define([
 "dojo/_base/config",
 "dojo/_base/declare",
 "dojo/_base/kernel",
 "dojo/_base/lang",
 "dojo/dom-attr",
 "dojo/dom-class",
 "dojo/dom-construct",
 "dojo/dom-style",
 "dojo/on",
 "dojo/Evented",
 "dijit/_Widget"
], function(config, declare, kernel, lang, domAttr, domClass, 
      domConstruct, domStyle, on, Evented, Widget){
 
    return declare("evf/ComplexWidget", [Widget, Evented], {
  
        kernel: kernel,
  
        dojoConfig: config,
  
        lang: lang,
  
        domAttr: domAttr, 
  
        domClass: domClass, 
  
        domConstruct: domConstruct, 
  
        domStyle: domStyle,
  
        dojoOn: on,
  
        listen: function(target, type, listener, dontFix) {   
            var hndl = 
              on(target, type, this.hitch(listener), dontFix);
     
            this.own(hndl);
            return hndl;
        }, 
  
        hitch: function(fn) {
            return lang.hitch(this, fn);
        }
    });
});
Writing a custom widget looks like the following:
define([
    "dojo/_base/declare",
    "evf/CustomWidget"
], function(declare, ComplexWidget){

    return declare("myApp/MyWidget", [ComplexWidget], {        

        postCreate: function(){
            this.inherited(arguments);
            this.domClass.add(this.domNode, 'MyWidgetCssClass');
        }
    });
});

The result is easy access to commonly used modules without having to write a lot of boilerplate code.

Tuesday, May 8, 2012

Dojo Resources

I have been asked in the past week by multiple people what are some good resources to use when working with the Dojo Toolkit. The following is far from an all inclusive list, but they are the resources I use when working with the Dojo Toolkit. Please feel free to post other Dojo resources in the comments.

The Dojo Module

I find myself using Dojo's Reference Guide when working with functions in the dojo module. These tend to be non ui widgets that are utilities. These areas include but are not limited to:

  • dojo.xhrGet, xhrPost
  • dojo.Deferred
  • dojo.data.ItemFileReadStore
  • dojo.store.Memory
  • dojo.connect, dojo.subscribe
  • dojo.query

The Dijit Module

The Dijit Theme Tester provides a good catalog to browse the UI widgets in the dijit namespace. I have the source code on my development machine and when I am looking to modify the behavior of a widget, I look directly in the source code. The Reference Guide gives some basic examples for the widgets. The tests are also a good source options and configuration examples. I don't usually load a test in the browser, I just browse the tests to see the examples.

The DojoX Module

The code that exists in the DojoX module is experimental and not guaranteed to maintain its API from release to release. Code stays here because of a number of reasons including not being properly documented. Lack of documentation can make using a piece of code difficult to use. Using code in this module almost always requires diving into the source code to make it work.

Miscellaneous

  • jsFiddle is a place where you can create and share snippets.
  • I also have a "sandbox" web site set up on my development machine where I can create html files to quickly demo different scenarios.
  • Dojo has a mailing list
  • Stack Overflow
  • Google Chrome - the debugger is fantastic.

Monday, April 16, 2012

Preventing a CSS Jungle

The problem using CSS in a large project is that over time the amount of CSS grows. When a rule is defined generically, like .shadedData, then it is difficult to know every place it is used. And when a developer doesn't know where it is used, modifying the style is done by adding a new rule .shadedData2. Even rules that aren't as generic as this can suffer the same fate. A CSS garden quickly becomes a jungle.

I recently had to add support for multiple themes to a product. The product is going to be OEM'd and needs to represent different companies' brands. The product had a lot of CSS that had become overgrown. In this post, I am going to describe the changes I made to the CSS infrastructure to support multiple themes and to also help the development team better maintain the CSS rules. And even if a project only needs a single theme, I think the following infrastructure is still beneficial to a project.

File Structure
themes
  common
    images
    layout
      header.css
    pages
      account.css
    widgets
      dialog.css
      button.css
    common.css

  oemA
    images
    layout
      header.css
    pages
      account.css
    widgets
      dialog.css
      button.css
    oemA.css

  oemB
    images
    layout
      header.css
    pages
      account.css      
    widgets
      dialog.css
      button.css
    oemB.css

The common theme contains general layout rules that will be used for all themes. There are no hard and fast rules for what belongs in the common theme, but it should be anything that should be used in all OEM themes, including heights, widths, paddings, and margins. Generally the common theme wouldn't contain any color definitions. However, with the work I just recently completed, there was part of the application that used a grey color and did not change based on the OEM, so I put it in the common theme. Again, this can be more of an art and you should do what feels right for you. You can always move things later.

The oemA and oemB directories contain css rules for particular OEMs. Only one of these themes should be used at a time in combination with the common theme. The css rules in these files are specific to the OEM and are generally the color scheme. The product I was recently working on is a business application and we weren't looking to make any major changes to the UI. The colors and in some cases the fonts were changed.

This is a good place to talk about CSS preprocessors. SASS and LESS are two examples of such preprocessors. Preprocessors allow you to define variables (colors, borders, etc) and then use the variables throughout the stylesheets. At first glance, it would appear that these preprocessors would eliminate the need to have oemA and oemB defined. One could just have the a single set of CSS rules defined and apply a different set of variables for each OEM. However, it was my experience that the colors don't translate one for one across themes. For example, in the original theme there were tabs that used the primary color of the theme. When implementing an additional theme, the tabs looked better using one of the secondary colors. It is my opinion that the CSS preprocessor provides value when used within a theme, but should not be used to provide variables across themes.

In the file structure above, the images directory contains images for the particular theme. I don't believe it is a good practice to reference images in a different theme. However, one exception is referencing images in the common theme. The common theme could contain a set of icons and for a particular OEM theme and you might want to override an image with one of those icons. Again, there are no hard and fast rules; this is an art.

The layout directory contains files that define CSS rules for the framework of the web application. These include things like headers, footers and sidebars. The pages directory is for specific page layouts within the application. The widgets directory is for widgets that are used throughout the application. Buttons and dialogs are two examples of such widgets.

The CSS
.themeName .pageOrWidget .theSpecificCssRule

What makes this concept work is nesting CSS selectors. Each CSS rule declaration should begin with the theme that it belongs to. The theme name should be added to the CSS of the body element and by doing so, you now control whether or not a theme is applied to the page. This is how Dojo applies themes.

Each CSS rule declaration should further restrict its use by specifying the page or widget that it is being used for as the second CSS selector. Each combination of the first two CSS selectors should equate to its own file in the file structure above. Any CSS selectors after the first two are specific to the need of the rule.

The Account Page Example
<body class="common oemB">
  <div class="logo"></div>
  <div class="accountPage">
    <div class="button">
      <span class="buttonText">OK</span>
    </div>
    <div class="accountSummary">...</div>
  </div>
</body>
/* common/widgets/button.css */
.common .button .buttonText {
 font-size: 1.25em;
}

/* oemA/widgets/button.css */
.oemA .button .buttonText {
 color: red;
}

/* oemB/widgets/button.css */
.oemB .button .buttonText {
 color: green;
}

Looking at this example, I would expect the logo to be defined in header.css, the button and buttonText to be defined in the button.css and accountSummary in the account.css

Compressing CSS

While defining CSS rules across multiple files is good for maintenance, it's horrible for production. So as part of the build process, the CSS files should be compressed and combined into fewer. I generally make one file per theme and the server side code that emits the html knows what stylesheets to include and what css classes to add to the body element.

The General CSS Declaration
.color { color: red; }

<div class="button">
    <span class="red">OK</span>
</div>

Avoid the general approach. What happens if we want to make the color blue? We have to modify the code that creates the widget to apply the blue class. What about multiple themes that each use a distinct color? The widget now needs to have knowledge of the current theme. The purpose of CSS is to take this responsibility away from the widget code. By using the general approach, the widget is again responsible for specific styling logic.

The widget code should be thought of as defining the theme "interface" using CSS classes. The CSS rules are the implementations of the "interface". The class names that make up the "interface" should describe their purpose (.buttonText) but not a specific implementation (.red).

CSS Grouping
.oemA .button .buttonText,
.oemA .button .buttonText.important,
.oemA .anotherWidget .widgetText {
 color: red;
}

CSS grouping provides the ability to not repeat yourself. While we as developers always try to adhere to the DRY principle, it has been my experience that overusing CSS grouping leads to poor maintainability.

Using the example above, where would the CSS rule reside in the file structure that we previously defined? You could make a common file beneath the widgets directory for rules like this. The problem with this approach is that over time a lot of widget rules would migrate to the common file and when you need to make modifications to a widget, it will require you to look in multiple files. Worse yet, if this rule lives in the anotherWidget file, looking for all button CSS now requires you to look throughout the jungle, thus defeating the purpose of having a separate file per widget.

/* oemA/widgets/button.css */
.oemA .button .buttonText,
.oemA .button .buttonText.important {
 color: @red; /* @red is less syntax */
}

/* oemA/widgets/anotherWidget .css */
.oemA .anotherWidget .widgetText {
 color: @red; /* @red is less syntax */
}

I think a better approach is to limit the use of CSS grouping to rules that belong in a single file and use a CSS preprocessor to provide common definition across multiple files within a single theme. This allows for the definition of red to be defined once and allows the CSS rules for a specific widget to live in a single file.

Wrapping Up

I have mentioned this a couple times throughout the post, but it bears repeating - using CSS is very much an art. I have tried to define a set of best practices around CSS that allows CSS to do what it was designed to do and still be maintainable across a large project that over time will inevitably have to be modified and even refactored.

Wednesday, April 11, 2012

A JSON Serialization Engine - Part II


In part I, I introduced the JsonStoreEngine and described how the developer uses the engine to serialize Java objects into JSON and can customize how the engine serializes certain objects. In this post, I am going to show more of the inner workings of the JsonStoreEngine.

Under the hood, the JsonStoreEngine uses Jackson for the JSON serialization. The JsonStoreEngine provides the logic to emit the flat list of items using the reference object notation to represent object references.

A Simple Example
public class OrderStatus {
    
    public String getIdentifier();
    
    public String getName();
    
    public String getDisplayOrder();
}

public class OrderStatusJsonConverter 
 extends AbstractTypedJsonConverter<OrderStatus> {

    public String determineIdentifier(OrderStatus obj) {
        return String.format("orderStatus::%s", obj.getIdentifier()); 
    }
    
    protected String onDetermineType(OrderStatus obj);
        return "orderStatus";
    }
    
    protected void onWriteObjectProperties(
      JsonSerializationContext context, OrderStatus obj) 
      throws IOException;
      
        context.writeProperty("name", obj.getName());
        context.writeProperty("order", obj.getDisplayOrder());
    }
}
The above example is the most basic. An OrderStatus object has no references to other objects and the engine serializes the primitive properties. This example produces the following output:
[{ id: 'orderStatus::1', _type: 'orderStatus', 
    name: 'Pending', order: 10 
}]

A Bigger Example
Here is an example where the engine serializes object references.
public class Order {
    
    public String getIdentifier();

    public String getOrderNumber();
    
    public Customer getCustomer();
    
    public OrderStatus getOrderStatus();

    public List getOrderLineItems();
}

public class OrderJsonConverter 
 extends AbstractTypedJsonConverter<Order> {

    public String determineIdentifier(Order obj) {
        return String.format("order::%s", obj.getIdentifier()); 
    }
    
    protected String onDetermineType(Order obj);
        return "order";
    }
    
    protected void onWriteObjectProperties(
      JsonSerializationContext context, Order obj) 
      throws IOException;
      
        context.writeProperty("orderNumber", obj.getOrderNumber());
        context.writeProperty("customer", obj.getCustomer());
        context.writeProperty("orderStatus", obj.getOrderStatus());
        context.writeProperty("lineItems", obj.getOrderLineItems());
    }
}
And the output produced:
[{ id: 'order::1', _type: 'order', orderNumber: 1234, 
    customer: { _reference: 'customer::1' }, 
    orderStatus: { _reference: 'orderStatus::1' },
    lineItems:[
        { _reference: 'orderLine::1' }, 
        { _reference: 'orderLine::2' }
    ]
},
{ id: 'customer::1', _type: 'customer', 
    name: 'Anderson, Jose'
},
{ id: 'orderStatus::1', _type: 'orderStatus', 
    name: 'Pending', order: 10 
},
{ id: 'orderLine::1', _type: 'orderLine', 
    order: { _reference: 'order::1' }, 
    price: 1.07, quantity: 10, 
    product: { _reference: 'product::1' } 
},
{ id: 'orderLine::2', _type: 'orderLine', 
    order: { _reference: 'order::1' }, 
    price: 4.48, quantity: 1, 
    product: { _reference: 'product::2' } 
}]

Where the Engine Does the Work
context.writeProperty("orderStatus", obj.getOrderStatus());
When the converter asks to write the order status, the engine intercepts and emits the reference object. The engine then registers the object for deferred serialization, only if the object hasn't already been serialized or registered for deferred serialization. Once the serialization of the original object is complete, the engine then serializes the objects that had been deferred.

Using the JsonStoreEngine and the ViewModelStore, we now have a framework in place to ship a complex model of data that is represented by Java objects on the server to javascript objects that can be consumed on the web client and used as a view model. The complexity of the data model can include references to other objects, circular object references and self references and also gives us control to specify how certain objects are serialized.

This will be a core component to building a Dojo View to plug into Spring's Web MVC architecture. The code for the serialization engine is checked into the evince framework repository on GitHub. There is also some more documentation on how to customize the serialization and conversion process.

Monday, April 9, 2012

A JSON Serialization Engine - Part I


In this previous post, I describe a specific JSON format that I want to consume on the client side using Dojo. In this post, I am going to show how to take a Java object and create that JSON format using the JsonStoreEngine.

The JsonStoreEngine is something I have written, has a simple API and works as a black box. The developer passes a Java object into the engine and the engine gives a custom formatted JSON structure back. The JsonStoreEngine also provides flexibility, giving the developer the ability to customize and control how particular objects are converted to JSON.

This version of the JsonStoreEngine is one way. It does not support deserialization. My primary use case for this engine is to serialize an object graph into a Dojo store, so that I can use the data on the client side to build the web page. When communicating back with the server, I only send a limited set of data using the standard HTTP post mechanism.

The Data

This custom JSON format is flat list of items where references to other items use a special notation. The following is an example of that structure:
var dataArr = [
  { id: 'customer::1', _type: 'customer', 
    name: 'Anderson, Jose',
    address: { _reference: 'address::1' } 
  },
  { id: 'address::1', _type: 'address', 
    address1: '2272 Stratford Drive', 
    address2: 'Honolulu, HI 96814' 
  },
  { id: 'customer::2', _type: 'customer', 
    name: 'Gomez, Marcus',
    address: { _reference: 'address::2' } 
  },
  { id: 'address::2', _type: 'address', 
    address1: '2718 College Avenue', 
    address2: 'Dayton, OH 45459' 
  },

  // ... other customers ...

  { id: 'product::1', _type: 'product', 
    name: 'Ball Original Classic Pectin Small Batch', 
    price: 1.07 
  },
  { id: 'product::2', _type: 'product', 
    name: 'Ball 4-Pk 16 Oz. Wide Mouth Class Canning Jars with Lids', 
    price: 4.48 
  },

  // ... other products ...

  { id: 'orderStatus::1', _type: 'orderStatus', 
    name: 'Pending', displayOrder: 10 
  },
  { id: 'orderStatus::2', _type: 'orderStatus', 
    name: 'Back Ordered', displayOrder: 30 
  },
  { id: 'orderStatus::3', _type: 'orderStatus', 
    name: 'Shipped', displayOrder: 20 
  },
  { id: 'order::1', _type: 'order', orderNumber: 1234, 
    customer: { _reference: 'customer::1' }, 
    orderStatus: { _reference: 'orderStatus::1' },
    lineItems:[
        { _reference: 'orderLine::1' }, 
        { _reference: 'orderLine::2' }
    ]
  },
  { id: 'orderLine::1', _type: 'orderLine', 
    order: { _reference: 'order::1' }, 
    price: 1.07, quantity: 10, 
    product: { _reference: 'product::1' } 
  },
  { id: 'orderLine::2', _type: 'orderLine', 
    order: { _reference: 'order::1' }, 
    price: 4.48, quantity: 1, 
    product: { _reference: 'product::2' } 
  },

  // ... other orders ...
];
The API

The API consists of two methods. The developer can call serialize only passing the object to be serialized. The JSON will be returned as a String to the developer. Alternatively, the developer can also pass an OutputStream. Doing so will write the JSON to that stream and nothing will be returned.
public String serialize(Object model)

public void serialize(OutputStream out, Object model) 
    throws IOException
Customizing the Conversion

The default converter is the PojoConverter. In the example below, a second PojoConverter is registered to handle the OrderLine class. Now anytime an OrderLine object is serialized, this converter will be used. This converter is configured to only serialize two fields: product and price. So looking at the data example above, the order field of an OrderLine object would not be serialized.
JsonStoreEngine engine = new JsonStoreEngine();
  
PojoConverter productConverter = new PojoConverter();
productConverter.setIncludeFieldsByDefault(false);
productConverter.setOverriddenFields(
  new String[] { "product", "price" });
engine.getLookupMap().put(OrderLine.class, productConverter);
The developer can also create a custom implementation of the JsonConverter interface. This custom implementation can then be registered in the same manner as the as the PojoConverter above.

The code for the serialization engine is checked into the evince framework repository on GitHub. In part II, I will look into the black box and go over the details of how the engine works.

Monday, March 12, 2012

Dojo: Implementing a ViewModelStore

In the 1.6 release of Dojo, a new Store API was released with the intentions of improving on the design of the Data API. While I agree with most of the new Store API design, there is one feature of the Data API that I make significant use of and it was not carried forward into the Store API. The missing feature is the data structure that is used to initialize the store. In this post I will discuss why I find it important and create a store that uses the legacy structure and also implements the new Store API.

I use a data store as a page view model providing the needed data to the widgets on the page. The data has many references and I want to be able to query the store for any object within it. The legacy Data API uses a flat list of items. Any references to other items are identified using a "_reference" attribute. When the store initializes, it will replace the "_reference" object with the actual object. This allows for a normalized model with all objects queryable in the store.

The Data

For this example, the view model contains multiple orders. I want to be able to create a combobox with all of the customers and a combobox with all possible order statuses. The orders that are shown should match the customer and order status selected in the comboboxes.

var dataArr = [
  { id: 'customer::1', _type: 'customer', 
    name: 'Anderson, Jose',
    address: { _reference: 'address::1' } 
  },
  { id: 'address::1', _type: 'address', 
    address1: '2272 Stratford Drive', 
    address2: 'Honolulu, HI 96814' 
  },
  { id: 'customer::2', _type: 'customer', 
    name: 'Gomez, Marcus',
    address: { _reference: 'address::2' } 
  },
  { id: 'address::2', _type: 'address', 
    address1: '2718 College Avenue', 
    address2: 'Dayton, OH 45459' 
  },

  // ... other customers ...

  { id: 'product::1', _type: 'product', 
    name: 'Ball Original Classic Pectin Small Batch', 
    price: 1.07 
  },
  { id: 'product::2', _type: 'product', 
    name: 'Ball 4-Pk 16 Oz. Wide Mouth Class Canning Jars with Lids', 
    price: 4.48 
  },

  // ... other products ...

  { id: 'orderStatus::1', _type: 'orderStatus', 
    name: 'Pending', displayOrder: 10 
  },
  { id: 'orderStatus::2', _type: 'orderStatus', 
    name: 'Back Ordered', displayOrder: 30 
  },
  { id: 'orderStatus::3', _type: 'orderStatus', 
    name: 'Shipped', displayOrder: 20 
  },
  { id: 'order::1', _type: 'order', orderNumber: 1234, 
    customer: { _reference: 'customer::1' }, 
    orderStatus: { _reference: 'orderStatus::1' },
    lineItems:[
        { _reference: 'orderLine::1' }, 
        { _reference: 'orderLine::2' }
    ]
  },
  { id: 'orderLine::1', _type: 'orderLine', 
    order: { _reference: 'order::1' }, 
    price: 1.07, quantity: 10, 
    product: { _reference: 'product::1' } 
  },
  { id: 'orderLine::2', _type: 'orderLine', 
    order: { _reference: 'order::1' }, 
    price: 4.48, quantity: 1, 
    product: { _reference: 'product::2' } 
  },

  // ... other orders ...
];

The ViewModelStore

The ViewModelStore extends the MemoryStore and the core component is the implementation of setData. Here, each item in the array is registered. After an item is registered and if previous objects contain a reference to the object, a setter function will be called and the reference to the newly registered object will be set. Using the data above as an example, after registering the address object, a previously registered setter function will be called to set the address property of the customer to this address object.
setData: function(data){
    ...
    this.index = {};
    
    // when a reference to an item has not been registered,  
    // a setter function is added and will be called when 
    // the item is registered. 
    this._referenceSetters = {};
    
    // loop through the flat list of items
    dojo.forEach(this.data, function(itm, idx) {
        
        var itmId = itm[this.idProperty]; 
        this.index[itmId] = idx;
        
        for(var prop in itm) {
            this._registerItem(itm, prop); 
        }
        
        // process the queue of deferred setters for this object.
        if (this._referenceSetters[itmId]) {
            dojo.forEach(this._referenceSetters[itmId], 
              function(fnSet) { fnSet(itm); }
            );
            this._referenceSetters[itmId] = null;
        }
        
    }, this);
    
    delete this._referenceSetters;
}
Registering an item determines if it is an array or not. If so, it will call the inspectValue function for each item of the array, otherwise it is called for the item itself. The inspectValue function determines if it is a reference to another object in the data. If it isn't, then there is nothing more to do. If it is a reference and the referenced item has already been registered, then that item replaces the object identified by the reference. If the item has not been registered, then a function to set the value is registered to be called when the reference is registered.
_inspectValue: function(val, fnSetter) {
    
    var refProperty = this.referenceProperty || '_reference';
    
    // not a 'referece', so return the value.
    if (!val || !dojo.isObject(val) || !val[refProperty]) {
        fnSetter(val);
        return; 
    }
    
    var refId = val[refProperty];
    var refItm = this.get(refId);
    
    // the referenced item has already been loaded, return it. 
    if (refItm) {
        fnSetter(refItm); 
        return;
    }
    
    //we don't have the reference yet, qo queue a deferred setter that 
    //will set the value once the item is registered.
    if (! this._referenceSetters[refId]) {
        this._referenceSetters[refId] = [];
    }
    this._referenceSetters[refId].push(fnSetter); 
},

Using the ViewModelStore

The code snippet below creates two comboboxes and populates them using the data from the store. The onChange events are then wired to a function that queries the store using the filters specified in the comboboxes and renders the orders. If a new status is to be added later, it simply has to be put into the view model and the page will handle it accordingly.
var customer = new ComboBox({
    store:  store,
    query:  { _type: 'customer' },
    labelAttr: 'name'
}, dojo.byId('customerNode'));
customer.startup();

var status = new ComboBox({
    store:  store,
    query:  { _type: 'orderStatus' },
    labelAttr: 'name'
}, dojo.byId('statusNode'));
status.startup();

var fnDisplayOrders = function() {
    
    var contentNode = dojo.byId("content");
    var displayedOrder = false;
    domConstruct.empty(contentNode);
    
    var result = store.query({ 
        _type:          'order',
        customer:       customer.get('item'),
        orderStatus:    status.get('item'),
    });
    
    result.forEach(function(order) {
        displayedOrder = true;
        var div = dojo.create('div', {}, contentNode);
        dojo.addClass(div, 'order');
        
        var header = dojo.create('div', {}, div);
        dojo.addClass(header, 'orderHeader');
        header.innerHTML = dojo.replace(
          'Order #: {orderNumber}<br/>{customer.firstName}
          {customer.lastName}<br/>{customer.address.address1}
          <br/>{customer.address.address2}',
          order );
        
        ... more rendering logic ...
    });
    
};

dojo.connect(customer, 'onChange', fnDisplayOrders);
dojo.connect(status, 'onChange', fnDisplayOrders);
The complete example can be found at https://gist.github.com/2010137