incubator-xap-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mtu...@apache.org
Subject svn commit: r518313 [8/43] - in /incubator/xap/trunk/codebase/src/dojo: ./ src/ src/animation/ src/cal/ src/charting/ src/charting/svg/ src/charting/vml/ src/collections/ src/crypto/ src/data/ src/data/core/ src/data/old/ src/data/old/format/ src/data/...
Date Wed, 14 Mar 2007 20:37:27 GMT
Added: incubator/xap/trunk/codebase/src/dojo/src/data/CsvStore.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/CsvStore.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/CsvStore.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/CsvStore.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,207 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.CsvStore");
+dojo.require("dojo.data.core.RemoteStore");
+dojo.require("dojo.lang.assert");
+
+dojo.declare("dojo.data.CsvStore", dojo.data.core.RemoteStore, {
+	/* summary:
+	 *   The CsvStore subclasses dojo.data.core.RemoteStore to implement
+	 *   the dojo.data.core.Read API.  
+	 */
+	
+	/* examples:
+	 *   var csvStore = new dojo.data.CsvStore({queryUrl:"movies.csv");
+	 *   var csvStore = new dojo.data.CsvStore({url:"http://example.com/movies.csv");
+	 */
+	_setupQueryRequest: function(/* dojo.data.core.Result */ result, /* object */ requestKw) { 
+		// summary: See dojo.data.core.RemoteStore._setupQueryRequest()
+		var serverQueryUrl = this._serverQueryUrl ? this._serverQueryUrl : "";
+		var queryUrl = result.query ? result.query : "";
+		requestKw.url = serverQueryUrl + queryUrl;
+		requestKw.method = 'get';
+	},
+	
+	_resultToQueryData: function(/* varies */ serverResponseData) {
+		// summary: See dojo.data.core.RemoteStore._resultToQueryData()
+		var csvFileContentString = serverResponseData;
+		var arrayOfArrays = this._getArrayOfArraysFromCsvFileContents(csvFileContentString);
+		var arrayOfObjects = this._getArrayOfObjectsFromArrayOfArrays(arrayOfArrays);
+        var remoteStoreData = this._getRemoteStoreDataFromArrayOfObjects(arrayOfObjects);
+		return remoteStoreData;
+	},
+	
+	_setupSaveRequest: function(/* object */ saveKeywordArgs, /* object */ requestKw) {
+		// summary: See dojo.data.core.RemoteStore._setupSaveRequest()
+		// description: NOT IMPLEMENTED -- CsvStore is a read-only store
+	},
+	
+	// -------------------------------------------------------------------
+	// Private methods
+	_getArrayOfArraysFromCsvFileContents: function(/* string */ csvFileContents) {
+		/* summary:
+		 *   Parses a string of CSV records into a nested array structure.
+		 * description:
+		 *   Given a string containing CSV records, this method parses
+		 *   the string and returns a data structure containing the parsed
+		 *   content.  The data structure we return is an array of length
+		 *   R, where R is the number of rows (lines) in the CSV data.  The 
+		 *   return array contains one sub-array for each CSV line, and each 
+		 *   sub-array contains C string values, where C is the number of 
+		 *   columns in the CSV data.
+		 */
+		 
+		/* example:
+		 *   For example, given this CSV string as input:
+		 *     "Title, Year, Producer \n Alien, 1979, Ridley Scott \n Blade Runner, 1982, Ridley Scott"
+		 *   We will return this data structure:
+		 *     [["Title", "Year", "Producer"]
+		 *      ["Alien", "1979", "Ridley Scott"],  
+		 *      ["Blade Runner", "1982", "Ridley Scott"]]
+		 */
+		dojo.lang.assertType(csvFileContents, String);
+		
+		var lineEndingCharacters = new RegExp("\r\n|\n|\r");
+		var leadingWhiteSpaceCharacters = new RegExp("^\\s+",'g');
+		var trailingWhiteSpaceCharacters = new RegExp("\\s+$",'g');
+		var doubleQuotes = new RegExp('""','g');
+		var arrayOfOutputRecords = [];
+		
+		var arrayOfInputLines = csvFileContents.split(lineEndingCharacters);
+		for (var i in arrayOfInputLines) {
+			var singleLine = arrayOfInputLines[i];
+			if (singleLine.length > 0) {
+				var listOfFields = singleLine.split(',');
+				var j = 0;
+				while (j < listOfFields.length) {
+					var space_field_space = listOfFields[j];
+					var field_space = space_field_space.replace(leadingWhiteSpaceCharacters, ''); // trim leading whitespace
+					var field = field_space.replace(trailingWhiteSpaceCharacters, ''); // trim trailing whitespace
+					var firstChar = field.charAt(0);
+					var lastChar = field.charAt(field.length - 1);
+					var secondToLastChar = field.charAt(field.length - 2);
+					var thirdToLastChar = field.charAt(field.length - 3);
+					if ((firstChar == '"') && 
+							((lastChar != '"') || 
+							 ((lastChar == '"') && (secondToLastChar == '"') && (thirdToLastChar != '"')) )) {
+						if (j+1 === listOfFields.length) {
+							// alert("The last field in record " + i + " is corrupted:\n" + field);
+							return null;
+						}
+						var nextField = listOfFields[j+1];
+						listOfFields[j] = field_space + ',' + nextField;
+						listOfFields.splice(j+1, 1); // delete element [j+1] from the list
+					} else {
+						if ((firstChar == '"') && (lastChar == '"')) {
+							field = field.slice(1, (field.length - 1)); // trim the " characters off the ends
+							field = field.replace(doubleQuotes, '"');   // replace "" with "
+						}
+						listOfFields[j] = field;
+						j += 1;
+					}
+				}
+				arrayOfOutputRecords.push(listOfFields);
+			}
+		}
+		return arrayOfOutputRecords; // Array
+	},
+
+	_getArrayOfObjectsFromArrayOfArrays: function(/* array[] */ arrayOfArrays) {
+		/* summary:
+		 *   Converts a nested array structure into an array of keyword objects.
+		 */
+		 
+		/* example:
+		 *   For example, given this as input:
+		 *     [["Title", "Year", "Producer"]
+		 *      ["Alien", "1979", "Ridley Scott"],  
+		 *      ["Blade Runner", "1982", "Ridley Scott"]]
+		 *   We will return this as output:
+		 *     [{"Title":"Alien", "Year":"1979", "Producer":"Ridley Scott"},
+		 *      {"Title":"Blade Runner", "Year":"1982", "Producer":"Ridley Scott"}]
+		 */
+		dojo.lang.assertType(arrayOfArrays, Array);
+		var arrayOfItems = [];
+		if (arrayOfArrays.length > 1) {
+			var arrayOfKeys = arrayOfArrays[0];
+			for (var i = 1; i < arrayOfArrays.length; ++i) {
+				var row = arrayOfArrays[i];
+				var item = {};
+				for (var j in row) {
+					var value = row[j];
+					var key = arrayOfKeys[j];
+					item[key] = value;
+				}
+				arrayOfItems.push(item);
+			}
+		}
+		return arrayOfItems; // Array
+	},
+	
+	_getRemoteStoreDataFromArrayOfObjects: function(/* object[] */ arrayOfObjects) {
+		/* summary:
+		 *   Converts an array of keyword objects in the internal record data 
+		 *    structure used by RemoteStore.
+		 */
+
+		/* example:
+		 *   For example, given this as input:
+		 *     [{"Title":"Alien", "Year":"1979", "Producer":"Ridley Scott"},
+		 *      {"Title":"Blade Runner", "Year":"1982", "Producer":"Ridley Scott"}]
+		 *   We will return this as output:
+		 *     { "1": {"Title":["Alien"], "Year":["1979"], "Producer":["Ridley Scott"]},
+		 *       "2": {"Title":["Blade Runner"], "Year":["1982"], "Producer":["Ridley Scott"]}
+		 *     }
+		 */
+		dojo.lang.assertType(arrayOfObjects, Array);
+		var output = {};
+		for (var i = 0; i < arrayOfObjects.length; ++i) {
+			var object = arrayOfObjects[i];
+			for (var key in object) {
+				var value = object[key]; // {"Title":"Alien"} --> "Alien"
+				object[key] = [value];   // {"Title":["Alien"]}
+			}
+			output[i] = object;
+		}
+		return output; // Object
+	},
+
+	// CsvStore implements the dojo.data.core.Read API, but does not yet  
+	// implements the dojo.data.core.Write API.  CsvStore extends RemoteStore,
+	// and RemoteStore does implement the Write API, so we need to explicitly
+	// mark those Write API methods as being unimplemented.
+	newItem: function(/* object? */ attributes, /* object? */ keywordArgs) {
+		dojo.unimplemented('dojo.data.CsvStore.newItem');
+	},
+	deleteItem: function(/* item */ item) {
+		dojo.unimplemented('dojo.data.CsvStore.deleteItem');
+	},
+	setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values) {
+		dojo.unimplemented('dojo.data.CsvStore.setValues');
+	},
+	set: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value) {
+		dojo.unimplemented('dojo.data.CsvStore.set');
+	},
+	unsetAttribute: function(/* item */ item, /* attribute || string */ attribute) {
+		dojo.unimplemented('dojo.data.CsvStore.unsetAttribute');
+	},
+	save: function(/* object? */ keywordArgs) {
+		dojo.unimplemented('dojo.data.CsvStore.save');
+	},
+	revert: function() {
+		dojo.unimplemented('dojo.data.CsvStore.revert');
+	},
+	isDirty: function(/*item?*/ item) {
+		dojo.unimplemented('dojo.data.CsvStore.isDirty');
+	}
+
+});
+

