You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2014/02/13 15:20:52 UTC
[08/51] [abbrv] git commit: Base classes for refactor: Logger, Promise,
Ajax, Request, Response, Error
Base classes for refactor: Logger, Promise, Ajax, Request, Response, Error
Project: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/commit/79b22941
Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/79b22941
Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/79b22941
Branch: refs/heads/two-dot-o
Commit: 79b2294161c524923c05e9ba2d23d624205217a0
Parents: 4245f53
Author: ryan bridges <rb...@apigee.com>
Authored: Mon Feb 3 18:21:37 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Mon Feb 3 18:21:37 2014 -0500
----------------------------------------------------------------------
sdks/html5-javascript/lib/Usergrid.js | 612 ++++++++++++++++++++++++++---
1 file changed, 560 insertions(+), 52 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/79b22941/sdks/html5-javascript/lib/Usergrid.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Usergrid.js b/sdks/html5-javascript/lib/Usergrid.js
index 1da4241..5e6e3f1 100644
--- a/sdks/html5-javascript/lib/Usergrid.js
+++ b/sdks/html5-javascript/lib/Usergrid.js
@@ -1,9 +1,9 @@
/*
* This module is a collection of classes designed to make working with
* the Appigee App Services API as easy as possible.
- * Learn more at http://apigee.com/docs/usergrid
+ * Learn more at http://Usergrid.com/docs/usergrid
*
- * Copyright 2012 Apigee Corporation
+ * Copyright 2012 Usergrid Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,9 +17,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- * @author rod simpson (rod@apigee.com)
- * @author matt dobson (matt@apigee.com)
- * @author ryan bridges (rbridges@apigee.com)
+ * @author rod simpson (rod@Usergrid.com)
+ * @author matt dobson (matt@Usergrid.com)
+ * @author ryan bridges (rbridges@Usergrid.com)
*/
@@ -28,9 +28,9 @@ window.console = window.console || {};
window.console.log = window.console.log || function() {};
//Usergrid namespace encapsulates this SDK
-window.Usergrid = window.Usergrid || {};
+/*window.Usergrid = window.Usergrid || {};
Usergrid = Usergrid || {};
-Usergrid.USERGRID_SDK_VERSION = '0.10.07';
+Usergrid.USERGRID_SDK_VERSION = '0.10.07';*/
/*
@@ -43,10 +43,7 @@ Usergrid.USERGRID_SDK_VERSION = '0.10.07';
*/
var uuidValueRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
function isUUID(uuid) {
- if (!uuid) {
- return false;
- }
- return uuidValueRegex.test(uuid);
+ return (!uuid)?false:uuidValueRegex.test(uuid);
}
/*
@@ -58,32 +55,32 @@ function isUUID(uuid) {
* @return {string} Returns the encoded string
*/
function encodeParams(params) {
- var tail = [];
- var item = [];
- var i;
- if (params instanceof Array) {
- for (i in params) {
- item = params[i];
- if ((item instanceof Array) && (item.length > 1)) {
- tail.push(item[0] + "=" + encodeURIComponent(item[1]));
- }
- }
- } else {
- for (var key in params) {
- if (params.hasOwnProperty(key)) {
- var value = params[key];
- if (value instanceof Array) {
- for (i in value) {
- item = value[i];
- tail.push(key + "=" + encodeURIComponent(item));
- }
- } else {
- tail.push(key + "=" + encodeURIComponent(value));
- }
- }
- }
- }
- return tail.join("&");
+ var tail = [];
+ var item = [];
+ var i;
+ if (params instanceof Array) {
+ for (i in params) {
+ item = params[i];
+ if ((item instanceof Array) && (item.length > 1)) {
+ tail.push(item[0] + "=" + encodeURIComponent(item[1]));
+ }
+ }
+ } else {
+ for (var key in params) {
+ if (params.hasOwnProperty(key)) {
+ var value = params[key];
+ if (value instanceof Array) {
+ for (i in value) {
+ item = value[i];
+ tail.push(key + "=" + encodeURIComponent(item));
+ }
+ } else {
+ tail.push(key + "=" + encodeURIComponent(value));
+ }
+ }
+ }
+ }
+ return tail.join("&");
}
/*
@@ -95,7 +92,7 @@ function encodeParams(params) {
* @return {boolean} Returns true or false
*/
function isFunction(f) {
- return (f && f !== null && typeof(f) === 'function');
+ return (f && f !== null && typeof(f) === 'function');
}
/*
@@ -109,18 +106,529 @@ function isFunction(f) {
* @return Returns whatever would be returned by the callback. or false.
*/
function doCallback(callback, params, context) {
- var returnValue;
- if (isFunction(callback)) {
- if (!params) params = [];
- if (!context) context = this;
- params.push(context);
- try {
- returnValue = callback.apply(context, params);
- } catch (ex) {
- if (console && console.error) {
- console.error("Callback error:", ex);
- }
- }
- }
- return returnValue;
+ var returnValue;
+ if (isFunction(callback)) {
+ if (!params) params = [];
+ if (!context) context = this;
+ params.push(context);
+ try {
+ returnValue = callback.apply(context, params);
+ } catch (ex) {
+ if (console && console.error) {
+ console.error("Callback error:", ex);
+ }
+ }
+ }
+ return returnValue;
}
+
+Function.prototype.extend = function(superClass) {
+ var subClass=this,F = function() {};
+ F.prototype = superClass.prototype;
+ subClass.prototype = new F();
+ subClass.prototype.constructor = subClass;
+
+ subClass.superclass = superClass.prototype;
+ if(superClass.prototype.constructor == Object.prototype.constructor) {
+ superClass.prototype.constructor = superClass;
+ }
+ return subClass;
+}
+//Logger
+(function() {
+ var name = 'Logger', global = this, overwrittenName = global[name], exports;
+ /* logging */
+ exports = (function() {
+ function Logger(name) {
+ function tr(m) {
+ return {
+ 'E': 'End',
+ '%': 'group',
+ '#': 'profile',
+ '!': 'time'
+ }[m];
+ }
+ var logEnabled = true,
+ methods = "log error warn info debug assert clear count dir dirxml exception % %Collapsed %E # #E table ! !E trace".replace(/([E%#!])/g, tr).split(' '),
+ con = window.console;
+ if(!name){
+ name="UNKNOWN";
+ }
+ function createLogMethod(method) {
+ return function() {
+ var args=[].slice.call(arguments);
+ var prepend='['+method.toUpperCase()+']['+name+']:';
+ if("string"===typeof args[0]){
+ args[0]=prepend+args[0];
+ }else{
+ args.unshift(prepend);
+ }
+ logEnabled && con && con[method] && con[method].apply(con, args);
+ }
+ }
+ for (var i = 0; i < methods.length; i++) {
+ var method = methods[i];
+ this[method] = createLogMethod(method);
+ }
+ }
+ return Logger;
+ }());
+
+ global[name] = exports;
+ global[name].noConflict = function() {
+ if(overwrittenName){
+ global[name] = overwrittenName;
+ }
+ return exports;
+ };
+ return global[name];
+}());
+//Promise
+(function() {
+ var name = 'Promise', global = this, overwrittenName = global[name], exports;
+
+ exports = (function(global) {
+ function Promise() {
+ this.complete = false;
+ this.error = null;
+ this.result = null;
+ this.callbacks = [];
+ }
+ Promise.prototype.create = function() {
+ return new Promise()
+ };
+ Promise.prototype.then = function(callback, context) {
+ var f = function() {
+ return callback.apply(context, arguments)
+ };
+ if (this.complete) {
+ f(this.error, this.result);
+ } else {
+ this.callbacks.push(f);
+ }
+ };
+ Promise.prototype.done = function(error, result) {
+ this.complete = true;
+ this.error = error;
+ this.result = result;
+ for (var i = 0; i < this.callbacks.length; i++) this.callbacks[i](error, result);
+ this.callbacks.length = 0;
+ };
+ Promise.join = function(promises) {
+ var p = new Promise(),
+ total = promises.length,
+ completed = 0,
+ errors = [],
+ results = [];
+
+ function notifier(i) {
+ return function(error, result) {
+ completed += 1;
+ errors[i] = error;
+ results[i] = result;
+ if (completed === total) {
+ p.done(errors, results);
+ }
+ };
+ }
+ for (var i = 0; i < total; i++) {
+ promises[i]().then(notifier(i));
+ }
+ return p;
+ };
+ Promise.chain = function(promises, error, result) {
+ var p = new Promise();
+ if (promises===null||promises.length === 0) {
+ p.done(error, result);
+ } else {
+ promises[0](error, result).then(function(res, err) {
+ promises.splice(0, 1);
+ //self.logger.info(promises.length)
+ if(promises){
+ Promise.chain(promises, res, err).then(function(r, e) {
+ p.done(r, e);
+ });
+ }else{
+ p.done(res, err);
+ }
+ });
+ }
+ return p;
+ };
+ return Promise;
+ }(window));
+
+
+ global[name] = exports;
+ global[name].noConflict = function() {
+ if(overwrittenName){
+ global[name] = overwrittenName;
+ }
+ return exports;
+ };
+ return global[name];
+}());
+//Ajax
+(function() {
+ var name = 'Ajax', global = this, overwrittenName = global[name], exports;
+
+ Function.prototype.partial = function() {
+ var fn = this,
+ b = [].slice.call(arguments);
+ return function() {
+ return fn.apply(this, b.concat([].slice.call(arguments)))
+ }
+ }
+
+ exports = (function() {
+ function Ajax() {
+ this.logger=new global.Logger(name);
+ var self=this;
+ function encode(data) {
+ var result = "";
+ if (typeof data === "string") {
+ result = data;
+ } else {
+ var e = encodeURIComponent;
+ for (var i in data) {
+ if (data.hasOwnProperty(i)) {
+ result += '&' + e(i) + '=' + e(data[i]);
+ }
+ }
+ }
+ return result;
+ }
+ var request = function(m, u, d) {
+ var p = new Promise();
+ (function(xhr) {
+ xhr.onreadystatechange = function() {
+ this.readyState ^ 4 || (self.logger.timeEnd(m + ' ' + u), p.done(null, this));
+ };
+ xhr.onerror=function(response){
+ p.done(response, null);
+ }
+ xhr.onecomplete=function(response){
+ self.info("%s request to %s returned %s", m, u, this.status );
+ }
+ xhr.open(m, u);
+ self.logger.time(m + ' ' + u);
+ xhr.send(encode(d));
+ }(new XMLHttpRequest()));
+ return p;
+ };
+ this.request=request;
+ this.get = request.partial('GET');
+ this.post = request.partial('POST');
+ this.put = request.partial('PUT');
+ this.delete = request.partial('DELETE');
+ }
+ return new Ajax();
+ }());
+
+ global[name] = exports;
+ global[name].noConflict = function() {
+ if(overwrittenName){
+ global[name] = overwrittenName;
+ }
+ return exports;
+ };
+ return global[name];
+}());
+//KeyStore
+(function() {
+ var name = 'KeyStore', global = this, overwrittenName = global[name], exports;
+
+ exports = (function() {
+ global.indexedDB = global.indexedDB || global.mozIndexedDB || global.webkitIndexedDB || global.msIndexedDB;
+ // (Mozilla has never prefixed these objects, so we don't need global.mozIDB*)
+ global.IDBTransaction = global.IDBTransaction || global.webkitIDBTransaction || global.msIDBTransaction;
+ global.IDBKeyRange = global.IDBKeyRange || global.webkitIDBKeyRange || global.msIDBKeyRange;
+
+ function KeyStore(database, version, storeName, keyPath, callback) {
+ this.logger=new global.Logger(name);
+ this.db = null;
+ this.error = null;
+ this.ready = false;
+ this.storeName = storeName;
+ this.keyPath = keyPath;
+ var self = this;
+ var request = indexedDB.open(database, version);
+
+ function useDatabase(db, callback) {
+ db.onversionchange = function(event) {
+ db.close();
+ console.warn("A new version of this keystore has been loaded. Please restart your application!");
+ };
+ self.db = db;
+ self.ready = true;
+ isFunction(callback) && callback(null, self);
+ }
+ request.onerror = function(event) {
+ console.error("internal keystore error: " + event.target.errorCode);
+ self.ready = true;
+ self.error = event.target;
+ isFunction(callback) && callback(event.target, self);
+ };
+ request.onupgradeneeded = function(event) {
+ console.warn("upgrading internal keystore");
+ var db = event.target.result;
+ var objectStore, index;
+ try {
+ objectStore = event.currentTarget.transaction.objectStore(self.storeName);
+ //console.log(objectStore);
+ if (!objectStore) throw "not found";
+ } catch (e) {
+ objectStore = db.createObjectStore(self.storeName, {
+ keyPath: self.keyPath
+ });
+ } finally {
+ objectStore.transaction.oncomplete = function(event) {
+ console.info("created ObjectStore: '%s'", self.storeName);
+ //useDatabase(db, callback);
+ };
+ }
+ try {
+ index = objectStore.index(self.keyPath);
+ if (!index) throw "not found";
+ } catch (e) {
+ objectStore.createIndex(self.keyPath, self.keyPath, {
+ unique: true
+ });
+ } finally {
+ objectStore.transaction.oncomplete = function(event) {
+ console.info("created ObjectStore index: '%s'", self.keyPath);
+ //useDatabase(db, callback);
+ };
+ }
+ };
+ request.onsuccess = function(event) {
+ console.info("successfully opened database %s", event.target.result);
+ useDatabase(event.target.result, callback);
+ };
+ }
+ KeyStore.prototype.delete = function(key, callback) {
+ var transaction = this.db.transaction([this.storeName], "readwrite");
+ var objectStore = transaction.objectStore(this.storeName);
+ var item = objectStore.get(key);
+ item.onsuccess = function(event) {
+ objectStore.delete(key);
+ isFunction(callback) && callback(null, key);
+ };
+ item.onerror = function(event) {
+ console.warn("Attempt to delete nonexistent item from keystore: %s", key);
+ isFunction(callback) && callback(null, key);
+ };
+ };
+
+ KeyStore.prototype.get = function(key, callback) {
+ var transaction = this.db.transaction([this.storeName], "readwrite");
+ var objectStore = transaction.objectStore(this.storeName);
+ var item = objectStore.get(key);
+ item.onsuccess = function(event) {
+ console.log(event.target.result);
+ isFunction(callback) && callback(null, event.target.result ? event.target.result.value : null);
+ };
+ item.onerror = function(event) {
+ isFunction(callback) && callback(event.target, event.target.result ? event.target.result.value : null);
+ };
+ };
+
+ KeyStore.prototype.set = function(key, value, callback) {
+ var transaction = this.db.transaction([this.storeName], "readwrite");
+ var objectStore = transaction.objectStore(this.storeName);
+ var data = {
+ 'key': key,
+ 'value': value
+ };
+ var item = objectStore.get(key);
+ item.onsuccess = function(event) {
+ data.created = (event.target.result) ? event.target.result.created : Date.now();
+ data.modified = Date.now();
+ objectStore.delete(key);
+ objectStore.add(data).onsuccess = function(event) {
+ //event.target.result is the 'key'
+ console.info("KEYSTORE: update %s=%s", data.key, data.value);
+ isFunction(callback) && callback(null, data.value);
+ };
+ };
+ item.onerror = function(event) {
+ data.created = Date.now();
+ data.modified = Date.now();
+ objectStore.add(data).onsuccess = function(event) {
+ console.info("KEYSTORE: create %s=%s", data.key = data.value);
+ isFunction(callback) && callback(null, data);
+ };
+ };
+ };
+ return KeyStore;
+ }());
+
+ global[name] = exports;
+ global[name].noConflict = function() {
+ if(overwrittenName){
+ global[name] = overwrittenName;
+ }
+ return exports;
+ };
+ return global[name];
+}());
+(function() {
+ var name = 'Usergrid', global = this, overwrittenName = global[name], exports;
+
+ exports = (function() {
+ function Usergrid(){
+ this.logger=new global.Logger(name);
+ var self=this;
+ this.keyStore=new KeyStore('usergrid-javascript-sdk', 2, "data", "key", function(err, ks){
+ self.logger.info("'%s' keystore created.", 'usergrid-javascript-sdk');
+ });
+ }
+ Usergrid.isValidEndpoint = function(endpoint) {
+ //TODO actually implement this
+ return true;
+ };
+ Usergrid.prototype.set = function(key, value, callback) {
+ if ("object" === typeof value) {
+ try {
+ value = JSON.stringify(value);
+ } catch (e) {
+ self.logger.warn("unable to stringify object: %s", e.message, value);
+ }
+ }
+ this[key] = value;
+ if ("undefined" !== typeof this.keyStore) {
+ if (value) {
+ this.keyStore.set(key, value, callback);
+ } else {
+ this.keyStore.delete(key, callback);
+ }
+ }else{
+ callback.apply(this, [null, null]);
+ }
+ };
+
+ Usergrid.prototype.get = function(key, callback) {
+ var keyStore = keyPrefix + key,
+ value;
+ if ("undefined" !== typeof this.keyStore) {
+ this.keyStore.get(key, callback);
+ }
+ try {
+ if (/^(\{|\[)/.test(value)) {
+ value = JSON.parse(value);
+ }
+ } catch (e) {
+ self.logger.warn("unable to parse object: %s", e.message, value);
+ } finally {
+
+ }
+ return value;
+ };
+ var VALID_REQUEST_METHODS=['GET','POST','PUT','DELETE'];
+ Usergrid.Request=function(method, endpoint, query_params, data, callback){
+ var p = new Promise();
+ this.method=method.toUpperCase();
+ this.endpoint=endpoint;
+ this.query_params=query_params;
+ this.data=data;
+ this.logger=new global.Logger("Usergrid.Request");
+ var self=this;
+ if(VALID_REQUEST_METHODS.indexOf(this.method)===-1){
+ throw "invalid request method '"+this.method+"'";
+ }
+ if(!Usergrid.isValidEndpoint(this.endpoint)){
+ throw "The provided endpoint is not valid: "+this.endpoint;
+ }
+ var encoded_params = encodeParams(this.query_params);
+ if (encoded_params) {
+ this.endpoint += "?" + encoded_params;
+ }
+ Ajax.request(this.method, this.endpoint, this.data).then(function(err, request){
+ //TODO create Usergrid.Response object
+ var response=new Usergrid.Response(request.responseText);
+ if(err){
+ callback(new Usergrid.Error(err), null);
+ }else if (response.data.error){
+ callback(new Usergrid.Error(response.data), null);
+ }else{
+ callback(null, response);
+ }
+ });
+ };
+
+
+
+ Usergrid.Response=function(response_data){
+ this.text=response_data;
+ this.logger=new global.Logger(name);
+ var self=this;
+ try{
+ this.data=JSON.parse(this.text);
+ }catch(e){
+ this.logger.error("Error parsing response text: ",this.text);
+ this.data=null;
+ }
+ };
+
+ Usergrid.Error=function(options){
+ this.name="UsergridError";
+ this.timestamp=Date.now();
+ if(options instanceof Error){
+ this.exception=options.name||"";
+ this.message=options.message||"An error has occurred";
+ }else if("object"===typeof options){
+ this.exception=options.error||"unknown_error";
+ this.message=options.error_description||"An error has occurred";
+ }else if("string"===typeof options){
+ this.exception="unknown_error";
+ this.message=options||"An error has occurred";
+ }
+ }
+ Usergrid.Error.prototype=new Error();
+
+ Usergrid.Client=function(){};
+ Usergrid.Entity=function(){};
+ Usergrid.Collection=function(){};
+ return Usergrid;
+ }());
+ //TODO create keystore interface (Function.length)
+
+
+ //define a key prefix for our storage object keys
+ /*Object.defineProperty(this, "keyPrefix", {
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ value: "apigee_"
+ });*/
+
+ global[name] = exports;
+ global[name].noConflict = function() {
+ if(overwrittenName){
+ global[name] = overwrittenName;
+ }
+ return exports;
+ };
+ return global[name];
+}());
+/*(function(global, storage) {
+ var name = 'Usergrid', overwrittenName = global[name];
+ var Usergrid=Usergrid||global.Usergrid;
+
+ global[name] = {
+ Request : Usergrid.Request,
+ Response : Usergrid.Response,
+ Error : Usergrid.Error,
+ Client : Usergrid.Client,
+ Entity : Usergrid.Entity,
+ Collection : Usergrid.Collection,
+ version : '0.10.07'
+ };
+ global[name].noConflict = function() {
+ if(overwrittenName){
+ global[name] = overwrittenName;
+ }
+ return Usergrid;
+ };
+ return global[name];
+}(this, localStorage));*/