Listing 1: Country JavaBean

public class Country {

	private String countryName;
	private String countryCode;
	private String capitalCity;

	public String getCountryName() {
		return countryName;
	}
	public void setCountryName(String countryName) {
		this.countryName = countryName;
	}
	
	public String getCountryCode() {
		return countryCode;
	}
	public void setCountryCode(String countryCode) {
		this.countryCode = countryCode;
	}
	
	public String getCapitalCity() {
		return capitalCity;
	}
	public void setCapitalCity(String capitalCity) {
		this.capitalCity = capitalCity;
	}
}


Listing 2: CountryDAO class

public class CountryDAO {
	
	public List<Country> getCountries() {
		....
	}
}



Listing 3: DWR Configuration (dwr.xml)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC
	"-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" 
	"http://getahead.org/dwr//dwr20.dtd">
<dwr>
  <allow>
    <create creator="new" JavaScript="CountryDAO">
    	<param name="class" value="CountryDAO"/>
      <include method="getCountries"/>
    </create>
    
    <convert match="Country" converter="bean"/>
  </allow>
</dwr>


Listing 4: JavaScript to get countries using DWR

<!- Include DWR files -->
<script type='text/JavaScript' src="/dwr/interface/CountryDAO.js"></script>
<script type='text/JavaScript' src="/dwr/engine.js"></script>
<script type='text/JavaScript' src="/dwr/util.js"></script>

<script>
...
// Get list of countries from server
CountryDAO.getCountries(getCountriesCallback);

var getCountriesCallback = function(data)
{
    //data is an array of JSON objects
    ...
}
...
<script>



Listing 5

if(!dojo._hasResource["DWRReadStore"]){
dojo._hasResource["DWRReadStore"] = true;
dojo.provide("DWRReadStore");

dojo.require("dojo.data.util.simpleFetch");

dojo.declare("DWRReadStore", null,{
    // The DWRReadStore implements the dojo.data.api.Read API and reads
    // data from the server using DWR
    constructor: function(params){
        this._features = {'dojo.data.api.Read':true};
    },
	
    getFeatures: function(){
        return this._features; 
    },

    _fetchItems: function(args,findCallback,errorCallback){ 
    },

    close: function(request){
         // We do not have any special cleanup requirements
    }
});

dojo.extend(DWRReadStore,dojo.data.util.simpleFetch);
}



Listing 6: DWRReadStore constructor

constructor: function(params){
    this._features = {'dojo.data.api.Read':true};        
    this._dwrMethod = params.dwrMethod;
    this._items = [];
    this._loadComplete = false;
    this._loadInProgress = false;
},



Listing 7: Implementation of _fetchItems with simple data caching

_fetchItems: function(args,findCallback,errorCallback){
    var self = this;
    // Function to apply filter to data set
    // This function will be implemented in the next section
    var filter = function(requestArgs, items){
        findCallback(items, requestArgs);
    };

    // If the data has already been return the previously loaded data
    if(this._loadComplete){
        filter(args, self._items);
    }else{
        if(this._dwrMethod ){
            // If a new request comes in before the previous one
            // is finished, we will ignore the request. 
            if(!this._loadInProgress){
                this._loadInProgress = true;
                this._dwrMethod(function(data){
                    try{
                        self._items = data;
                        self._loadComplete = true;
                        self._loadInProgress = false;

                        filter(args, self._items);
                    }catch(e){
                        self._loadComplete = true;
                        self._loadInProgress = false;
                        errorCallback(e, args);
                    }
                });
            }
        }else{
            errorCallback(new Error("DWR Method is undefined."), args);
        }
    }
},



Listing 8: Changes to implement data filtering

_containsValue: function(item,attribute,value){
    var itemValue = this.getValue(item, attribute);
    if (itemValue.indexOf(value.substr(0, value.length-1))  >= 0 ) {
        return true;
    }
    return false;
},

        
_testMatch: function(args, item) {
    var self = this;
    var match = true;
    if(item === null){
        match = false;
    }else{
        for(var key in args.query) {
            var value = args.query[key];
            if (!self._containsValue(item, key, value)){
                match = false;
            }
        }
    }
    return match;
},

_fetchItems: function(args,findCallback,errorCallback){
    ...
    ...
    // Function to apply filter to data set
    var filter = function(args, items){
        var filteredItems = [];
        for(var i = 0; i < items.length; ++i){
            var candidateItem = items[i];
            if(self._testMatch(args, candidateItem)){
                filteredItems.push(candidateItem);
            }
        }
        findCallback(filteredItems, args);
    };
},



Listing 9: Implementation of getValue function

    getValue: function(item, attribute, defaultValue){
        return item[attribute];
    },



Listing 10: Usage of DWRReadStore

<html>
<head>
<!-- Include DWR files -->
<script type='text/JavaScript' src="/dwr/interface/CountryDAO.js"></script>
<script type='text/JavaScript' src="/dwr/engine.js"></script>
<script type='text/JavaScript' src="/dwr/util.js"></script>

<!-- Include Dojo files -->
<script type="text/JavaScript" src="/JavaScript/dojo/dojo.js" djConfig="parseOnLoad:true"></script>
<script type="text/JavaScript" src="/JavaScript/dijit/dijit.js"> </script>
<script type="text/JavaScript" src="/JavaScript/DWRReadStore.js"> </script>

<script>
dojo.require("dojo.parser");
dojo.require("dijit.form.ComboBox");
dojo.require("DWRReadStore");

dojo.addOnLoad(init);
function init()
{
    var dwrStore = new DWRReadStore({dwrMethod: CountryDAO.getCountries});
    dijit.byId("txtCountry").store = dwrStore;
}
</script>
</head>

<body>
    <input type="text" type="text" id="txtCountry"
        dojoType="dijit.form.ComboBox" searchAttr="countryName"
        autocomplete="false"
        hasDownArrow="false"/>

</body>
</html>