Added: incubator/xap/trunk/codebase/src/dojo/src/data/OpmlStore.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/OpmlStore.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/OpmlStore.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/OpmlStore.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,224 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.OpmlStore");
+dojo.require("dojo.data.core.Read");
+dojo.require("dojo.data.core.Result");
+dojo.require("dojo.lang.assert");
+dojo.require("dojo.json");
+
+dojo.require("dojo.experimental");
+dojo.experimental("dojo.data.OpmlStore");
+// FIXME: The OpmlStore works in Firefox but does not yet work in IE.
+
+dojo.declare("dojo.data.OpmlStore", dojo.data.core.Read, {
+	/* summary:
+	 *   The OpmlStore implements the dojo.data.core.Read API.  
+	 */
+	 
+	/* examples:
+	 *   var opmlStore = new dojo.data.OpmlStore({url:"geography.opml"});
+	 *   var opmlStore = new dojo.data.OpmlStore({url:"http://example.com/geography.opml"});
+	 */
+	initializer: function(/* object */ keywordParameters) {
+		// keywordParameters: {url: String}
+		this._arrayOfTopLevelItems = [];
+		this._metadataNodes = null;
+		this._loadFinished = false;
+		this._opmlFileUrl = keywordParameters["url"];
+	},
+	
+	_assertIsItem: function(/* item */ item) {
+		if (!this.isItem(item)) { 
+			throw new Error("dojo.data.OpmlStore: a function was passed an item argument that was not an item");
+		}
+	},
+	
+	_removeChildNodesThatAreNotElementNodes: function(/* node */ node, /* boolean */ recursive) {
+		var childNodes = node.childNodes;
+		if (childNodes.length == 0) {
+			return;
+		}
+		var nodesToRemove = [];
+		var i, childNode;
+		for (i = 0; i < childNodes.length; ++i) {
+			childNode = childNodes[i];
+			if (childNode.nodeType != Node.ELEMENT_NODE) { 
+				nodesToRemove.push(childNode); 
+			}
+		};
+		// dojo.debug('trim: ' + childNodes.length + ' total, ' + nodesToRemove.length + ' junk');
+		for (i = 0; i < nodesToRemove.length; ++i) {
+			childNode = nodesToRemove[i];
+			node.removeChild(childNode);
+		}
+		// dojo.debug('trim: ' + childNodes.length + ' remaining');
+		if (recursive) {
+			for (i = 0; i < childNodes.length; ++i) {
+				childNode = childNodes[i];
+				this._removeChildNodesThatAreNotElementNodes(childNode, recursive);
+			}
+		}
+	},
+	
+	_processRawXmlTree: function(/* xmlDoc */ rawXmlTree) {
+		var headNodes = rawXmlTree.getElementsByTagName('head');
+		var headNode = headNodes[0];
+		this._removeChildNodesThatAreNotElementNodes(headNode);
+		this._metadataNodes = headNode.childNodes;
+		var bodyNodes = rawXmlTree.getElementsByTagName('body');
+		var bodyNode = bodyNodes[0];
+		this._removeChildNodesThatAreNotElementNodes(bodyNode, true);
+		
+		var bodyChildNodes = bodyNodes[0].childNodes;
+		for (var i = 0; i < bodyChildNodes.length; ++i) {
+			var node = bodyChildNodes[i];
+			if (node.tagName == 'outline') {
+				this._arrayOfTopLevelItems.push(node);
+			}
+		}
+	},
+	
+	get: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue) {
+		// summary: See dojo.data.core.Read.get()
+		this._assertIsItem(item);
+		if (attribute == 'children') {
+			return (item.firstChild || defaultValue);
+		} else {
+			var value = item.getAttribute(attribute);
+			value = (value != undefined) ? value : defaultValue;
+			return value;
+		}
+	},
+		
+	getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute) {
+		// summary: See dojo.data.core.Read.getValues()
+		this._assertIsItem(item);
+		if (attribute == 'children') {
+			var array = [];
+			for (var i = 0; i < item.childNodes.length; ++i) {
+				array.push(item.childNodes[i]);
+			}
+			return array; // Array
+			// return item.childNodes; // FIXME: this isn't really an Array
+		} else {
+			return [item.getAttribute(attribute)]; // Array
+		}
+	},
+		
+	getAttributes: function(/* item */ item) {
+		// summary: See dojo.data.core.Read.getAttributes()
+		this._assertIsItem(item);
+		var attributes = [];
+		var xmlNode = item;
+		var xmlAttributes = xmlNode.attributes;
+		for (var i = 0; i < xmlAttributes.length; ++i) {
+			var xmlAttribute = xmlAttributes.item(i);
+			attributes.push(xmlAttribute.nodeName);
+		}
+		if (xmlNode.childNodes.length > 0) {
+			attributes.push('children');
+		}
+		return attributes; // array
+	},
+	
+	hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute) {
+		// summary: See dojo.data.core.Read.hasAttribute()
+		return (this.getValues(item, attribute).length > 0);
+	},
+	
+	containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value) {
+		// summary: See dojo.data.core.Read.containsValue()
+		var values = this.getValues(item, attribute);
+		for (var i = 0; i < values.length; ++i) {
+			var possibleValue = values[i];
+			if (value == possibleValue) {
+				return true;
+			}
+		}
+		return false; // boolean
+	},
+		
+	isItem: function(/* anything */ something) {
+		return (something && 
+				something.nodeType == Node.ELEMENT_NODE && 
+				something.tagName == 'outline'); // boolean
+	},
+	
+	isItemAvailable: function(/* anything */ something) {
+		return this.isItem(something);
+	},
+	
+	find: function(/* object? || dojo.data.core.Result */ keywordArgs) {
+		// summary: See dojo.data.core.Read.find()
+		var result = null;
+		if (keywordArgs instanceof dojo.data.core.Result) {
+			result = keywordArgs;
+			result.store = this;
+		} else {
+			result = new dojo.data.core.Result(keywordArgs, this);
+		}
+		var self = this;
+		var bindHandler = function(type, data, evt) {
+			var scope = result.scope || dj_global;
+			if (type == "load") {
+				self._processRawXmlTree(data);
+				if (result.saveResult) {
+					result.items = self._arrayOfTopLevelItems;
+				}
+				if (result.onbegin) {
+					result.onbegin.call(scope, result);
+				}
+				for (var i=0; i < self._arrayOfTopLevelItems.length; i++) {
+					var item = self._arrayOfTopLevelItems[i];
+					if (result.onnext && !result._aborted) {
+						result.onnext.call(scope, item, result);
+					}
+				}
+				if (result.oncompleted && !result._aborted) {
+					result.oncompleted.call(scope, result);
+				}
+			} else if(type == "error" || type == 'timeout') {
+				// todo: how to handle timeout?
+				var errorObject = data;
+				// dojo.debug("error in dojo.data.OpmlStore.find(): " + dojo.json.serialize(errorObject));
+				if (result.onerror) {
+					result.onerror.call(scope, data);
+				}
+			}
+		};
+		
+		if (!this._loadFinished) {
+			if (this._opmlFileUrl) {
+				var bindRequest = dojo.io.bind({
+					url: this._opmlFileUrl, // "playlist.opml",
+					handle: bindHandler,
+					mimetype: "text/xml",
+					sync: (result.sync || false) });
+				result._abortFunc = bindRequest.abort;
+			}
+		}
+		return result; // dojo.data.csv.Result
+	},
+	
+	getIdentity: function(/* item */ item) {
+		// summary: See dojo.data.core.Read.getIdentity()
+		dojo.unimplemented('dojo.data.OpmlStore.getIdentity()');
+		return null;
+	},
+	
+	findByIdentity: function(/* string */ identity) {
+		// summary: See dojo.data.core.Read.findByIdentity()
+		dojo.unimplemented('dojo.data.OpmlStore.findByIdentity()');
+		return null;
+	}
+});
+
+

