Subversion Repositories Applications.papyrus

Rev

Blame | Last modification | View Log | RSS feed

if(!dojo._hasResource["dojo.data.ItemFileReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.data.ItemFileReadStore"] = true;
dojo.provide("dojo.data.ItemFileReadStore");

dojo.require("dojo.data.util.filter");
dojo.require("dojo.data.util.simpleFetch");
dojo.require("dojo.date.stamp");

dojo.declare("dojo.data.ItemFileReadStore", null,{
        //      summary:
        //              The ItemFileReadStore implements the dojo.data.api.Read API and reads
        //              data from JSON files that have contents in this format --
        //              { items: [
        //                      { name:'Kermit', color:'green', age:12, friends:['Gonzo', {_reference:{name:'Fozzie Bear'}}]},
        //                      { name:'Fozzie Bear', wears:['hat', 'tie']},
        //                      { name:'Miss Piggy', pets:'Foo-Foo'}
        //              ]}
        //              Note that it can also contain an 'identifer' property that specified which attribute on the items 
        //              in the array of items that acts as the unique identifier for that item.
        //
        constructor: function(/* Object */ keywordParameters){
                //      summary: constructor
                //      keywordParameters: {url: String}
                //      keywordParameters: {data: jsonObject}
                //      keywordParameters: {typeMap: object)
                //              The structure of the typeMap object is as follows:
                //              {
                //                      type0: function || object,
                //                      type1: function || object,
                //                      ...
                //                      typeN: function || object
                //              }
                //              Where if it is a function, it is assumed to be an object constructor that takes the 
                //              value of _value as the initialization parameters.  If it is an object, then it is assumed
                //              to be an object of general form:
                //              {
                //                      type: function, //constructor.
                //                      deserialize:    function(value) //The function that parses the value and constructs the object defined by type appropriately.
                //              }
        
                this._arrayOfAllItems = [];
                this._arrayOfTopLevelItems = [];
                this._loadFinished = false;
                this._jsonFileUrl = keywordParameters.url;
                this._jsonData = keywordParameters.data;
                this._datatypeMap = keywordParameters.typeMap || {};
                if(!this._datatypeMap['Date']){
                        //If no default mapping for dates, then set this as default.
                        //We use the dojo.date.stamp here because the ISO format is the 'dojo way'
                        //of generically representing dates.
                        this._datatypeMap['Date'] = {
                                                                                        type: Date,
                                                                                        deserialize: function(value){
                                                                                                return dojo.date.stamp.fromISOString(value);
                                                                                        }
                                                                                };
                }
                this._features = {'dojo.data.api.Read':true, 'dojo.data.api.Identity':true};
                this._itemsByIdentity = null;
                this._storeRefPropName = "_S";  // Default name for the store reference to attach to every item.
                this._itemNumPropName = "_0"; // Default Item Id for isItem to attach to every item.
                this._rootItemPropName = "_RI"; // Default Item Id for isItem to attach to every item.
                this._loadInProgress = false;   //Got to track the initial load to prevent duelling loads of the dataset.
                this._queuedFetches = [];
        },
        
        url: "",        // use "" rather than undefined for the benefit of the parser (#3539)

        _assertIsItem: function(/* item */ item){
                //      summary:
                //              This function tests whether the item passed in is indeed an item in the store.
                //      item: 
                //              The item to test for being contained by the store.
                if(!this.isItem(item)){ 
                        throw new Error("dojo.data.ItemFileReadStore: Invalid item argument.");
                }
        },

        _assertIsAttribute: function(/* attribute-name-string */ attribute){
                //      summary:
                //              This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
                //      attribute: 
                //              The attribute to test for being contained by the store.
                if(typeof attribute !== "string"){ 
                        throw new Error("dojo.data.ItemFileReadStore: Invalid attribute argument.");
                }
        },

        getValue: function(     /* item */ item, 
                                                /* attribute-name-string */ attribute, 
                                                /* value? */ defaultValue){
                //      summary: 
                //              See dojo.data.api.Read.getValue()
                var values = this.getValues(item, attribute);
                return (values.length > 0)?values[0]:defaultValue; // mixed
        },

        getValues: function(/* item */ item, 
                                                /* attribute-name-string */ attribute){
                //      summary: 
                //              See dojo.data.api.Read.getValues()

                this._assertIsItem(item);
                this._assertIsAttribute(attribute);
                return item[attribute] || []; // Array
        },

        getAttributes: function(/* item */ item){
                //      summary: 
                //              See dojo.data.api.Read.getAttributes()
                this._assertIsItem(item);
                var attributes = [];
                for(var key in item){
                        // Save off only the real item attributes, not the special id marks for O(1) isItem.
                        if((key !== this._storeRefPropName) && (key !== this._itemNumPropName) && (key !== this._rootItemPropName)){
                                attributes.push(key);
                        }
                }
                return attributes; // Array
        },

        hasAttribute: function( /* item */ item,
                                                        /* attribute-name-string */ attribute) {
                //      summary: 
                //              See dojo.data.api.Read.hasAttribute()
                return this.getValues(item, attribute).length > 0;
        },

        containsValue: function(/* item */ item, 
                                                        /* attribute-name-string */ attribute, 
                                                        /* anything */ value){
                //      summary: 
                //              See dojo.data.api.Read.containsValue()
                var regexp = undefined;
                if(typeof value === "string"){
                        regexp = dojo.data.util.filter.patternToRegExp(value, false);
                }
                return this._containsValue(item, attribute, value, regexp); //boolean.
        },

        _containsValue: function(       /* item */ item, 
                                                                /* attribute-name-string */ attribute, 
                                                                /* anything */ value,
                                                                /* RegExp?*/ regexp){
                //      summary: 
                //              Internal function for looking at the values contained by the item.
                //      description: 
                //              Internal function for looking at the values contained by the item.  This 
                //              function allows for denoting if the comparison should be case sensitive for
                //              strings or not (for handling filtering cases where string case should not matter)
                //      
                //      item:
                //              The data item to examine for attribute values.
                //      attribute:
                //              The attribute to inspect.
                //      value:  
                //              The value to match.
                //      regexp:
                //              Optional regular expression generated off value if value was of string type to handle wildcarding.
                //              If present and attribute values are string, then it can be used for comparison instead of 'value'
                return dojo.some(this.getValues(item, attribute), function(possibleValue){
                        if(possibleValue !== null && !dojo.isObject(possibleValue) && regexp){
                                if(possibleValue.toString().match(regexp)){
                                        return true; // Boolean
                                }
                        }else if(value === possibleValue){
                                return true; // Boolean
                        }
                });
        },

        isItem: function(/* anything */ something){
                //      summary: 
                //              See dojo.data.api.Read.isItem()
                if(something && something[this._storeRefPropName] === this){
                        if(this._arrayOfAllItems[something[this._itemNumPropName]] === something){
                                return true;
                        }
                }
                return false; // Boolean
        },

        isItemLoaded: function(/* anything */ something){
                //      summary: 
                //              See dojo.data.api.Read.isItemLoaded()
                return this.isItem(something); //boolean
        },

        loadItem: function(/* object */ keywordArgs){
                //      summary: 
                //              See dojo.data.api.Read.loadItem()
                this._assertIsItem(keywordArgs.item);
        },

        getFeatures: function(){
                //      summary: 
                //              See dojo.data.api.Read.getFeatures()
                return this._features; //Object
        },

        getLabel: function(/* item */ item){
                //      summary: 
                //              See dojo.data.api.Read.getLabel()
                if(this._labelAttr && this.isItem(item)){
                        return this.getValue(item,this._labelAttr); //String
                }
                return undefined; //undefined
        },

        getLabelAttributes: function(/* item */ item){
                //      summary: 
                //              See dojo.data.api.Read.getLabelAttributes()
                if(this._labelAttr){
                        return [this._labelAttr]; //array
                }
                return null; //null
        },

        _fetchItems: function(  /* Object */ keywordArgs, 
                                                        /* Function */ findCallback, 
                                                        /* Function */ errorCallback){
                //      summary: 
                //              See dojo.data.util.simpleFetch.fetch()
                var self = this;
                var filter = function(requestArgs, arrayOfItems){
                        var items = [];
                        if(requestArgs.query){
                                var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false; 

                                //See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
                                //same value for each item examined.  Much more efficient.
                                var regexpList = {};
                                for(var key in requestArgs.query){
                                        var value = requestArgs.query[key];
                                        if(typeof value === "string"){
                                                regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
                                        }
                                }

                                for(var i = 0; i < arrayOfItems.length; ++i){
                                        var match = true;
                                        var candidateItem = arrayOfItems[i];
                                        if(candidateItem === null){
                                                match = false;
                                        }else{
                                                for(var key in requestArgs.query) {
                                                        var value = requestArgs.query[key];
                                                        if (!self._containsValue(candidateItem, key, value, regexpList[key])){
                                                                match = false;
                                                        }
                                                }
                                        }
                                        if(match){
                                                items.push(candidateItem);
                                        }
                                }
                                findCallback(items, requestArgs);
                        }else{
                                // We want a copy to pass back in case the parent wishes to sort the array. 
                                // We shouldn't allow resort of the internal list, so that multiple callers 
                                // can get lists and sort without affecting each other.  We also need to
                                // filter out any null values that have been left as a result of deleteItem()
                                // calls in ItemFileWriteStore.
                                for(var i = 0; i < arrayOfItems.length; ++i){
                                        var item = arrayOfItems[i];
                                        if(item !== null){
                                                items.push(item);
                                        }
                                }
                                findCallback(items, requestArgs);
                        }
                };

                if(this._loadFinished){
                        filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
                }else{

                        if(this._jsonFileUrl){
                                //If fetches come in before the loading has finished, but while
                                //a load is in progress, we have to defer the fetching to be 
                                //invoked in the callback.
                                if(this._loadInProgress){
                                        this._queuedFetches.push({args: keywordArgs, filter: filter});
                                }else{
                                        this._loadInProgress = true;
                                        var getArgs = {
                                                        url: self._jsonFileUrl, 
                                                        handleAs: "json-comment-optional"
                                                };
                                        var getHandler = dojo.xhrGet(getArgs);
                                        getHandler.addCallback(function(data){
                                                try{
                                                        self._getItemsFromLoadedData(data);
                                                        self._loadFinished = true;
                                                        self._loadInProgress = false;
                                                        
                                                        filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions));
                                                        self._handleQueuedFetches();
                                                }catch(e){
                                                        self._loadFinished = true;
                                                        self._loadInProgress = false;
                                                        errorCallback(e, keywordArgs);
                                                }
                                        });
                                        getHandler.addErrback(function(error){
                                                self._loadInProgress = false;
                                                errorCallback(error, keywordArgs);
                                        });
                                }
                        }else if(this._jsonData){
                                try{
                                        this._loadFinished = true;
                                        this._getItemsFromLoadedData(this._jsonData);
                                        this._jsonData = null;
                                        filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
                                }catch(e){
                                        errorCallback(e, keywordArgs);
                                }
                        }else{
                                errorCallback(new Error("dojo.data.ItemFileReadStore: No JSON source data was provided as either URL or a nested Javascript object."), keywordArgs);
                        }
                }
        },

        _handleQueuedFetches: function(){
                //      summary: 
                //              Internal function to execute delayed request in the store.
                //Execute any deferred fetches now.
                if (this._queuedFetches.length > 0) {
                        for(var i = 0; i < this._queuedFetches.length; i++){
                                var fData = this._queuedFetches[i];
                                var delayedQuery = fData.args;
                                var delayedFilter = fData.filter;
                                if(delayedFilter){
                                        delayedFilter(delayedQuery, this._getItemsArray(delayedQuery.queryOptions)); 
                                }else{
                                        this.fetchItemByIdentity(delayedQuery);
                                }
                        }
                        this._queuedFetches = [];
                }
        },

        _getItemsArray: function(/*object?*/queryOptions){
                //      summary: 
                //              Internal function to determine which list of items to search over.
                //      queryOptions: The query options parameter, if any.
                if(queryOptions && queryOptions.deep) {
                        return this._arrayOfAllItems; 
                }
                return this._arrayOfTopLevelItems;
        },

        close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
                 //     summary: 
                 //             See dojo.data.api.Read.close()
        },

        _getItemsFromLoadedData: function(/* Object */ dataObject){
                //      summary:
                //              Function to parse the loaded data into item format and build the internal items array.
                //      description:
                //              Function to parse the loaded data into item format and build the internal items array.
                //
                //      dataObject:
                //              The JS data object containing the raw data to convery into item format.
                //
                //      returns: array
                //              Array of items in store item format.
                
                // First, we define a couple little utility functions...
                
                function valueIsAnItem(/* anything */ aValue){
                        // summary:
                        //              Given any sort of value that could be in the raw json data,
                        //              return true if we should interpret the value as being an
                        //              item itself, rather than a literal value or a reference.
                        // example:
                        //      |       false == valueIsAnItem("Kermit");
                        //      |       false == valueIsAnItem(42);
                        //      |       false == valueIsAnItem(new Date());
                        //      |       false == valueIsAnItem({_type:'Date', _value:'May 14, 1802'});
                        //      |       false == valueIsAnItem({_reference:'Kermit'});
                        //      |       true == valueIsAnItem({name:'Kermit', color:'green'});
                        //      |       true == valueIsAnItem({iggy:'pop'});
                        //      |       true == valueIsAnItem({foo:42});
                        var isItem = (
                                (aValue != null) &&
                                (typeof aValue == "object") &&
                                (!dojo.isArray(aValue)) &&
                                (!dojo.isFunction(aValue)) &&
                                (aValue.constructor == Object) &&
                                (typeof aValue._reference == "undefined") && 
                                (typeof aValue._type == "undefined") && 
                                (typeof aValue._value == "undefined")
                        );
                        return isItem;
                }
                
                var self = this;
                function addItemAndSubItemsToArrayOfAllItems(/* Item */ anItem){
                        self._arrayOfAllItems.push(anItem);
                        for(var attribute in anItem){
                                var valueForAttribute = anItem[attribute];
                                if(valueForAttribute){
                                        if(dojo.isArray(valueForAttribute)){
                                                var valueArray = valueForAttribute;
                                                for(var k = 0; k < valueArray.length; ++k){
                                                        var singleValue = valueArray[k];
                                                        if(valueIsAnItem(singleValue)){
                                                                addItemAndSubItemsToArrayOfAllItems(singleValue);
                                                        }
                                                }
                                        }else{
                                                if(valueIsAnItem(valueForAttribute)){
                                                        addItemAndSubItemsToArrayOfAllItems(valueForAttribute);
                                                }
                                        }
                                }
                        }
                }

                this._labelAttr = dataObject.label;

                // We need to do some transformations to convert the data structure
                // that we read from the file into a format that will be convenient
                // to work with in memory.

                // Step 1: Walk through the object hierarchy and build a list of all items
                var i;
                var item;
                this._arrayOfAllItems = [];
                this._arrayOfTopLevelItems = dataObject.items;

                for(i = 0; i < this._arrayOfTopLevelItems.length; ++i){
                        item = this._arrayOfTopLevelItems[i];
                        addItemAndSubItemsToArrayOfAllItems(item);
                        item[this._rootItemPropName]=true;
                }

                // Step 2: Walk through all the attribute values of all the items, 
                // and replace single values with arrays.  For example, we change this:
                //              { name:'Miss Piggy', pets:'Foo-Foo'}
                // into this:
                //              { name:['Miss Piggy'], pets:['Foo-Foo']}
                // 
                // We also store the attribute names so we can validate our store  
                // reference and item id special properties for the O(1) isItem
                var allAttributeNames = {};
                var key;

                for(i = 0; i < this._arrayOfAllItems.length; ++i){
                        item = this._arrayOfAllItems[i];
                        for(key in item){
                                if (key !== this._rootItemPropName)
                                {
                                        var value = item[key];
                                        if(value !== null){
                                                if(!dojo.isArray(value)){
                                                        item[key] = [value];
                                                }
                                        }else{
                                                item[key] = [null];
                                        }
                                }
                                allAttributeNames[key]=key;
                        }
                }

                // Step 3: Build unique property names to use for the _storeRefPropName and _itemNumPropName
                // This should go really fast, it will generally never even run the loop.
                while(allAttributeNames[this._storeRefPropName]){
                        this._storeRefPropName += "_";
                }
                while(allAttributeNames[this._itemNumPropName]){
                        this._itemNumPropName += "_";
                }

                // Step 4: Some data files specify an optional 'identifier', which is 
                // the name of an attribute that holds the identity of each item. 
                // If this data file specified an identifier attribute, then build a 
                // hash table of items keyed by the identity of the items.
                var arrayOfValues;

                var identifier = dataObject.identifier;
                if(identifier){
                        this._itemsByIdentity = {};
                        this._features['dojo.data.api.Identity'] = identifier;
                        for(i = 0; i < this._arrayOfAllItems.length; ++i){
                                item = this._arrayOfAllItems[i];
                                arrayOfValues = item[identifier];
                                var identity = arrayOfValues[0];
                                if(!this._itemsByIdentity[identity]){
                                        this._itemsByIdentity[identity] = item;
                                }else{
                                        if(this._jsonFileUrl){
                                                throw new Error("dojo.data.ItemFileReadStore:  The json data as specified by: [" + this._jsonFileUrl + "] is malformed.  Items within the list have identifier: [" + identifier + "].  Value collided: [" + identity + "]");
                                        }else if(this._jsonData){
                                                throw new Error("dojo.data.ItemFileReadStore:  The json data provided by the creation arguments is malformed.  Items within the list have identifier: [" + identifier + "].  Value collided: [" + identity + "]");
                                        }
                                }
                        }
                }else{
                        this._features['dojo.data.api.Identity'] = Number;
                }

                // Step 5: Walk through all the items, and set each item's properties 
                // for _storeRefPropName and _itemNumPropName, so that store.isItem() will return true.
                for(i = 0; i < this._arrayOfAllItems.length; ++i){
                        item = this._arrayOfAllItems[i];
                        item[this._storeRefPropName] = this;
                        item[this._itemNumPropName] = i;
                }

                // Step 6: We walk through all the attribute values of all the items,
                // looking for type/value literals and item-references.
                //
                // We replace item-references with pointers to items.  For example, we change:
                //              { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
                // into this:
                //              { name:['Kermit'], friends:[miss_piggy] } 
                // (where miss_piggy is the object representing the 'Miss Piggy' item).
                //
                // We replace type/value pairs with typed-literals.  For example, we change:
                //              { name:['Nelson Mandela'], born:[{_type:'Date', _value:'July 18, 1918'}] }
                // into this:
                //              { name:['Kermit'], born:(new Date('July 18, 1918')) } 
                //
                // We also generate the associate map for all items for the O(1) isItem function.
                for(i = 0; i < this._arrayOfAllItems.length; ++i){
                        item = this._arrayOfAllItems[i]; // example: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
                        for(key in item){
                                arrayOfValues = item[key]; // example: [{_reference:{name:'Miss Piggy'}}]
                                for(var j = 0; j < arrayOfValues.length; ++j) {
                                        value = arrayOfValues[j]; // example: {_reference:{name:'Miss Piggy'}}
                                        if(value !== null && typeof value == "object"){
                                                if(value._type && value._value){
                                                        var type = value._type; // examples: 'Date', 'Color', or 'ComplexNumber'
                                                        var mappingObj = this._datatypeMap[type]; // examples: Date, dojo.Color, foo.math.ComplexNumber, {type: dojo.Color, deserialize(value){ return new dojo.Color(value)}}
                                                        if(!mappingObj){ 
                                                                throw new Error("dojo.data.ItemFileReadStore: in the typeMap constructor arg, no object class was specified for the datatype '" + type + "'");
                                                        }else if(dojo.isFunction(mappingObj)){
                                                                arrayOfValues[j] = new mappingObj(value._value);
                                                        }else if(dojo.isFunction(mappingObj.deserialize)){
                                                                arrayOfValues[j] = mappingObj.deserialize(value._value);
                                                        }else{
                                                                throw new Error("dojo.data.ItemFileReadStore: Value provided in typeMap was neither a constructor, nor a an object with a deserialize function");
                                                        }
                                                }
                                                if(value._reference){
                                                        var referenceDescription = value._reference; // example: {name:'Miss Piggy'}
                                                        if(dojo.isString(referenceDescription)){
                                                                // example: 'Miss Piggy'
                                                                // from an item like: { name:['Kermit'], friends:[{_reference:'Miss Piggy'}]}
                                                                arrayOfValues[j] = this._itemsByIdentity[referenceDescription];
                                                        }else{
                                                                // example: {name:'Miss Piggy'}
                                                                // from an item like: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
                                                                for(var k = 0; k < this._arrayOfAllItems.length; ++k){
                                                                        var candidateItem = this._arrayOfAllItems[k];
                                                                        var found = true;
                                                                        for(var refKey in referenceDescription){
                                                                                if(candidateItem[refKey] != referenceDescription[refKey]){ 
                                                                                        found = false; 
                                                                                }
                                                                        }
                                                                        if(found){ 
                                                                                arrayOfValues[j] = candidateItem; 
                                                                        }
                                                                }
                                                        }
                                                }
                                        }
                                }
                        }
                }
        },

        getIdentity: function(/* item */ item){
                //      summary: 
                //              See dojo.data.api.Identity.getIdentity()
                var identifier = this._features['dojo.data.api.Identity'];
                if(identifier === Number){
                        return item[this._itemNumPropName]; // Number
                }else{
                        var arrayOfValues = item[identifier];
                        if(arrayOfValues){
                                return arrayOfValues[0]; // Object || String
                        }
                }
                return null; // null
        },

        fetchItemByIdentity: function(/* Object */ keywordArgs){
                //      summary: 
                //              See dojo.data.api.Identity.fetchItemByIdentity()

                // Hasn't loaded yet, we have to trigger the load.
                if(!this._loadFinished){
                        var self = this;
                        if(this._jsonFileUrl){

                                if(this._loadInProgress){
                                        this._queuedFetches.push({args: keywordArgs});
                                }else{
                                        this._loadInProgress = true;
                                        var getArgs = {
                                                        url: self._jsonFileUrl, 
                                                        handleAs: "json-comment-optional"
                                        };
                                        var getHandler = dojo.xhrGet(getArgs);
                                        getHandler.addCallback(function(data){
                                                var scope =  keywordArgs.scope?keywordArgs.scope:dojo.global;
                                                try{
                                                        self._getItemsFromLoadedData(data);
                                                        self._loadFinished = true;
                                                        self._loadInProgress = false;
                                                        var item = self._getItemByIdentity(keywordArgs.identity);
                                                        if(keywordArgs.onItem){
                                                                keywordArgs.onItem.call(scope, item);
                                                        }
                                                        self._handleQueuedFetches();
                                                }catch(error){
                                                        self._loadInProgress = false;
                                                        if(keywordArgs.onError){
                                                                keywordArgs.onError.call(scope, error);
                                                        }
                                                }
                                        });
                                        getHandler.addErrback(function(error){
                                                self._loadInProgress = false;
                                                if(keywordArgs.onError){
                                                        var scope =  keywordArgs.scope?keywordArgs.scope:dojo.global;
                                                        keywordArgs.onError.call(scope, error);
                                                }
                                        });
                                }

                        }else if(this._jsonData){
                                // Passed in data, no need to xhr.
                                self._getItemsFromLoadedData(self._jsonData);
                                self._jsonData = null;
                                self._loadFinished = true;
                                var item = self._getItemByIdentity(keywordArgs.identity);
                                if(keywordArgs.onItem){
                                        var scope =  keywordArgs.scope?keywordArgs.scope:dojo.global;
                                        keywordArgs.onItem.call(scope, item);
                                }
                        } 
                }else{
                        // Already loaded.  We can just look it up and call back.
                        var item = this._getItemByIdentity(keywordArgs.identity);
                        if(keywordArgs.onItem){
                                var scope =  keywordArgs.scope?keywordArgs.scope:dojo.global;
                                keywordArgs.onItem.call(scope, item);
                        }
                }
        },

        _getItemByIdentity: function(/* Object */ identity){
                //      summary:
                //              Internal function to look an item up by its identity map.
                var item = null;
                if(this._itemsByIdentity){
                        item = this._itemsByIdentity[identity];
                }else{
                        item = this._arrayOfAllItems[identity];
                }
                if(item === undefined){
                        item = null;
                }
                return item; // Object
        },

        getIdentityAttributes: function(/* item */ item){
                //      summary: 
                //              See dojo.data.api.Identity.getIdentifierAttributes()
                 
                var identifier = this._features['dojo.data.api.Identity'];
                if(identifier === Number){
                        // If (identifier === Number) it means getIdentity() just returns
                        // an integer item-number for each item.  The dojo.data.api.Identity
                        // spec says we need to return null if the identity is not composed 
                        // of attributes 
                        return null; // null
                }else{
                        return [identifier]; // Array
                }
        },
        
        _forceLoad: function(){
                //      summary: 
                //              Internal function to force a load of the store if it hasn't occurred yet.  This is required
                //              for specific functions to work properly.  
                var self = this;
                if(this._jsonFileUrl){
                                var getArgs = {
                                        url: self._jsonFileUrl, 
                                        handleAs: "json-comment-optional",
                                        sync: true
                                };
                        var getHandler = dojo.xhrGet(getArgs);
                        getHandler.addCallback(function(data){
                                try{
                                        //Check to be sure there wasn't another load going on concurrently 
                                        //So we don't clobber data that comes in on it.  If there is a load going on
                                        //then do not save this data.  It will potentially clobber current data.
                                        //We mainly wanted to sync/wait here.
                                        //TODO:  Revisit the loading scheme of this store to improve multi-initial
                                        //request handling.
                                        if (self._loadInProgress !== true && !self._loadFinished) {
                                                self._getItemsFromLoadedData(data);
                                                self._loadFinished = true;
                                        }
                                }catch(e){
                                        console.log(e);
                                        throw e;
                                }
                        });
                        getHandler.addErrback(function(error){
                                throw error;
                        });
                }else if(this._jsonData){
                        self._getItemsFromLoadedData(self._jsonData);
                        self._jsonData = null;
                        self._loadFinished = true;
                } 
        }
});
//Mix in the simple fetch implementation to this class.
dojo.extend(dojo.data.ItemFileReadStore,dojo.data.util.simpleFetch);

}