Added: incubator/xap/trunk/codebase/src/dojo/src/data/RdfStore.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/RdfStore.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/RdfStore.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/RdfStore.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,292 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.RdfStore");
+dojo.provide("dojo.data.RhizomeStore");
+dojo.require("dojo.lang.declare");
+dojo.require("dojo.data.core.RemoteStore");
+dojo.require("dojo.experimental");
+
+/* summary:
+ * RdfStore provides a dojo.data Store for querying and updating a server 
+ * that supports the SPARQL Query Result JSON format.
+ * (see http://www.w3.org/TR/rdf-sparql-json-res/)
+ * 
+ * It also maps RDF datatypes to Javascript objects.
+ * 
+ * RdfStore makes following assumptions about the Result JSON:
+ * (1) The result always contains 3 bound variables named "s","p", and "o", 
+ *     and each result binding is treated as an RDF statement.
+ * (2) When saving changes to the store, the JSON "results" object will also 
+ *     contain a "deleted" key whose value is a list of deleted RDF resources.
+ *
+ */
+
+dojo.data.RdfDatatypeSerializer = function(/* JavaScript type */type, /* function */convertFunc, /* RDF datatype URI */uri) {
+	/* summary:
+	This class serializes a javascript object into a RDF datatype literal.
+	*/
+	this.type = type;
+	this._converter = convertFunc;
+	this.uri = uri;
+	this.serialize = function(value) { 
+		return this._converter.call(value, value); 
+	};
+}
+
+dojo.declare("dojo.data.RdfStore", dojo.data.core.RemoteStore, {
+
+	_datatypeMap: {
+		//map datatype strings to constructor function
+		literal: function(value) { 
+			var literal = value.value;
+			if (value["xml:lang"]) {
+				literal.lang = value["xml:lang"];
+			}
+			return literal;
+		},
+		
+		uri: function(value) { 
+			return { id: value.value }; 
+		},
+		
+		bnode: function(value) { 
+			return { id: '_:' + value.value }; 
+		},
+
+		'http://www.w3.org/2001/XMLSchema#int': function(value) { 
+			return parseInt(value.value); 
+		},
+		'http://www.w3.org/2001/XMLSchema#integer': function(value) { 
+			return parseInt(value.value);
+		},
+		'http://www.w3.org/2001/XMLSchema#long': function(value) { 
+			return parseInt(value.value);
+		},
+		'http://www.w3.org/2001/XMLSchema#float': function(value) { 
+			return parseFloat(value.value);
+		},
+		'http://www.w3.org/2001/XMLSchema#double': function(value) { 
+			return parseFloat(value.value);
+		},
+		'http://www.w3.org/2001/XMLSchema#boolean': function(value) { 
+			return !value || value == "false" || value == "0" ? false : true; 
+		}
+		//todo: more datatypes: 
+		//integer subtypes, string types, XMLiteral
+		//,'http://www.w3.org/2001/XMLSchema#... : function(value) { return parseInt(value.value); }
+	},
+
+	_datatypeSerializers: [
+		new dojo.data.RdfDatatypeSerializer(Number, Number.toString, 'http://www.w3.org/2001/XMLSchema#float'), 
+		new dojo.data.RdfDatatypeSerializer(Boolean, Boolean.toString, 'http://www.w3.org/2001/XMLSchema#boolean')
+	],
+	
+	_findDatatypeSerializer: function(value) {
+		var length = this._datatypeSerializers.length;
+		for (var i = 0; i < length; i++) {
+			var datatype = this._datatypeSerializers[i];
+			if (value instanceof datatype.type) {
+				return datatype;
+			}
+		}
+	},
+
+	_toRDFValue: function(value) {
+		//convert values to rdf json format
+		//(from http://www.w3.org/TR/2006/NOTE-rdf-sparql-json-res-20061004/)
+
+		var rdfvalue = {};
+		if (value.id) {
+			if (value.id.slice(0, 2) == '_:') {
+				rdfvalue.type = 'bnode';
+				rdfvalue.value = value.id.substring(2);
+			} else {
+				rdfvalue.type = 'uri';
+				rdfvalue.value = value.id;
+			}
+		} else if (typeof value == "string" || value instanceof String) {
+			rdfvalue.type = 'literal';
+			rdfvalue.value = value;
+			if (value.lang)
+				rdfvalue["xml:lang"] = value.lang;
+		} else {
+			if (typeof value == "number")
+				value = new Number(value);
+			else if (typeof value == "boolean")
+				value = new Boolean(value);
+				
+			var datatype = this._findDatatypeSerializer(value);
+			if (datatype) {
+				rdfvalue = {
+					"type": "typed-literal",
+					"datatype": datatype.uri,
+					"value": value.toString()
+					//todo: datatype.serialize(value) causes
+					//Error: Function.prototype.toString called on incompatible number
+				};
+			} else {
+				//treat it as a string 
+				//todo: warn?
+				rdfvalue = { 
+					"type": "literal", 
+				 	"value": value.toString() };
+			}
+		}
+		return rdfvalue;
+	},
+	
+	_setupSaveRequest: function(saveKeywordArgs, requestKw) { 
+		 /*
+		 This function prepares the save request by populating requestKw, 
+		 an associative array that will be passed to dojo.io.bind.
+		 */
+		
+		//see http://www.w3.org/TR/rdf-sparql-json-res/
+		var rdfResult = { "head":  {'vars': ['s','p','o']}, 
+						 "results": {'bindings': []} };
+
+		var resources = [];
+		for (var key in this._deleted) {
+			resources.push(key);
+		}
+		rdfResult.results.deleted = resources;
+		
+		for (key in this._changed) {
+			var subject = this._toRDFValue(this.getIdentity(key))
+			
+			var attributes = this._changed[key];
+			for (var attr in attributes) {
+				var predicate = {type:'uri', value: attr};
+				
+				var values = attributes[attr];
+				if (!values.length)
+					continue;
+				var rdfvalues = [];
+				for (var i = 0; i < values.length; i++) {
+					var rdfvalue = this._toRDFValue(values[i]);
+					rdfResult.results.bindings.push(
+						{s: subject, p: predicate, o: rdfvalue});
+				}
+			}
+		}
+		
+		var oldRegistry = dojo.json.jsonRegistry;
+		dojo.json.jsonRegistry = this._jsonRegistry;
+		var jsonString = dojo.json.serialize(rdfResult);
+		dojo.json.jsonRegistry = oldRegistry;
+		
+		//dojo.debug('save json' , jsonString);
+		
+		requestKw.postContent = jsonString;
+	},
+	
+	_resultToQueryMetadata: function(json) {
+		return json.head;
+	},
+	
+	_resultToQueryData: function(json) { 
+		//assume s, p, o bindings
+		var items = {};
+		var stmts = json.results.bindings;
+		for (var i = 0; i < stmts.length; i++) {
+			var stmt = stmts[i];
+			//assert stmt.s && stmt.p && stmt.o;
+			var subject = stmt.s.value;
+			if (stmt.s.type == 'bnode') {
+				subject = '_:' + subject;
+			}
+			//else { assert stmt.s.type == 'uri';} 
+			var attributes = data[subject];
+			if (!attributes) {
+				attributes = {};
+				data[stmt.s] = attributes;
+			}
+			var attr = attributes[stmt.p.value];
+			if (!attr) {
+				attributes[stmt.p.value] = [stmt.o];
+			} else {
+				attr.push(stmt.o);
+			}
+		}
+		return items;
+	}
+});
+
+dojo.declare("dojo.data.RhizomeStore", dojo.data.RdfStore, {
+	/* summary:
+	 *   RhizomeStore is a subclass of RdfStore that works with
+	 *   the Rhizome semantic wiki (see http://www.liminalzone.org)
+	 *   Rhizome understands the RemoteStore's "native" json format
+	 *   so it doesn't need to convert it to the SPARQL Query Result format.
+	 */
+
+	initializer: function(kwArgs) {
+		this._serverQueryUrl = kwArgs.baseUrl + 'search?view=json&searchType=RxPath&search=';
+		this._serverSaveUrl = kwArgs.baseUrl + 'save-metadata';
+	},
+
+	_resultToQueryMetadata: function(json) {
+		return json;
+	},
+	
+	_resultToQueryData: function(json) { 
+		//dojo.debug( 'resultjson ' + dojo.json.serialize(json) );
+		return json;
+	},
+	
+	_setupSaveRequest: function(saveKeywordArgs, requestKw) { 
+		 /*
+		 This function prepares the save request by populating requestKw, 
+		 an associative array that will be passed to dojo.io.bind.
+		 */
+		requestKw.url = this._serverSaveUrl;
+		requestKw.method = 'post';
+		requestKw.mimetype = "text/plain";
+		
+		var resources = [];
+		for (var key in this._deleted) {
+			resources.push(key);
+		}
+
+		var changes = {};
+		for (key in this._changed) {
+			if (!this._added[key]) { //don't put new resources in this list
+				resources.push(key);
+			}
+			
+			var attributes = this._changed[key];
+			var rdfattributes = {};
+			for (var attr in attributes) {
+				var values = attributes[attr];
+				if (!values.length)
+					continue;
+				var rdfvalues = [];
+				for (var i = 0; i < values.length; i++) {
+					var rdfvalue = this._toRDFValue(values[i]);
+					rdfvalues.push(rdfvalue);
+				}
+				rdfattributes[attr] = rdfvalues;
+			}
+			changes[key] = rdfattributes;
+		}
+		
+		var oldRegistry = dojo.json.jsonRegistry;
+		dojo.json.jsonRegistry = this._jsonRegistry;
+		var jsonString = dojo.json.serialize(changes);
+		dojo.json.jsonRegistry = oldRegistry;
+		
+		requestKw.content = {
+			rdfFormat: 'json',
+			resource: resources,
+			metadata: jsonString
+		};
+	}
+});

Added: incubator/xap/trunk/codebase/src/dojo/src/data/YahooStore.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/YahooStore.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/YahooStore.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/YahooStore.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,53 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.YahooStore");
+dojo.require("dojo.data.core.RemoteStore");
+dojo.require("dojo.lang.declare");
+dojo.require("dojo.io.ScriptSrcIO");
+
+dojo.declare("dojo.data.YahooStore", dojo.data.core.RemoteStore, {
+	/* Summary:
+	 *	  The YahooStore implements the dojo.data.core.Read API. 
+	 */	
+	_setupQueryRequest: function(result, requestKw) { 
+		var start = 1;
+		var count = 1;
+		if (result) {
+			start = result.start || start;
+			count = result.count || count;
+		}
+		var sourceUrl = "http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=dojo&language=en&query=" + 
+				result.query + "&start=" + start + "&results=" + count + "&output=json";
+		requestKw.url = sourceUrl;
+		requestKw.transport = "ScriptSrcTransport";
+		requestKw.mimetype = "text/json";
+		requestKw.jsonParamName = 'callback';
+	},
+		 
+	_resultToQueryMetadata: function(json) { 
+		return json.ResultSet; 
+	},
+	
+	_resultToQueryData: function(json) {
+		var data = {}
+		for (var i = 0; i < json.ResultSet.totalResultsReturned; ++i) {
+			var record = json.ResultSet.Result[i];
+			var item = {};
+			item["Url"] = [record.Url];
+			item["Title"] = [record.Title];
+			item["Summary"] =[ record.Summary];
+			var arrayIndex = (json.ResultSet.firstResultPosition - 1) + i;
+			data[ arrayIndex.toString() ] = item;
+		}
+		return data;
+	}
+});
+

Added: incubator/xap/trunk/codebase/src/dojo/src/data/core/Read.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/core/Read.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/core/Read.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/core/Read.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,321 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.core.Read");
+dojo.require("dojo.data.core.Result");
+dojo.require("dojo.lang.declare");
+dojo.require("dojo.experimental");
+
+/* summary:
+ *   This is an abstract API that data provider implementations conform to.  
+ *   This file defines methods signatures and intentionally leaves all the
+ *   methods unimplemented.
+ */
+dojo.experimental("dojo.data.core.Read");
+ 
+dojo.declare("dojo.data.core.Read", null, {
+	get: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* value? */ defaultValue) {
+		/* summary:
+		 *   Returns a single attribute value.
+		 *   Returns defaultValue if *item* does not have a value for *attribute*.
+		 *   Returns null if null was explicitly set as the attribute value.
+		 *   Returns undefined if the item does not have a value for the given 
+		 *   attribute, or if the item does not have the attribute. 
+		 * description:
+		 *   Saying that an "item x does not have a value for an attribute y"
+		 *   is identical to saying that an "item x does not have attribute y". 
+		 *   It is an oxymoron to say "that attribute is present but has no values" 
+		 *   or "the item has that attribute but does not have any attribute values".
+		 *   If store.hasAttribute(item, attribute) returns false, then
+		 *   store.get(item, attribute) will return undefined.
+		 */
+		 
+		/* exceptions:
+		 *   Conforming implementations should throw an exception if *item* is not
+		 *   an item, or *attribute* is neither an attribute object or a string.
+		 * examples:
+		 *   var darthVader = store.get(lukeSkywalker, "father");
+		 */
+		dojo.unimplemented('dojo.data.core.Read.get');
+		var attributeValue = null;
+		return attributeValue; // a literal, an item, null, or undefined (never an array)
+	},
+	
+	getValues: function(/* item */ item, /* attribute || attribute-name-string */ attribute) {
+		/* summary:
+		 *   This getValues() method works just like the get() method, but getValues()
+		 *   always returns an array rather than a single attribute value.  The array
+		 *   may be empty, may contain a single attribute value, or may contain many
+		 *   attribute values.
+		 *   If the item does not have a value for the given attribute, then getValues()
+		 *   will return an empty array: [].  (So, if store.hasAttribute(item, attribute)
+		 *   returns false, then store.getValues(item, attribute) will return [].)
+		 */
+		 
+		/* exceptions:
+		 *   Throws an exception if *item* is not an item, or *attribute* is neither an 
+		 *   attribute object or a string.
+		 * examples:
+		 *   var friendsOfLuke = store.get(lukeSkywalker, "friends");
+		 */
+		dojo.unimplemented('dojo.data.core.Read.getValues');
+		var array = null;
+		return array; // an array that may contain literals and items
+	},
+	
+	getAttributes: function(/* item */ item) {
+		/* summary:
+		 *   Returns an array with all the attributes that this item has.  This
+		 *   method will always return an array; if the item has no attributes
+		 *   at all, getAttributes() will return an empty array: [].
+		 */
+		 
+		/* exceptions:
+		 *   Throws an exception if *item* is not an item. 
+		 * examples:
+		 *   var array = store.getAttributes(kermit);
+		 */
+		dojo.unimplemented('dojo.data.core.Read.getAttributes');
+		var array = null;
+		return array; // array
+	},
+	
+	hasAttribute: function(/* item */ item, /* attribute || attribute-name-string */ attribute) {
+		/* summary:
+		 *   Returns true if the given *item* has a value for the given *attribute*.
+		 */
+		 
+		/* exceptions:
+		 *   Throws an exception if *item* is not an item, or *attribute* is neither an 
+		 *   attribute object or a string.
+		 * examples:
+		 *   var trueOrFalse = store.hasAttribute(kermit, "color");
+		 */
+		dojo.unimplemented('dojo.data.core.Read.hasAttribute');
+		return false; // boolean
+	},
+	
+	containsValue: function(/* item */ item, /* attribute || attribute-name-string */ attribute, /* anything */ value) {
+		/* summary:
+		 *   Returns true if the given *value* is one of the values that getValue()
+		 *   would return.
+		 */
+		 
+		/* exceptions:
+		 *   Throws an exception if *item* is not an item, or *attribute* is neither an 
+		 *   attribute object or a string.
+		 * examples:
+		 *   var trueOrFalse = store.containsValue(kermit, "color", "green");
+		 */
+		dojo.unimplemented('dojo.data.core.Read.containsValue');
+		return false; // boolean
+	},
+	
+	isItem: function(/* anything */ something) {
+		/* summary:
+		 *   Returns true if *something* is an item.  Returns false if *something*
+		 *   is a literal or is any object other than an item.
+		 */
+		 
+		/* examples:
+		 *   var yes = store.isItem(store.newItem());
+		 *   var no  = store.isItem("green");
+		 */
+		dojo.unimplemented('dojo.data.core.Read.isItem');
+		return false; // boolean
+	},
+	
+	isItemAvailable: function(/* anything */ something) {
+		/* summary:
+		 *   Returns false if isItem(something) is false.  Returns false if
+		 *   if isItem(something) is true but the the item is not yet available
+		 *   in local memory (for example, if the item has not yet been fully
+		 *   loaded from the server).
+		 */
+		 
+		/* examples:
+		 *   var yes = store.isItemAvailable(store.newItem());
+		 *   var no  = store.isItemAvailable("green");
+		 */
+		dojo.unimplemented('dojo.data.core.Read.isItemAvailable');
+		return false; // boolean
+	},
+	
+	find: function(/* object? || dojo.data.core.Result */ keywordArgs) {
+		/* summary:
+		 *   Given a query, this method executes the query and makes the
+		 *   results available as data items.
+		 * description:
+		 *   A Result object will always be returned, even if the result set
+		 *   is empty.  A Result object will always be returned immediately.
+		 *   By default the Result object will be fully populated with result
+		 *   items as soon as it is created (synchronously).  The caller may 
+		 *   request that the find() operation be executed asynchronously, in
+		 *   which case the Result object will be returned immediately but 
+		 *   will not yet be populated with result items.  
+		 *   For more info about the Result API, see dojo.data.core.Result
+		 * keywordArgs:
+		 *   The keywordArgs parameter may either be an instance of 
+		 *   dojo.data.core.Result or may be a simple anonymous object
+		 *   that may contain any of the following:
+		 *   { query: query-string or query-object,
+		 *     sync: Boolean,
+		 *     saveResult: Boolean,
+		 *     onbegin: Function,
+		 *     onnext: Function,
+		 *     oncompleted: Function,
+		 *     onerror: Function,
+		 *     scope: object
+		 *     }
+		 *   All implementations should accept keywordArgs objects with any of
+		 *   the 7 standard properties: query, sync, saveResult, onnext, oncompleted, 
+		 *   onerror, and scope.  Some implementations may accept additional 
+		 *   properties in the keywordArgs object as valid parameters, such as 
+		 *   {maxResults:100} or {includeOutliers:true}.		 
+		 * The *query* parameter.
+		 *   The query may be optional in some data store implementations.
+		 *   The dojo.data.core.Read API does not specify the syntax or semantics
+		 *   of the query itself -- each different data store implementation
+		 *   may have its own notion of what a query should look like.
+		 *   In most implementations the query will probably be a string, but
+		 *   in some implementations the query might be a Date, or a number,
+		 *   or some complex keyword parameter object.  The dojo.data.core.Read
+		 *   API is completely agnostic about what the query actually is.
+		 * The *sync* parameter.
+		 *   The sync parameter specifies whether the find operation is asynchronous 
+		 *   or not, with {sync:false} for asynchronous finds operations and 
+		 *   {sync:true} for synchronous find operations.  If no sync parameter
+		 *   is specified, the default is {sync:true}.
+		 * The *saveResult* parameter.
+		 *   If saveResult is true, then the find call will return a Result
+		 *   object that includes a property called *items*, and *items* will
+		 *   contain an array of the items found by the query.  If no saveResult
+		 *   parameter is specified and no onnext Function is set, the default 
+		 *   saveResult value will be {saveResult:true}.  If no saveResult
+		 *   parameter is specified but an onnext Function is set, the default 
+		 *   saveResult value will be {saveResult:false}.  
+		 * The *onbegin* parameter.
+		 *   If an onbegin callback function is provided, the callback function
+		 *   will be called just once, before the first onnext callback is called.
+		 *   The onbegin callback function will be passed a single argument:
+		 *   the Result object.  The onbegin callback will be called even if 
+		 *   query returns zero items.
+		 * The *onnext* parameter.
+		 *   If an onnext callback function is provided, the callback function
+		 *   will be called as each item in the result is received. The callback 
+		 *   function will be passed two arguments: the item itself, and the
+		 *   Result object.
+		 * The *oncompleted* parameter.
+		 *   If an oncompleted callback function is provided, the callback function
+		 *   will be called just once, after the last onnext callback is called.
+		 *   The oncompleted callback function will be passed a single argument:
+		 *   the Result object.  The oncompleted callback will be called even if 
+		 *   query returns zero items.
+		 * The *onerror* parameter.
+		 *   If an onerror callback function is provided, the callback function
+		 *   will be called if there is any sort of error while attempting to
+		 *   execute the query..
+		 *   The onerror callback function will be passed two arguments:
+		 *   an Error object and the Result object.
+		 * The *scope* parameter.
+		 *   If a scope object is provided, all of the callback function (onnext, 
+		 *   oncompleted, onerror) will be invoked in the context of the scope
+		 *   object.  In the body of the callback function, the value of the "this"
+		 *   keyword will be the scope object.   If no scope object is provided,
+		 *   the callback functions will be called in the context of dj_global.  
+		 *   For example, onnext.call(scope, item, result) vs. 
+		 *   onnext.call(dj_global, item, result)
+		 * returns:
+		 *   The find() method will return an instance of dojo.data.core.Result
+		 *   (or an object that extends dojo.data.core.Result or conforms to the
+		 *   dojo.data.core.Result API).  If the find() method was passed an
+		 *   instance of dojo.data.core.Result as an argument, the same instance
+		 *   will be returned.  If the find() method was passed a simple 
+		 *   keywordArgs object, like {sync:true}, then the properties in the
+		 *   keywordArgs object will be copied into the Result object that 
+		 *   find() returns.  The Result object will also have additional 
+		 *   properties when it is returned.  The result.store property will 
+		 *   have a pointer to the datastore object that find() is a method of.
+		 *   The result.length will be -1 if the find() operation has not 
+		 *   finished or if there was an error; if the find() operation
+		 *   finishes successfully, result.length will be the number of items
+		 *   that were found.  If the saveResult property was set to true, or
+		 *   if no onnext callback was set, the result.item property will 
+		 *   contain an array of data items.  The result.resultMetadata property 
+		 *   will contain an additional metaData that was returned by the query
+		 *   along with the data items.  For example, if the query returned a
+		 *   list of 500 houses for sales, the resultMetadata property might
+		 *   contain the average asking price of the houses, or info about 
+		 *   how long the query took to execute.
+		 */
+		
+		/* exceptions:
+		 *   Throws an exception if the query is not valid, or if the query
+		 *   is required but was not supplied.
+		 * examples:
+		 *   var result = store.find({query:"all books"});
+		 *   var result = store.find();
+		 *   var result = store.find({query:"foo/bar", sync:true});
+		 *   var result = store.find({query:"foo/bar", sync:false, onnext:callback});
+		 *   var result = store.find({query:{author:"King"}, maxResults:100});
+		 */
+		dojo.unimplemented('dojo.data.core.Read.find');
+		var result = null; // new dojo.data.core.Result().
+		return result; // a dojo.data.core.Result object
+	},
+	
+	getIdentity: function(/* item */ item) {
+		/* summary:
+		 *   Returns a unique identifer for an item.  The return value will be
+		 *   either a string or something that has a toString() method (such as,
+		 *   for example, a dojo.uuid.Uuid object).
+		 * description:
+		 * ISSUE - 
+		 *   Should we move this method out of dojo.data.core.Read, and put it somewhere
+		 *   else, like maybe dojo.data.core.Identity?
+		 */
+		 
+		/* exceptions:
+		 *   Conforming implementations may throw an exception or return null if
+		 *   item is not an item.
+		 * examples:
+		 *   var itemId = store.getIdentity(kermit);
+		 *   assert(kermit === store.findByIdentity(store.getIdentity(kermit)));
+		 */
+		dojo.unimplemented('dojo.data.core.Read.getIdentity');
+		var itemIdentifyString = null;
+		return itemIdentifyString; // string
+	},
+	
+	findByIdentity: function(/* string */ identity) {
+		/* summary:
+		 *   Given the identity of an item, this method returns the item that has 
+		 *   that identity.  Conforming implementations should return null if there 
+		 *   is no item with the given identity.  Implementations of findByIdentity() 
+		 *   may sometimes return an item from a local cache and may sometimes 
+		 *   fetch an item from a remote server, in which case the call to 
+		 *   findByIdentity() will block until the findByIdentity() implementation 
+		 *   has the item to return.
+		 * description:
+		 * FIXME - 
+		 *   In our meeting on 2006-10-03 we resolved to move the findByIdentity()
+		 *   method out of the Read.js API and into the Identity.js API, as soon
+		 *   as we have an Identity.js API.
+		 */
+		 
+		/* examples:
+		 *   var alaska = store.getByIdentity("AK");
+		 *   assert("AK" == store.getIdentity(store.getByIdentity("AK")));
+		 */
+		dojo.unimplemented('dojo.data.core.Read.getByIdentity');
+		var item = null;
+		return item; // item
+	}
+});

Added: incubator/xap/trunk/codebase/src/dojo/src/data/core/RemoteStore.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/core/RemoteStore.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/core/RemoteStore.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/core/RemoteStore.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,590 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.core.RemoteStore");
+dojo.require("dojo.data.core.Read");
+dojo.require("dojo.data.core.Write");
+dojo.require("dojo.data.core.Result");
+dojo.require("dojo.experimental");
+dojo.require("dojo.Deferred");
+dojo.require("dojo.lang.declare");
+dojo.require("dojo.json");
+dojo.require("dojo.io.*");
+
+/* summary:
+ *   RemoteStore is an implemention the dojo.data.core.Read and Write APIs. 
+ *   It is designed to serve as a base class for dojo.data stores which interact 
+ *   with stateless web services that can querying and modifying record-oriented 
+ *   data.  Its features include asynchronous and synchronous querying and saving; 
+ *   caching of queries; transactions; and datatype mapping.
+ */
+
+/**************************************************************************
+  Classes derived from RemoteStore should implement the following three 
+  methods, which are each described in the documentation below:
+    _setupQueryRequest(result, requestKw) 
+    _resultToQueryData(responseData) 
+    _setupSaveRequest(saveKeywordArgs, requestKw)
+  
+  Data Consistency Guarantees
+  
+  * if two references to the same item are obtained (e.g. from two different query results) any changes to one item will be reflected in the other item reference.
+  * If an item has changed on the server and the item is retrieved via a new query, any previously obtained references to the item will (silently) reflect these new values.
+  * However, any uncommitted changes will not be "overwritten".
+  * If server queries are made while there are uncommitted changes, no attempt is made to evaluate whether the modifications would change the query result, e.g. add any uncommitted new items that match the query.
+  * However, uncomitted deleted items are removed from the query result.
+  * The transaction isolation level is equivalent to JDBC's "Read Committed":
+    each store instance is treated as separate transaction; since there is no row or table locking so nonrepeatable and phantom reads are possible.
+  
+  Memory Usage
+  
+  Because Javascript doesn't support weak references or user-defined finalize methods, there is a tradeoff between data consistency and memory usage.
+  In order to implement the above consistency guarantees (and to provide caching), RemoteStore remembers all the queries and items retrieved. 
+  To reduce memory consumption, use the method forgetResults(query);
+  
+  Store assumptions
+  
+  RemoteStore makes some assumptions about the nature of the remote store, things may break if these aren't true:
+  * that the items contained in a query response include all the attributes of the item (e.g. all the columns of a row).   
+    (to fix: changes need to record add and removes and fix self._data[key] = [ attributeDict, refCount]; )
+  * the query result may contain references to items that are not available to the client; use isItem() to test for the presence of the item.
+  * that modification to an item's attributes won't change it's primary key.
+  
+**************************************************************************/
+
+/* dojo.data API issues to resolve:
+ * save should returns a Deferred, might want to add keyword argument with 'sync' 
+ */
+
+dojo.experimental("dojo.data.core.RemoteStore");
+
+dojo.lang.declare("dojo.data.core.RemoteStore", [dojo.data.core.Read, dojo.data.core.Write], {
+
+	_datatypeMap: {
+		//map datatype strings to constructor function
+	},
+
+	//set to customize json serialization
+	_jsonRegistry: dojo.json.jsonRegistry,
+
+	initializer: function(/* object */ kwArgs) {
+		if (!kwArgs) {
+			kwArgs = {};
+		}
+		this._serverQueryUrl = kwArgs.queryUrl || "";
+		this._serverSaveUrl = kwArgs.saveUrl || "";
+				
+		this._deleted = {}; // deleted items {id: 1}	
+		this._changed = {}; // {id: {attr: [new values]}} // [] if attribute is removed
+		this._added = {};   // {id: 1} list of added items
+		this._results = {}; // {query: [ id1, ]};	// todo: make MRUDict of queries
+		/* data is a dictionary that conforms to this format: 
+		  { id-string: { attribute-string: [ value1, value2 ] } }
+		  where value is either an atomic JSON data type or 
+		  { 'id': string } for references to items
+		  or 
+		  { 'type': 'name', 'value': 'value' } for user-defined datatypes
+		*/ 
+		this._data = {}; // {id: [values, refcount]} // todo: handle refcount
+		this._numItems = 0;
+	},
+	
+	_setupQueryRequest: function(/* dojo.data.core.Result */ result, /* object */ requestKw) { 
+		/* summary:
+		 *   Classes derived from RemoteStore should override this method to
+		 *   provide their own implementations.
+		 *   This function prepares the query request by populating requestKw, 
+		 *   an associative array that will be passed to dojo.io.bind.
+		 */
+		result.query = result.query || "";
+		requestKw.url = this._serverQueryUrl + encodeURIComponent(result.query);
+		requestKw.method = 'get';
+		requestKw.mimetype = "text/json";
+	},
+
+	_resultToQueryMetadata: function(/* varies */ serverResponseData) { 
+		/* summary:
+		 *   Classes derived from RemoteStore should override this method to
+		 *   provide their own implementations.
+		 *   Converts the server response data into the resultMetadata object
+		 *   that will be returned to the caller.
+		 * returns:
+		 *   This simple default implementation just returns the entire raw
+		 *   serverResponseData, allowing the caller complete access to the 
+		 *   raw response data and metadata.
+		 */
+		return serverResponseData; 
+	},
+		
+	_resultToQueryData: function(/* varies */ serverResponseData) {
+		/* summary:
+		 *   Classes derived from RemoteStore should override this method to
+		 *   provide their own implementations.
+		 *   Converts the server response data into the internal data structure 
+		 *   used by RemoteStore.  
+		 * returns:
+		 *   The RemoteStore implementation requires _resultToQueryData() to 
+		 *   return an object that looks like:
+		 *   {item1-identifier-string: { 
+		 *   	attribute1-string: [ value1, value2, ... ], 
+		 *   	attribute2-string: [ value3, value4, ... ], 
+		 *   	...
+		 *   	},
+		 *    item2-identifier-string: { 
+		 *   	attribute1-string: [ value10, value11, ... ], 
+		 *   	attribute2-string: [ value12, value13, ... ], 
+		 *   	...
+		 *   	}
+		 *   }
+		 *   where value is either an atomic JSON data type or 
+		 *     {'id': string } for references to items
+		 *   or 
+		 *    {'type': 'name', 'value': 'value' } for user-defined datatypes
+		 * data:
+		 *   This simple default implementation assumes that the *serverResponseData* 
+		 *   argument is an object that looks like:
+		 *     { data:{ ... }, format:'format identifier', other metadata }
+		 *   
+		 */
+		return serverResponseData.data;
+	},
+
+	_remoteToLocalValues: function(/* object */ attributes) {
+		for (var key in attributes) {
+			 var values = attributes[key];
+			 for (var i = 0; i < values.length; i++) {
+				var value = values[i];
+				var type = value.datatype || value.type;
+				if (type) {
+					// todo: better error handling?
+					var localValue = value.value;
+					if (this._datatypeMap[type]) 
+						localValue = this._datatypeMap[type](value);							
+					values[i] = localValue;
+				}
+			}
+		}
+		return attributes; // object (attributes argument, modified in-place)
+	},
+
+	_queryToQueryKey: function(query) {
+		/* summary:
+		 *   Convert the query to a string that uniquely represents this query. 
+		 *   (Used by the query cache.)
+		 */
+		if (typeof query == "string")
+			return query;
+		else
+			return dojo.json.serialize(query);
+	},
+
+	_assertIsItem: function(/* item */ item) {
+		if (!this.isItem(item)) { 
+			throw new Error("dojo.data.RemoteStore: a function was passed an item argument that was not an item");
+		}
+	},
+	
+	get: function(/* item */ item, /* attribute || string */ attribute, /* value? */ defaultValue) {
+		// summary: See dojo.data.core.Read.get()
+		var valueArray = this.getValues(item, attribute);
+		if (valueArray.length == 0) {
+			return defaultValue;
+		}
+		return valueArray[0];  // value
+	},
+
+	getValues: function(/* item */ item, /* attribute || string */ attribute) {				
+		// summary: See dojo.data.core.Read.getValues()
+		var itemIdentity = this.getIdentity(item);
+		this._assertIsItem(itemIdentity);
+		var changes = this._changed[itemIdentity];
+		if (changes) {
+			var newvalues = changes[attribute]; 
+			if (newvalues !== undefined) {
+				return newvalues;  // Array
+			}
+			else {
+				return []; // Array
+			}
+		}
+		// return item.atts[attribute];
+		return this._data[itemIdentity][0][attribute]; // Array
+	},
+
+	getAttributes: function(/* item */ item) {	
+		// summary: See dojo.data.core.Read.getAttributes()
+		var itemIdentity = this.getIdentity(item);
+		if (!itemIdentity) 
+			return undefined; //todo: raise exception
+
+		var atts = [];
+		//var attrDict = item.attrs;
+		var attrDict = this._data[itemIdentity][0];
+		for (var att in attrDict) {
+			atts.push(att);
+		}
+		return atts; // Array
+	},
+	
+	hasAttribute: function(/* item */ item, /* attribute || string */ attribute) {
+		// summary: See dojo.data.core.Read.hasAttribute()
+		var valueArray = this.getValues(item, attribute);
+		return valueArray.length ? true : false; // Boolean
+	},
+
+	containsValue: function(/* item */ item, /* attribute || string */ attribute, /* value */ value) {
+		// summary: See dojo.data.core.Read.containsValue()
+		var valueArray = this.getValues(item, attribute);
+		for (var i=0; i < valueArray.length; i++) {	
+			if (valueArray[i] == value) {
+				return true; // Boolean
+			}
+		}
+		return false; // Boolean
+	},
+		
+	isItem: function(/* anything */ something) {
+		// summary: See dojo.data.core.Read.isItem()
+		if (!something) { return false; }
+		var itemIdentity = something;
+		// var id = something.id ? something.id : something; 
+		// if (!id) { return false; }
+		if (this._deleted[itemIdentity]) { return false; } //todo: do this?
+		if (this._data[itemIdentity]) { return true; } 
+		if (this._added[itemIdentity]) { return true; }
+		return false; // Boolean
+	},
+
+	find: function(/* object? || dojo.data.core.Result */ keywordArgs) {
+		// summary: See dojo.data.core.Read.find()
+		/* description:
+		 *   In addition to the keywordArgs parameters described in the
+		 *   dojo.data.core.Read.find() documentation, the keywordArgs for
+		 *   the RemoteStore find() method may include a bindArgs parameter,
+		 *   which the RemoteStore will pass to dojo.io.bind when it sends 
+		 *   the query.  The bindArgs parameter should be a keyword argument 
+		 *   object, as described in the dojo.io.bind documentation.
+		 */
+		var result = null;
+		if (keywordArgs instanceof dojo.data.core.Result) {
+			result = keywordArgs;
+			result.store = this;
+		} else {
+			result = new dojo.data.core.Result(keywordArgs, this);
+		}
+		var query = result.query;
+		
+		//todo: use this._results to implement caching
+		var self = this;
+		var bindfunc = function(type, data, evt) {
+			var scope = result.scope || dj_global;
+			if(type == "load") {	
+				//dojo.debug("loaded 1 " + dojo.json.serialize(data) );
+				result.resultMetadata = self._resultToQueryMetadata(data);
+				var dataDict = self._resultToQueryData(data); 
+				//dojo.debug("loaded 2 " + dojo.json.serialize(dataDict) );
+				if (result.onbegin) {
+					result.onbegin.call(scope, result);
+				}
+				var count = 0;
+				var resultData = []; 
+				var newItemCount = 0;
+				for (var key in dataDict) {
+					if (result._aborted)  {
+						break;
+					}
+					if (!self._deleted[key]) { //skip deleted items
+						//todo if in _added, remove from _added
+						var values = dataDict[key];										
+						var attributeDict = self._remoteToLocalValues(values);
+						var existingValue = self._data[key];
+						var refCount = 1;
+						if (existingValue) {
+							refCount = ++existingValue[1]; //increment ref count
+						} else {
+							newItemCount++;
+						}
+						//note: if the item already exists, we replace the item with latest set of attributes
+						//this assumes queries always return complete records
+						self._data[key] = [ attributeDict, refCount]; 
+						resultData.push(key);
+						count++; 
+						if (result.onnext) {
+							result.onnext.call(scope, key, result);
+						}
+					}									
+				}
+				self._results[self._queryToQueryKey(query)] = resultData; 
+				self._numItems += newItemCount;
+
+				result.length = count;
+				if (result.saveResult) {
+					result.items = resultData;
+				}
+				if (!result._aborted && result.oncompleted) {
+					result.oncompleted.call(scope, result);
+				}
+			} else if(type == "error" || type == 'timeout') {
+				// here, "data" is our error object
+				//todo: how to handle timeout?
+				dojo.debug("find error: " + dojo.json.serialize(data));
+				if (result.onerror) {
+					result.onerror.call(scope, data);
+				}
+			}
+		};
+
+		var bindKw = keywordArgs.bindArgs || {};
+		bindKw.sync = result.sync;
+		bindKw.handle = bindfunc;
+
+		this._setupQueryRequest(result, bindKw);
+		var request = dojo.io.bind(bindKw);
+		//todo: error if not bind success
+		//dojo.debug( "bind success " + request.bindSuccess);
+		result._abortFunc = request.abort;	 
+		return result; 
+	},
+
+	getIdentity: function(item) {
+		// summary: See dojo.data.core.Read.getIdentity()
+		if (!this.isItem(item)) {
+			return null;
+		}
+		return (item.id ? item.id : item); // Identity
+	},
+
+/*
+	findByIdentity: function(id) {
+		var item = this._latestData[id];
+		var idQuery = "/" + "*[.='"+id+"']";
+		//if (!item) item = this.find(idQuery, {async=0}); //todo: support bind(async=0)
+		if (item)
+			return new _Item(id, item, this); 
+		return null;
+	},
+*/
+
+/****
+Write API
+***/
+	newItem: function(/* object? */ attributes, /* object? */ keywordArgs) {
+		var itemIdentity = keywordArgs['identity'];
+		if (this._deleted[itemIdentity]) {
+			delete this._deleted[itemIdentity];
+		} else {
+			this._added[itemIdentity] = 1;
+			//todo? this._numItems++; ?? but its not in this._data
+		}
+		if (attributes) {
+			// FIXME:
+			for (var attribute in attributes) {
+				var valueOrArrayOfValues = attributes[attribute];
+				if (dojo.lang.isArray(valueOrArrayOfValues)) {
+					this.setValues(itemIdentity, attribute, valueOrArrayOfValues);
+				} else {
+					this.set(itemIdentity, attribute, valueOrArrayOfValues);
+				}
+			}
+		}
+		return { id: itemIdentity };
+	},
+		
+	deleteItem: function(/* item */ item) {
+		var identity = this.getIdentity(item);
+		if (!identity) {
+			return false;
+		}
+		
+		if (this._added[identity]) {
+			delete this._added[identity];
+		} else {
+			this._deleted[identity] = 1; 
+			//todo? this._numItems--; ?? but its still in this._data
+		}
+			
+		if (this._changed[identity]) {
+			delete this._changed[identity];	
+		}
+		return true; 
+	},
+	
+	setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values) {
+		var identity = this.getIdentity(item);
+		if (!identity) {
+			return undefined; //todo: raise exception
+		}
+
+		var changes = this._changed[identity];
+		if (!changes) {
+			changes = {}
+			this._changed[identity] = changes;
+		} 					
+		changes[attribute] = values;
+		return true; // boolean
+	},
+
+	set: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value) {
+		return this.setValues(item, attribute, [value]); 
+	},
+
+	unsetAttribute: function(/* item */ item, /* attribute || string */ attribute) {
+		return this.setValues(item, attribute, []); 
+	},
+
+	_initChanges: function() {
+		this._deleted = {}; 
+		this._changed = {};
+		this._added = {}; 
+	},
+
+	_setupSaveRequest: function(saveKeywordArgs, requestKw) { 
+		/* summary:
+		 *   This function prepares the save request by populating requestKw, 
+		 *   an associative array that will be passed to dojo.io.bind.
+		 */
+		requestKw.url = this._serverSaveUrl;
+		requestKw.method = 'post';
+		requestKw.mimetype = "text/plain";
+		var deleted = [];
+		for (var key in this._deleted) {
+			deleted.push(key);
+		}
+		//don't need _added in saveStruct, changed covers that info	 
+		var saveStruct = {'changed': this._changed, 'deleted': deleted };
+		var oldRegistry = dojo.json.jsonRegistry;
+		dojo.json.jsonRegistry = this._jsonRegistry;
+		var jsonString = dojo.json.serialize(saveStruct);
+		dojo.json.jsonRegistry = oldRegistry;
+		requestKw.postContent = jsonString;
+	},
+
+	save: function(/* object? */ keywordArgs) {
+		/* summary:
+		 *   Saves all the changes that have been made.
+		 * keywordArgs:
+		 *   The optional keywordArgs parameter may contain 'sync' to specify 
+		 *   whether the save operation is asynchronous or not.  The default is 
+		 *   asynchronous.  
+		 * examples: 
+		 *   store.save();
+		 *   store.save({sync:true});
+		 *   store.save({sync:false});
+		 */
+		keywordArgs = keywordArgs || {};
+		var result = new dojo.Deferred();			 
+		var self = this;
+
+		var bindfunc = function(type, data, evt) {			
+			if(type == "load"){ 
+				if (result.fired == 1) {
+					//it seems that mysteriously "load" sometime 
+					//gets called after "error"
+					//so check if an error has already occurred 
+					//and stop if it has 
+					return;
+				}
+				//update this._data upon save
+				var key = null;
+				for (key in self._added) {
+					if (!self._data[key])
+					self._data[key] = [{} , 1];
+				}
+				for (key in self._changed) {
+					var existing = self._data[key];
+					var changes = self._changed[key];
+					if (existing) {
+						existing[0] = changes;
+					} else {
+						self._data[key] = [changes, 1];
+					}
+				}
+				for (key in self._deleted) {
+					if (self._data[key]) {
+						delete self._data[key];
+					}
+				}
+				self._initChanges(); 
+				result.callback(true); //todo: what result to pass?
+			} else if(type == "error" || type == 'timeout'){
+				result.errback(data); //todo: how to handle timeout
+			}	
+		};
+				
+		var bindKw = { sync: keywordArgs["sync"], handle: bindfunc };
+		this._setupSaveRequest(keywordArgs, bindKw);
+		var request = dojo.io.bind(bindKw);
+		result.canceller = function(deferred) { request.abort(); };
+				
+		return result; 
+	},
+		 
+	revert: function() {
+		this._initChanges(); 
+		return true;
+	},
+
+	isDirty: function(/*item?*/ item) {
+		if (item) {
+			// return true if this item is dirty
+			var identity = item.id || item;
+			return this._deleted[identity] || this._changed[identity];
+		} else {
+			// return true if any item is dirty
+			var key = null;
+			for (key in this._changed) {
+				return true;
+			}
+			for (key in this._deleted) {
+				return true;
+			}
+			for (key in this._added) {
+				return true;
+			}
+
+			return false;
+		}
+	},
+
+/**
+additional public methods
+*/
+	createReference: function(idstring) {
+		return { id : idstring };
+	},
+
+	getSize: function() { 
+		return this._numItems; 
+	},
+		
+	forgetResults: function(query) {
+		var queryKey = this._queryToQueryKey(query);
+		var results = this._results[queryKey];
+		if (!results) return false;
+
+		var removed = 0;
+		for (var i = 0; i < results.length; i++) {
+			var key = results[i];
+			var existingValue = this._data[key];
+			if (existingValue[1] <= 1) {
+				delete this._data[key];
+				removed++;
+			}
+			else
+				existingValue[1] = --existingValue[1];
+		}
+		delete this._results[queryKey];
+		this._numItems -= removed;
+		return true;
+	} 
+});
+
+
+

Added: incubator/xap/trunk/codebase/src/dojo/src/data/core/Result.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/core/Result.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/core/Result.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/core/Result.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,58 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.core.Result");
+dojo.require("dojo.lang.declare");
+dojo.require("dojo.experimental");
+
+/* summary:
+ *	 Instances of dojo.data.core.Result are returned by the find() method
+ *	 of datastores that implement the dojo.data.core.Read API.  For more
+ *   documentation, see the find() method on dojo.data.core.Read.
+ */
+dojo.experimental("dojo.data.core.Result");
+
+dojo.declare("dojo.data.core.Result", null, {
+	initializer: function(/* object */ keywordArgs, /* dojo.data.core.Read */ store) {
+		this.fromKwArgs(keywordArgs || {});
+		this.items = null;
+		this.resultMetadata = null;
+		this.length = -1; // -1 until completion 
+		this.store = store;
+		
+		this._aborted = false;
+		this._abortFunc = null;
+	},
+
+	/* Whether the request should be made synchronously. 
+	 * We default to true if there's no {sync:false} property in the keywordArgs 
+	 * in the initializer for a given instance of dojo.data.core.Result.
+	 */
+	sync: true,
+		
+	//timeout: function(type){ }, todo: support this
+	//timeoutSeconds: 0, todo: support this
+		
+	// the abort method needs to be filled in by the transport that accepts the
+	// bind() request
+	abort: function() {
+		this._aborted = true;
+		if (this._abortFunc) {
+			this._abortFunc();
+		}
+	},
+	
+	fromKwArgs: function(/* object */ kwArgs) {
+		if (typeof kwArgs.saveResult == "undefined") {
+			this.saveResult = kwArgs.onnext ? false : true;
+		}
+		dojo.lang.mixin(this, kwArgs);
+	}
+});

Added: incubator/xap/trunk/codebase/src/dojo/src/data/core/Write.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/core/Write.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/core/Write.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/core/Write.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,169 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.core.Write");
+dojo.require("dojo.data.core.Read");
+dojo.require("dojo.lang.declare");
+dojo.require("dojo.experimental");
+
+/* summary:
+ *   This is an abstract API that data provider implementations conform to.  
+ *   This file defines methods signatures and intentionally leaves all the
+ *   methods unimplemented.
+ */
+dojo.experimental("dojo.data.core.Write");
+ 
+dojo.declare("dojo.data.core.Write", dojo.data.core.Read, {
+	newItem: function(/* object? */ keywordArgs) {
+		/* summary:
+		 *   Returns a newly created item.  Sets the attributes of the new
+		 *   item based on the *keywordArgs* provided.
+		 */
+		 
+		/* exceptions:
+		 *   Throws an exception if *keywordArgs* is a string or a number or
+		 *   anything other than a simple anonymous object.
+		 * examples:
+		 *   var kermit = store.newItem({name: "Kermit", color:[blue, green]});
+		 */
+		var newItem;
+		dojo.unimplemented('dojo.data.core.Write.newItem');
+		return newItem; // item
+	},
+	
+	deleteItem: function(/* item */ item) {
+		/* summary:
+		 *   Deletes an item from the store.
+		 */
+		 
+		/* exceptions:
+		 *   Throws an exception if the argument *item* is not an item 
+		 *   (if store.isItem(item) returns false).
+		 * examples:
+		 *   var success = store.deleteItem(kermit);
+		 */
+		dojo.unimplemented('dojo.data.core.Write.deleteItem');
+		return false; // boolean
+	},
+	
+	set: function(/* item */ item, /* attribute || string */ attribute, /* almost anything */ value) {
+		/* summary:
+		 *   Sets the value of an attribute on an item.
+		 *   Replaces any previous value or values.
+		 */
+		 
+		/* exceptions:
+		 *   Throws an exception if *item* is not an item, or if *attribute*
+		 *   is neither an attribute object or a string.
+		 *   Throws an exception if *value* is undefined.
+		 * examples:
+		 *   var success = store.set(kermit, "color", "green");
+		 */
+		dojo.unimplemented('dojo.data.core.Write.set');
+		return false; // boolean
+	},
+	
+	setValues: function(/* item */ item, /* attribute || string */ attribute, /* array */ values) {
+		/* summary:
+		 *   Adds each value in the *values* array as a value of the given
+		 *   attribute on the given item.
+		 *   Replaces any previous value or values.
+		 *   Calling store.setValues(x, y, []) (with *values* as an empty array) has
+		 *   the same effect as calling store.clear(x, y).
+		 */
+		 
+		/* exceptions:
+		 *   Throws an exception if *values* is not an array, if *item* is not an
+		 *   item, or if *attribute* is neither an attribute object or a string.
+		 * examples:
+		 *   var success = store.setValues(kermit, "color", ["green", "aqua"]);
+		 *   success = store.setValues(kermit, "color", []);
+		 *   if (success) {assert(!store.hasAttribute(kermit, "color"));}
+		 */
+		dojo.unimplemented('dojo.data.core.Write.setValues');
+		return false; // boolean
+	},
+	
+	unsetAttribute: function(/* item */ item, /* attribute || string */ attribute) {
+		/* summary:
+		 *   Deletes all the values of an attribute on an item.
+		 */
+		 
+		/* exceptions:
+		 *   Throws an exception if *item* is not an item, or if *attribute*
+		 *   is neither an attribute object or a string.
+		 * examples:
+		 *   var success = store.unsetAttribute(kermit, "color");
+		 *   if (success) {assert(!store.hasAttribute(kermit, "color"));}
+		 */
+		dojo.unimplemented('dojo.data.core.Write.clear');
+		return false; // boolean
+	},
+	
+	save: function() {
+		/* summary:
+		 *   Saves to the server all the changes that have been made locally.
+		 *   The save operation may take some time.  By default the save will
+		 *   be done synchronously, before the call returns.  The caller may
+		 *   be request an asynchronous save by passing {async: true}.
+		 *   If the caller requests an asynchronous save, the data store may do
+		 *   either a synchronous or asynchronous save, whichever it prefers.
+		 *   Different data store implementations may take additional optional
+		 *   parameters.
+		 * description:
+		 * ISSUE - 
+		 *   Should the async save take a callback, like this:
+		 *     store.save({sync: false, onComplete: callback});
+		 *   Or should the async save return a Deferred, like this:
+		 *     var deferred = store.save({sync: false});
+		 *     deferred.addCallbacks(successCallback, errorCallback);
+		 *   Or should save() return boolean, like this:
+		 *     var success = store.save();
+		 */
+		 
+		/* examples:
+		 *   var success = store.save();
+		 *   var success = store.save({sync: false});
+		 */
+		dojo.unimplemented('dojo.data.core.Write.save');
+		return false; // boolean
+	},
+	
+	revert: function() {
+		/* summary:
+		 *   Discards any unsaved changes.
+		 */
+		 
+		/* examples:
+		 *   var success = store.revert();
+		 */
+		dojo.unimplemented('dojo.data.core.Write.revert');
+		return false; // boolean
+	},
+	
+	isDirty: function(/* item? */ item) {
+		/* summary:
+		 *   Given an item, isDirty() returns true if the item has been modified 
+		 *   since the last save().  If isDirty() is called with no *item* argument,  
+		 *   then this method returns true if any item has been modified since
+		 *   the last save().
+		 */
+		 
+		/* exceptions:
+		 *   Throws an exception if isDirty() is passed an argument and the
+		 *   argument is not an item.
+		 * examples:
+		 *   var trueOrFalse = store.isDirty(kermit); // true if kermit is dirty
+		 *   var trueOrFalse = store.isDirty();       // true if any item is dirty
+		 */
+		dojo.unimplemented('dojo.data.core.Write.isDirty');
+		return false; // boolean
+	}
+});

Added: incubator/xap/trunk/codebase/src/dojo/src/data/old/Attribute.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/old/Attribute.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/old/Attribute.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/old/Attribute.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,62 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.old.Attribute");
+dojo.require("dojo.data.old.Item");
+dojo.require("dojo.lang.assert");
+
+// -------------------------------------------------------------------
+// Constructor
+// -------------------------------------------------------------------
+dojo.data.old.Attribute = function(/* dojo.data.old.provider.Base */ dataProvider, /* string */ attributeId) {
+	/**
+	 * summary:
+	 * An Attribute object represents something like a column in 
+	 * a relational database.
+	 */
+	dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base, {optional: true});
+	dojo.lang.assertType(attributeId, String);
+	dojo.data.old.Item.call(this, dataProvider);
+	this._attributeId = attributeId;
+};
+dojo.inherits(dojo.data.old.Attribute, dojo.data.old.Item);
+
+// -------------------------------------------------------------------
+// Public instance methods
+// -------------------------------------------------------------------
+dojo.data.old.Attribute.prototype.toString = function() {
+	return this._attributeId; // string
+};
+
+dojo.data.old.Attribute.prototype.getAttributeId = function() {
+	/**
+	 * summary: 
+	 * Returns the string token that uniquely identifies this
+	 * attribute within the context of a data provider.
+	 * For a data provider that accesses relational databases,
+	 * typical attributeIds might be tokens like "name", "age", 
+	 * "ssn", or "dept_key".
+	 */ 
+	return this._attributeId; // string
+};
+
+dojo.data.old.Attribute.prototype.getType = function() {
+	/**
+	 * summary: Returns the data type of the values of this attribute.
+	 */ 
+	return this.get('type'); // dojo.data.old.Type or null
+};
+
+dojo.data.old.Attribute.prototype.setType = function(/* dojo.data.old.Type or null */ type) {
+	/**
+	 * summary: Sets the data type for this attribute.
+	 */ 
+	this.set('type', type);
+};

Added: incubator/xap/trunk/codebase/src/dojo/src/data/old/Item.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/old/Item.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/old/Item.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/old/Item.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,327 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.old.Item");
+dojo.require("dojo.data.old.Observable");
+dojo.require("dojo.data.old.Value");
+dojo.require("dojo.lang.common");
+dojo.require("dojo.lang.assert");
+
+// -------------------------------------------------------------------
+// Constructor
+// -------------------------------------------------------------------
+dojo.data.old.Item = function(/* dojo.data.old.provider.Base */ dataProvider) {
+	/**
+	 * summary:
+	 * An Item has attributes and attribute values, sort of like 
+	 * a record in a database, or a 'struct' in C.  Instances of
+	 * the Item class know how to store and retrieve their
+	 * attribute values.
+	 */
+	dojo.lang.assertType(dataProvider, dojo.data.old.provider.Base, {optional: true});
+	dojo.data.old.Observable.call(this);
+	this._dataProvider = dataProvider;
+	this._dictionaryOfAttributeValues = {};
+};
+dojo.inherits(dojo.data.old.Item, dojo.data.old.Observable);
+
+// -------------------------------------------------------------------
+// Public class methods
+// -------------------------------------------------------------------
+dojo.data.old.Item.compare = function(/* dojo.data.old.Item */ itemOne, /* dojo.data.old.Item */ itemTwo) {
+	/**
+	 * summary:
+	 * Given two Items to compare, this method returns 0, 1, or -1.
+	 * This method is designed to be used by sorting routines, like
+	 * the JavaScript built-in Array sort() method.
+	 * 
+	 * Example:
+	 * <pre>
+	 *   var a = dataProvider.newItem("kermit");
+	 *   var b = dataProvider.newItem("elmo");
+	 *   var c = dataProvider.newItem("grover");
+	 *   var array = new Array(a, b, c);
+	 *   array.sort(dojo.data.old.Item.compare);
+	 * </pre>
+	 */
+	dojo.lang.assertType(itemOne, dojo.data.old.Item);
+	if (!dojo.lang.isOfType(itemTwo, dojo.data.old.Item)) {
+		return -1;
+	}
+	var nameOne = itemOne.getName();
+	var nameTwo = itemTwo.getName();
+	if (nameOne == nameTwo) {
+		var attributeArrayOne = itemOne.getAttributes();
+		var attributeArrayTwo = itemTwo.getAttributes();
+		if (attributeArrayOne.length != attributeArrayTwo.length) {
+			if (attributeArrayOne.length > attributeArrayTwo.length) {
+				return 1; 
+			} else {
+				return -1;
+			}
+		}
+		for (var i in attributeArrayOne) {
+			var attribute = attributeArrayOne[i];
+			var arrayOfValuesOne = itemOne.getValues(attribute);
+			var arrayOfValuesTwo = itemTwo.getValues(attribute);
+			dojo.lang.assert(arrayOfValuesOne && (arrayOfValuesOne.length > 0));
+			if (!arrayOfValuesTwo) {
+				return 1;
+			}
+			if (arrayOfValuesOne.length != arrayOfValuesTwo.length) {
+				if (arrayOfValuesOne.length > arrayOfValuesTwo.length) {
+					return 1; 
+				} else {
+					return -1;
+				}
+			}
+			for (var j in arrayOfValuesOne) {
+				var value = arrayOfValuesOne[j];
+				if (!itemTwo.hasAttributeValue(value)) {
+					return 1;
+				}
+			}
+			return 0;
+		}
+	} else {
+		if (nameOne > nameTwo) {
+			return 1; 
+		} else {
+			return -1;  // 0, 1, or -1
+		}
+	}
+};
+
+// -------------------------------------------------------------------
+// Public instance methods
+// -------------------------------------------------------------------
+dojo.data.old.Item.prototype.toString = function() {
+	/**
+	 * Returns a simple string representation of the item.
+	 */
+	var arrayOfStrings = [];
+	var attributes = this.getAttributes();
+	for (var i in attributes) {
+		var attribute = attributes[i];
+		var arrayOfValues = this.getValues(attribute);
+		var valueString;
+		if (arrayOfValues.length == 1) {
+			valueString = arrayOfValues[0];
+		} else {
+			valueString = '[';
+			valueString += arrayOfValues.join(', ');
+			valueString += ']';
+		}
+		arrayOfStrings.push('  ' + attribute + ': ' + valueString);
+	}
+	var returnString = '{ ';
+	returnString += arrayOfStrings.join(',\n');
+	returnString += ' }';
+	return returnString; // string
+};
+
+dojo.data.old.Item.prototype.compare = function(/* dojo.data.old.Item */ otherItem) {
+	/**
+	 * summary: Compares this Item to another Item, and returns 0, 1, or -1.
+	 */ 
+	return dojo.data.old.Item.compare(this, otherItem); // 0, 1, or -1
+};
+
+dojo.data.old.Item.prototype.isEqual = function(/* dojo.data.old.Item */ otherItem) {
+	/**
+	 * summary: Returns true if this Item is equal to the otherItem, or false otherwise.
+	 */
+	return (this.compare(otherItem) == 0); // boolean
+};
+
+dojo.data.old.Item.prototype.getName = function() {
+	return this.get('name');
+};
+
+dojo.data.old.Item.prototype.get = function(/* string or dojo.data.old.Attribute */ attributeId) {
+	/**
+	 * summary: Returns a single literal value, like "foo" or 33.
+	 */ 
+	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
+	var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
+	if (dojo.lang.isUndefined(literalOrValueOrArray)) {
+		return null; // null
+	}
+	if (literalOrValueOrArray instanceof dojo.data.old.Value) {
+		return literalOrValueOrArray.getValue(); // literal
+	}
+	if (dojo.lang.isArray(literalOrValueOrArray)) {
+		var dojoDataValue = literalOrValueOrArray[0];
+		return dojoDataValue.getValue(); // literal
+	}
+	return literalOrValueOrArray; // literal
+};
+
+dojo.data.old.Item.prototype.getValue = function(/* string or dojo.data.old.Attribute */ attributeId) {
+	/**
+	 * summary: Returns a single instance of dojo.data.old.Value.
+	 */ 
+	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
+	var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
+	if (dojo.lang.isUndefined(literalOrValueOrArray)) {
+		return null; // null
+	}
+	if (literalOrValueOrArray instanceof dojo.data.old.Value) {
+		return literalOrValueOrArray; // dojo.data.old.Value
+	}
+	if (dojo.lang.isArray(literalOrValueOrArray)) {
+		var dojoDataValue = literalOrValueOrArray[0];
+		return dojoDataValue; // dojo.data.old.Value
+	}
+	var literal = literalOrValueOrArray;
+	dojoDataValue = new dojo.data.old.Value(literal);
+	this._dictionaryOfAttributeValues[attributeId] = dojoDataValue;
+	return dojoDataValue; // dojo.data.old.Value
+};
+
+dojo.data.old.Item.prototype.getValues = function(/* string or dojo.data.old.Attribute */ attributeId) {
+	/**
+	 * summary: Returns an array of dojo.data.old.Value objects.
+	 */ 
+	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
+	var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
+	if (dojo.lang.isUndefined(literalOrValueOrArray)) {
+		return null; // null
+	}
+	if (literalOrValueOrArray instanceof dojo.data.old.Value) {
+		var array = [literalOrValueOrArray];
+		this._dictionaryOfAttributeValues[attributeId] = array;
+		return array; // Array
+	}
+	if (dojo.lang.isArray(literalOrValueOrArray)) {
+		return literalOrValueOrArray; // Array
+	}
+	var literal = literalOrValueOrArray;
+	var dojoDataValue = new dojo.data.old.Value(literal);
+	array = [dojoDataValue];
+	this._dictionaryOfAttributeValues[attributeId] = array;
+	return array; // Array
+};
+
+dojo.data.old.Item.prototype.load = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
+	/**
+	 * summary: 
+	 * Used for loading an attribute value into an item when
+	 * the item is first being loaded into memory from some
+	 * data store (such as a file).
+	 */ 
+	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
+	this._dataProvider.registerAttribute(attributeId);
+	var literalOrValueOrArray = this._dictionaryOfAttributeValues[attributeId];
+	if (dojo.lang.isUndefined(literalOrValueOrArray)) {
+		this._dictionaryOfAttributeValues[attributeId] = value;
+		return;
+	}
+	if (!(value instanceof dojo.data.old.Value)) {
+		value = new dojo.data.old.Value(value);
+	}
+	if (literalOrValueOrArray instanceof dojo.data.old.Value) {
+		var array = [literalOrValueOrArray, value];
+		this._dictionaryOfAttributeValues[attributeId] = array;
+		return;
+	}
+	if (dojo.lang.isArray(literalOrValueOrArray)) {
+		literalOrValueOrArray.push(value);
+		return;
+	}
+	var literal = literalOrValueOrArray;
+	var dojoDataValue = new dojo.data.old.Value(literal);
+	array = [dojoDataValue, value];
+	this._dictionaryOfAttributeValues[attributeId] = array;
+};
+
+dojo.data.old.Item.prototype.set = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
+	/**
+	 * summary: 
+	 * Used for setting an attribute value as a result of a
+	 * user action.
+	 */ 
+	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
+	this._dataProvider.registerAttribute(attributeId);
+	this._dictionaryOfAttributeValues[attributeId] = value;
+	this._dataProvider.noteChange(this, attributeId, value);
+};
+
+dojo.data.old.Item.prototype.setValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* dojo.data.old.Value */ value) {
+	this.set(attributeId, value);
+};
+
+dojo.data.old.Item.prototype.addValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
+	/**
+	 * summary: 
+	 * Used for adding an attribute value as a result of a
+	 * user action.
+	 */ 
+	this.load(attributeId, value);
+	this._dataProvider.noteChange(this, attributeId, value);
+};
+
+dojo.data.old.Item.prototype.setValues = function(/* string or dojo.data.old.Attribute */ attributeId, /* Array */ arrayOfValues) {
+	/**
+	 * summary: 
+	 * Used for setting an array of attribute values as a result of a
+	 * user action.
+	 */
+	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
+	dojo.lang.assertType(arrayOfValues, Array);
+	this._dataProvider.registerAttribute(attributeId);
+	var finalArray = [];
+	this._dictionaryOfAttributeValues[attributeId] = finalArray;
+	for (var i in arrayOfValues) {
+		var value = arrayOfValues[i];
+		if (!(value instanceof dojo.data.old.Value)) {
+			value = new dojo.data.old.Value(value);
+		}
+		finalArray.push(value);
+		this._dataProvider.noteChange(this, attributeId, value);
+	}
+};
+
+dojo.data.old.Item.prototype.getAttributes = function() {
+	/**
+	 * summary: 
+	 * Returns an array containing all of the attributes for which
+	 * this item has attribute values.
+	 */ 
+	var arrayOfAttributes = [];
+	for (var key in this._dictionaryOfAttributeValues) {
+		arrayOfAttributes.push(this._dataProvider.getAttribute(key));
+	}
+	return arrayOfAttributes; // Array
+};
+
+dojo.data.old.Item.prototype.hasAttribute = function(/* string or dojo.data.old.Attribute */ attributeId) {
+	/**
+	 * summary: Returns true if the given attribute of the item has been assigned any value.
+	 */ 
+	// dojo.lang.assertType(attributeId, [String, dojo.data.old.Attribute]);
+	return (attributeId in this._dictionaryOfAttributeValues); // boolean
+};
+
+dojo.data.old.Item.prototype.hasAttributeValue = function(/* string or dojo.data.old.Attribute */ attributeId, /* anything */ value) {
+	/**
+	 * summary: Returns true if the given attribute of the item has been assigned the given value.
+	 */ 
+	var arrayOfValues = this.getValues(attributeId);
+	for (var i in arrayOfValues) {
+		var candidateValue = arrayOfValues[i];
+		if (candidateValue.isEqual(value)) {
+			return true; // boolean
+		}
+	}
+	return false; // boolean
+};
+
+

Added: incubator/xap/trunk/codebase/src/dojo/src/data/old/Kind.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/old/Kind.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/old/Kind.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/old/Kind.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,28 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.old.Kind");
+dojo.require("dojo.data.old.Item");
+
+// -------------------------------------------------------------------
+// Constructor
+// -------------------------------------------------------------------
+dojo.data.old.Kind = function(/* dojo.data.old.provider.Base */ dataProvider) {
+	/**
+	 * summary:
+	 * A Kind represents a kind of item.  In the dojo data model
+	 * the item Snoopy might belong to the 'kind' Dog, where in
+	 * a Java program the object Snoopy would belong to the 'class'
+	 * Dog, and in MySQL the record for Snoopy would be in the 
+	 * table Dog.
+	 */
+	dojo.data.old.Item.call(this, dataProvider);
+};
+dojo.inherits(dojo.data.old.Kind, dojo.data.old.Item);

Added: incubator/xap/trunk/codebase/src/dojo/src/data/old/Observable.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/data/old/Observable.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/data/old/Observable.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/data/old/Observable.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,59 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.data.old.Observable");
+dojo.require("dojo.lang.common");
+dojo.require("dojo.lang.assert");
+
+// -------------------------------------------------------------------
+// Constructor
+// -------------------------------------------------------------------
+dojo.data.old.Observable = function() {
+};
+
+// -------------------------------------------------------------------
+// Public instance methods
+// -------------------------------------------------------------------
+dojo.data.old.Observable.prototype.addObserver = function(/* object */ observer) {
+	/**
+	 * summary: Registers an object as an observer of this item,
+	 * so that the object will be notified when the item changes.
+	 */ 
+	dojo.lang.assertType(observer, Object);
+	dojo.lang.assertType(observer.observedObjectHasChanged, Function);
+	if (!this._arrayOfObservers) {
+		this._arrayOfObservers = [];
+	}
+	if (!dojo.lang.inArray(this._arrayOfObservers, observer)) {
+		this._arrayOfObservers.push(observer);
+	}
+};
+
+dojo.data.old.Observable.prototype.removeObserver = function(/* object */ observer) {
+	/**
+	 * summary: Removes the observer registration for a previously
+	 * registered object.
+	 */ 
+	if (!this._arrayOfObservers) {
+		return;
+	}
+	var index = dojo.lang.indexOf(this._arrayOfObservers, observer);
+	if (index != -1) {
+		this._arrayOfObservers.splice(index, 1);
+	}
+};
+
+dojo.data.old.Observable.prototype.getObservers = function() {
+	/**
+	 * summary: Returns an array with all the observers of this item.
+	 */ 
+	return this._arrayOfObservers; // Array or undefined
+};
+



Mime
View raw message