Commit a9caa60c authored by Tristan Cavelier's avatar Tristan Cavelier

Redesigning jio in order to improve security and extensibility.

parent 4003ab14
...@@ -14,7 +14,39 @@ module.exports = function(grunt) { ...@@ -14,7 +14,39 @@ module.exports = function(grunt) {
concat: { concat: {
dist: { dist: {
src: ['<banner:meta.banner>', src: ['<banner:meta.banner>',
'<file_strip_banner:../../src/<%= pkg.name %>.js>'], // Wrapper top
'<file_strip_banner:../../src/<%= pkg.name %>/wrapper.top.js>',
// Classes
'<file_strip_banner:../../src/<%= pkg.name %>/commands/command.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/commands/getDocumentList.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/commands/loadDocument.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/commands/removeDocument.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/commands/saveDocument.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/exceptions.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/jobs/status/jobStatus.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/jobs/status/doneStatus.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/jobs/status/failStatus.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/jobs/status/initialStatus.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/jobs/status/onGoingStatus.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/jobs/status/waitStatus.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/storages/storage.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/storages/storageHandler.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/activityUpdater.js>',
// Jio wrapper top
'<file_strip_banner:../../src/<%= pkg.name %>/jio.top.js>',
// Jio Classes
'<file_strip_banner:../../src/<%= pkg.name %>/jobs/job.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/announcements/announcement.js>',
// Singletons
'<file_strip_banner:../../src/<%= pkg.name %>/announcements/announcer.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/jobs/jobIdHandler.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/jobs/jobManager.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/jobs/jobRules.js>',
// Jio wrappor bottem
'<file_strip_banner:../../src/<%= pkg.name %>/jio.bottom.js>',
'<file_strip_banner:../../src/<%= pkg.name %>/jioNamespace.js>',
// Wrapper bottom
'<file_strip_banner:../../src/<%= pkg.name %>/wrapper.bottom.js>'],
dest: '../../lib/jio/<%= pkg.name %>.js' dest: '../../lib/jio/<%= pkg.name %>.js'
} }
}, },
...@@ -25,17 +57,17 @@ module.exports = function(grunt) { ...@@ -25,17 +57,17 @@ module.exports = function(grunt) {
} }
}, },
qunit: { qunit: {
files: ['../../test/jiotests.html', files: [// '../../test/jiotests.html',
'../../test/jiotests_withoutrequirejs.html'] '../../test/jiotests_withoutrequirejs.html']
}, },
lint: { lint: {
files: ['grunt.js', files: ['grunt.js',
'../../src/<%= pkg.name %>.js', '../../lib/jio/<%= pkg.name %>.js']
'../../js/base64.requirejs_module.js', // '../../js/base64.requirejs_module.js',
'../../src/jio.dummystorages.js', // '../../src/jio.dummystorages.js',
'../../js/jquery.requirejs_module.js', // '../../js/jquery.requirejs_module.js',
'../../test/jiotests.js', // '../../test/jiotests.js',
'../../test/jiotests.loader.js'] // '../../test/jiotests.loader.js']
}, },
watch: { watch: {
files: '<config:lint.files>', files: '<config:lint.files>',
...@@ -60,7 +92,6 @@ module.exports = function(grunt) { ...@@ -60,7 +92,6 @@ module.exports = function(grunt) {
sjcl:true, sjcl:true,
LocalOrCookieStorage: true, LocalOrCookieStorage: true,
Base64: true, Base64: true,
JIO: true,
console: true, console: true,
unescape: true, unescape: true,
// Needed to avoid "not defined error" with requireJs // Needed to avoid "not defined error" with requireJs
...@@ -82,6 +113,6 @@ module.exports = function(grunt) { ...@@ -82,6 +113,6 @@ module.exports = function(grunt) {
}); });
// Default task. // Default task.
grunt.registerTask('default', 'lint qunit concat min'); grunt.registerTask('default', 'concat min lint qunit');
}; };
/*! JIO - v0.1.0 - 2012-06-05 /*! JIO - v0.1.0 - 2012-06-11
* Copyright (c) 2012 Nexedi; Licensed */ * Copyright (c) 2012 Nexedi; Licensed */
var JIO = var jio = (function () {
(function () { var jioLoaderFunction = function ( localOrCookieStorage, $ ) {
var command = function(spec, my) {
//////////////////////////////////////////////////////////////////////////// var that = {};
// constants spec = spec || {};
var jio_const_obj = { my = my || {};
job_method_object: { // Attributes //
checkNameAvailability:{}, var priv = {};
saveDocument:{}, priv.path = spec.path || '';
loadDocument:{}, priv.option = spec.option || {};
getDocumentList:{}, priv.respond = priv.option.onResponse || function(){};
removeDocument:{} priv.done = priv.option.onDone || function(){};
priv.fail = priv.option.onFail || function(){};
priv.end = function() {};
// Methods //
/**
* Returns the label of the command.
* @method getLabel
* @return {string} The label.
*/
that.getLabel = function() {
return 'command';
};
/**
* Returns the path of the command.
* @method getPath
* @return {string} The path of the command.
*/
that.getPath = function() {
return priv.path;
};
/**
* Returns the value of an option.
* @method getOption
* @param {string} optionname The option name.
* @return The option value.
*/
that.getOption = function(optionname) {
return priv.option[optionname];
};
/**
* Validates the storage.
* Override this function.
* @param {object} handler The storage handler
*/
that.validate = function(handler) {
that.validateState();
};
/**
* Delegate actual excecution the storage handler.
* @param {object} handler The storage handler.
*/
that.execute = function(handler) {
that.validate(handler);
handler.execute(that);
};
/**
* Execute the good method from the storage.
* Override this function.
* @method executeOn
* @param {object} storage The storage.
*/
that.executeOn = function(storage) {};
/*
* Do not override.
* Override `validate()' instead
*/
that.validateState = function() {
if (priv.path === '') {
throw invalidCommandState({command:that,message:'Path is empty'});
}
};
that.done = function(return_value) {
console.log ('test');
priv.done(return_value);
priv.respond({value:return_value});
priv.end();
};
that.fail = function(return_error) {
priv.fail(return_error);
priv.respond({error:return_error});
priv.end();
};
that.onEndDo = function(fun) {
priv.end = fun;
};
/**
* Returns a serialized version of this command.
* Override this function.
* @method serialized
* @return {object} The serialized command.
*/
that.serialized = function() {
return {label:that.getLabel(),
path:priv.path,
option:priv.option};
};
return that;
};
var getDocumentList = function(spec, my) {
var that = command(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.label = function() {
return 'getDocumentList';
};
that.executeOn = function(storage) {
storage.getDocumentList(that);
};
return that;
};
var loadDocument = function(spec, my) {
var that = command(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.label = function() {
return 'loadDocument';
};
that.executeOn = function(storage) {
storage.loadDocument(that);
};
return that;
};
var removeDocument = function(spec, my) {
var that = command(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.label = function() {
return 'removeDocument';
};
that.executeOn = function(storage) {
storage.removeDocument(that);
};
return that;
};
var saveDocument = function(spec, my) {
var that = command(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
var content = spec.content;
// Methods //
that.label = function() {
return 'saveDocument';
};
that.getContent = function() {
return content;
};
/**
* Validates the storage handler.
* @param {object} handler The storage handler
*/
var super_validate = that.validate;
that.validate = function(handler) {
if (typeof content !== 'string') {
throw invalidCommandState({command:that,message:'No data to save'});
}
super_validate(handler);
};
that.executeOn = function(storage) {
storage.saveDocument(that);
};
return that;
};
var jioException = function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
that.name = 'jioException';
that.message = spec.message || 'Unknown Reason.';
that.toString = function() {
return that.name + ': ' + that.message;
};
return that;
};
var invalidCommandState = function(spec, my) {
var that = jioException(spec, my);
spec = spec || {};
var command = spec.command;
that.name = 'invalidCommandState';
that.toString = function() {
return that.name +': ' +
command.getLabel() + ', ' + that.message;
};
return that;
};
var invalidStorage = function(spec, my) {
var that = jioException(spec, my);
spec = spec || {};
var type = spec.storage.getType();
that.name = 'invalidStorage';
that.toString = function() {
return that.name +': ' +
'Type "'+type + '", ' + that.message;
};
return that;
};
var invalidStorageType = function(spec, my) {
var that = jioException(spec, my);
var type = spec.type;
that.name = 'invalidStorageType';
that.toString = function() {
return that.name +': ' +
type + ', ' + that.message;
};
return that;
};
var jobNotReadyException = function(spec, my) {
var that = jioException(spec, my);
that.name = 'jobNotReadyException';
return that;
};
var tooMuchTriesJobException = function(spec, my) {
var that = jioException(spec, my);
that.name = 'tooMuchTriesJobException';
return that;
};
var invalidJobException = function(spec, my) {
var that = jioException(spec, my);
that.name = 'invalidJobException';
return that;
};
var jobStatus = function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.getLabel = function() {
return 'job status';
};
that.canStart = function() {};
that.canRestart = function() {};
that.serialized = function() {
return {label:that.getLabel()};
};
return that;
};
var doneStatus = function(spec, my) {
var that = jobStatus(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.getLabel = function() {
return 'done';
};
that.canStart = function() {
return false;
};
that.canRestart = function() {
return false;
};
return that;
};
var failStatus = function(spec, my) {
var that = jobStatus(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.getLabel = function() {
return 'fail';
};
that.canStart = function() {
return false;
};
that.canRestart = function() {
return true;
};
return that;
};
var initialStatus = function(spec, my) {
var that = jobStatus(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.getLabel = function() {
return 'initial';
};
that.canStart = function() {
return true;
};
that.canRestart = function() {
return true;
};
return that;
};
var onGoingStatus = function(spec, my) {
var that = jobStatus(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.getLabel = function() {
return 'on going';
};
that.canStart = function() {
return false;
};
that.canRestart = function() {
return false;
};
return that;
};
var waitStatus = function(spec, my) {
var that = jobStatus(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
var job_id_a = spec.job_id_array || [];
var threshold = 0;
// Methods //
that.getLabel = function() {
return 'wait';
};
that.waitForJob = function(job) {
var i;
for (i = 0; i < job_id_a.length; i+= 1) {
if (job_id_a[i] === job.getId()) {
return;
}
}
job_id_a.push(job.getId());
};
that.dontWaitForJob = function(job) {
var i, tmp_job_id_a = [];
for (i = 0; i < job_id_a.length; i+= 1) {
if (job_id_a[i] !== job.getId()){
tmp_job_id_a.push(job_id_a[i]);
}
}
job_id_a = tmp_job_id_a;
};
that.waitForTime = function(ms) {
threshold = Date.now() + ms;
};
that.stopWaitForTime = function() {
threshold = 0;
};
that.canStart = function() {
return (job_id_a.length === 0 && Date.now() >= threshold);
};
that.canRestart = function() {
return false;
};
that.serialized = function() {
return {label:that.getLabel(),
waitfortime:threshold,
waitforjob:job_id_a};
};
return that;
};
var storage = function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var priv = {};
priv.type = spec.type || '';
// my.jio exists
// Methods //
that.getType = function() {
return priv.type;
};
/**
* Execute the command on this storage.
* @method execute
* @param {object} command The command
*/
that.execute = function(command) {
command.executeOn(that);
};
/**
* Override this function to validate specifications.
* @method isValid
* @return {boolean} true if ok, else false.
*/
that.isValid = function() {
return true;
};
that.validate = function(command) {
command.validate(that);
};
/**
* Returns a serialized version of this storage.
* @method serialized
* @return {object} The serialized storage.
*/
that.serialized = function() {
return {type:that.getType()};
};
that.saveDocument = function(command) {
throw invalidStorage({storage:that,message:'Unknown storage.'});
};
that.loadDocument = function(command) {
that.saveDocument();
};
that.removeDocument = function(command) {
that.saveDocument();
};
that.getDocumentList = function(command) {
that.saveDocument();
};
return that;
};
var storageHandler = function(spec, my) {
var that = storage(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
var priv = {};
priv.storage_a = spec.storagelist || [];
// Methods //
/**
* It is called before the execution.
* Override this function.
* @method beforeExecute
* @param {object} command The command.
* @param {object} option Some options.
*/
that.beforeExecute = function(command,option) {};
/**
* Execute the command according to this storage.
* @method execute
* @param {object} command The command.
* @param {object} option Some options.
*/
that.execute = function(command,option) {
var i;
that.validate(command);
that.beforeExecute(command,option);
for(i = 0; i < priv.storage_a.length; i++) {
priv.storage_a[i].execute(command);
}
that.afterExecute(command,option);
};
/**
* Is is called after the execution.
* Override this function.
* @method afterExecute
* @param {object} command The command.
* @param {object} option Some options.
*/
that.afterExecute = function(command,option) {
that.done();
};
/**
* Returns a serialized version of this storage
* @method serialized
* @return {object} The serialized storage.
*/
that.serialized = function() {
return {type:priv.type,
storagelist:priv.storagelist};
};
return that;
};
var activityUpdater = (function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var priv = {};
priv.id = spec.id || 0;
priv.interval = 400;
priv.interval_id = null;
// Methods //
priv.touch = function() {
LocalOrCookieStorage.setItem ('jio/id/'+priv.id, Date.now());
};
that.setId = function(id) {
priv.id = id;
};
that.setIntervalDelay = function(ms) {
priv.interval = ms;
};
that.getIntervalDelay = function() {
return priv.interval;
};
that.start = function() {
if (!priv.interval_id) {
priv.touch();
priv.interval_id = setInterval(function() {
priv.touch();
}, priv.interval);
}
};
that.stop = function() {
if (priv.interval_id !== null) {
clearInterval(priv.interval_id);
priv.interval_id = null;
}
};
return that;
}());
var jio = function(spec, my) {
var job = function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var priv = {};
priv.id = jobIdHandler.nextId();
priv.command = spec.command;
priv.storage = spec.storage;
priv.status = initialStatus();
priv.tried = 0;
priv.max_retry = 0;
priv.date = new Date();
// Initialize //
(function() {
if (!priv.storage){
throw invalidJobException({job:that,message:'No storage set'});
}
if (!priv.command){
throw invalidJobException({job:that,message:'No command set'});
}
}());
// Methods //
/**
* Returns the job command.
* @method getCommand
* @return {object} The job command.
*/
that.getCommand = function() {
return priv.command;
};
that.getStatus = function() {
return priv.status;
};
that.getId = function() {
return priv.id;
};
that.getStorage = function() {
return priv.storage;
};
/**
* Checks if the job is ready.
* @method isReady
* @return {boolean} true if ready, else false.
*/
that.isReady = function() {
if (priv.tried === 0) {
return priv.status.canStart();
} else {
return priv.status.canRestart();
}
};
/**
* Returns a serialized version of this job.
* @method serialized
* @return {object} The serialized job.
*/
that.serialized = function() {
return {id:priv.id,
date:priv.date.getTime(),
tried:priv.tried,
max_retry:priv.max_retry,
status:priv.status.serialized(),
command:priv.command.serialized(),
storage:priv.storage.serialized()};
};
/**
* Tells the job to wait for another one.
* @method waitForJob
* @param {object} job The job to wait for.
*/
that.waitForJob = function(job) {
if (priv.status.getLabel() !== 'wait') {
priv.status = waitStatus();
}
priv.status.waitForJob(job);
};
/**
* Tells the job to do not wait for a job.
* @method dontWaitForJob
* @param {object} job The other job.
*/
that.dontWaitFor = function(job) {
if (priv.status.getLabel() === 'wait') {
priv.status.dontWaitForJob(job);
}
};
/**
* Tells the job to wait for a while.
* @method waitForTime
* @param {number} ms Time to wait in millisecond.
*/
that.waitForTime = function(ms) {
if (priv.status.getLabel() !== 'wait') {
priv.status = waitStatus();
}
priv.status.waitForTime(ms);
};
/**
* Tells the job to do not wait for a while anymore.
* @method stopWaitForTime
*/
that.stopWaitForTime = function() {
if (priv.status.getLabel() === 'wait') {
priv.status.stopWaitForTime();
}
};
/**
* Updates the date of the job with the another one.
* @method update
* @param {object} job The other job.
*/
that.update = function(job) {
priv.date = job.getDate();
};
that.execute = function() {
if (priv.max_retry !== 0 && priv.tried >= priv.max_retry) {
throw tooMuchTriesJobException(
{job:that,message:'The job was invoked too much time.'});
}
if (!that.isReady()) {
throw jobNotReadyException({message:'Can not execute this job.'});
}
priv.status = onGoingStatus();
priv.tried ++;
priv.command.onEndDo (function() {
jobManager.terminateJob (that);
});
priv.command.execute (priv.storage);
};
return that;
};
var announcement = function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var callback_a = [];
var name = spec.name || '';
// Methods //
that.add = function(callback) {
callback_a.push(callback);
};
that.remove = function(callback) {
var i, tmp_callback_a = [];
for (i = 0; i < callback_a.length; i+= 1) {
if (callback_a[i] !== callback) {
tmp_callback_a.push(callback_a[i]);
}
}
callback_a = tmp_callback_a;
};
that.register = function() {
announcer.register(that);
};
that.unregister = function() {
announcer.unregister(that);
};
that.trigger = function(args) {
var i;
for(i = 0; i < callback_a.length; i++) {
callback_a[i].apply(null, args);
}
};
return that;
};
var announcer = (function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var announcement_o = {};
// Methods //
that.register = function(name) {
if(!announcement_o[name]) {
announcement_o[name] = announcement();
}
};
that.unregister = function(name) {
if (announcement_o[name]) {
delete announcement_o[name];
}
};
that.at = function(name) {
return announcement_o[name];
};
that.on = function(name, callback) {
that.register(name);
that.at(name).add(callback);
};
that.trigger = function(name, args) {
that.at(name).trigger(args);
};
return that;
}());
var jobIdHandler = (function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var id = 0;
// Methods //
that.nextId = function() {
id = id + 1;
return id;
};
return that;
}());
var jobManager = (function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var job_array_name = 'jio/job_array';
var priv = {};
priv.id = spec.id;
priv.interval_id = null;
priv.interval = 200;
priv.job_a = [];
// Methods //
priv.getJobArrayName = function() {
return job_array_name + '/' + priv.id;
};
priv.getJobArray = function() {
return LocalOrCookieStorage.getItem(priv.getJobArrayName())||[];
};
priv.copyJobArrayToLocal = function() {
var new_a = [], i;
for (i = 0; i < priv.job_a.length; i+= 1) {
new_a.push(priv.job_a[i].serialized());
}
LocalOrCookieStorage.setItem(priv.getJobArrayName(),new_a);
};
priv.removeJob = function(job) {
var i, tmp_job_a = [];
for (i = 0; i < priv.job_a.length; i+= 1) {
if (priv.job_a[i] !== job) {
tmp_job_a.push(priv.job_a[i]);
}
}
priv.job_a = tmp_job_a;
priv.copyJobArrayToLocal();
};
/**
* Sets the job manager id.
* @method setId
* @param {number} id The id.
*/
that.setId = function(id) {
priv.id = id;
};
/**
* Starts listening to the job array, executing them regulary.
* @method start
*/
that.start = function() {
var i;
if (priv.interval_id === null) {
priv.interval_id = setInterval (function() {
for (i = 0; i < priv.job_a.length; i+= 1) {
that.execute(priv.job_a[i]);
}
},priv.interval);
}
};
/**
* Stops listening to the job array.
* @method stop
*/
that.stop = function() {
if (priv.interval_id !== null) {
clearInterval(priv.interval_id);
priv.interval_id = null;
if (priv.job_a.length === 0) {
LocalOrCookieStorage.deleteItem(priv.getJobArrayName());
}
}
};
/**
* Executes a job.
* @method execute
* @param {object} job The job object.
*/
that.execute = function(job) {
try {
job.execute();
} catch (e) {
switch (e.name) {
case 'jobNotReadyException': break; // do nothing
case 'tooMuchTriesJobException': break; // do nothing
default: throw e;
}
}
priv.copyJobArrayToLocal();
};
that.terminateJob = function(job) {
priv.removeJob(job);
priv.copyJobArrayToLocal();
};
that.addJob = function(job) {
var result_a = that.validateJobAccordingToJobList (priv.job_a,job);
priv.manage (job,result_a);
priv.copyJobArrayToLocal();
};
that.validateJobAccordingToJobList = function(job_a,job) {
var i, result_a = [];
for (i = 0; i < job_a.length; i+= 1) {
result_a.push(jobRules.validateJobAccordingToJob (job_a[i],job));
}
return result_a;
};
priv.manage = function(job,result_a) {
var i;
if (priv.job_a.length !== result_a.length) {
throw new RangeError("Array out of bound");
} }
}, for (i = 0; i < result_a.length; i+= 1) {
// end constants if (result_a[i].action === 'dont accept') {
//////////////////////////////////////////////////////////////////////////// return;
// jio globals }
jio_global_obj = { }
job_managing_method:{ for (i = 0; i < result_a.length; i+= 1) {
switch (result_a[i].action) {
case 'eliminate':
that.eliminate(result_a[i].job);
break;
case 'replace':
job.update(result_a[i].job);
priv.copyJobArrayToLocal();
return;
case 'wait':
job.waitForJob(result_a[i].job);
break;
default: break;
}
}
priv.job_a.push(job);
priv.copyJobArrayToLocal();
};
that.eliminate = function(job) {
var i, tmp_a = [];
for (i = 0; i < priv.job_a.length; i+= 1) {
if (priv.job_a[i].getId() !== job.getId()) {
tmp_a.push(priv.job_a[i]);
}
}
priv.job_a = tmp_a;
};
return that;
}());
var jobRules = (function(spec, my) {
var that = {};
// Attributes //
var priv = {};
that.eliminate = function() { return 'eliminate'; };
that.update = function() { return 'update'; };
that.dontAccept = function() { return 'dont accept'; };
that.wait = function() { return 'wait'; };
that.none = function() { return 'none'; };
priv.compare = {
};
priv.default_compare = function(job1,job2) {
return (job1.getCommand().getPath() === job2.getCommand().getPath() &&
JSON.stringify(job1.getStorage()) ===
JSON.stringify(job2.getStorage()));
};
priv.action = {
/* /*
LEGEND: LEGEND:
- s: storage - s: storage
- a: applicant
- m: method - m: method
- n: name - n: name
- c: content - c: content
...@@ -31,19 +986,17 @@ var JIO = ...@@ -31,19 +986,17 @@ var JIO =
- =: are equal - =: are equal
- !: are not equal - !: are not equal
select ALL s= a= n= select ALL s= n=
removefailordone fail|done removefailordone fail|done
/ elim repl nacc wait / elim repl nacc wait
Remove !ongoing Save 1 x x x Remove !ongoing Save 1 x x x
Save !ongoing Remove 1 x x x Save !ongoing Remove 1 x x x
GetList !ongoing GetList 0 1 x x GetList !ongoing GetList 0 1 x x
Check !ongoing Check 0 1 x x
Remove !ongoing Remove 0 1 x x Remove !ongoing Remove 0 1 x x
Load !ongoing Load 0 1 x x Load !ongoing Load 0 1 x x
Save c= !ongoing Save 0 1 x x Save c= !ongoing Save 0 1 x x
Save c! !ongoing Save 0 1 x x Save c! !ongoing Save 0 1 x x
GetList ongoing GetList 0 0 1 x GetList ongoing GetList 0 0 1 x
Check ongoing Check 0 0 1 x
Remove ongoing Remove 0 0 1 x Remove ongoing Remove 0 0 1 x
Remove ongoing Load 0 0 1 x Remove ongoing Load 0 0 1 x
Remove !ongoing Load 0 0 1 x Remove !ongoing Load 0 0 1 x
...@@ -58,1337 +1011,354 @@ var JIO = ...@@ -58,1337 +1011,354 @@ var JIO =
Save ongoing Load 0 0 0 1 Save ongoing Load 0 0 0 1
Save c! ongoing Save 0 0 0 1 Save c! ongoing Save 0 0 0 1
Save !ongoing Load 0 0 0 1 Save !ongoing Load 0 0 0 1
GetList ongoing Check 0 0 0 0
GetList ongoing Remove 0 0 0 0 GetList ongoing Remove 0 0 0 0
GetList ongoing Load 0 0 0 0 GetList ongoing Load 0 0 0 0
GetList ongoing Save 0 0 0 0 GetList ongoing Save 0 0 0 0
GetList !ongoing Check 0 0 0 0
GetList !ongoing Remove 0 0 0 0 GetList !ongoing Remove 0 0 0 0
GetList !ongoing Load 0 0 0 0 GetList !ongoing Load 0 0 0 0
GetList !ongoing Save 0 0 0 0 GetList !ongoing Save 0 0 0 0
Check ongoing GetList 0 0 0 0
Check ongoing Remove 0 0 0 0
Check ongoing Load 0 0 0 0
Check ongoing Save 0 0 0 0
Check !ongoing GetList 0 0 0 0
Check !ongoing Remove 0 0 0 0
Check !ongoing Load 0 0 0 0
Check !ongoing Save 0 0 0 0
Remove ongoing GetList 0 0 0 0 Remove ongoing GetList 0 0 0 0
Remove ongoing Check 0 0 0 0
Remove !ongoing GetList 0 0 0 0 Remove !ongoing GetList 0 0 0 0
Remove !ongoing Check 0 0 0 0
Load ongoing GetList 0 0 0 0 Load ongoing GetList 0 0 0 0
Load ongoing Check 0 0 0 0
Load !ongoing GetList 0 0 0 0 Load !ongoing GetList 0 0 0 0
Load !ongoing Check 0 0 0 0
Save ongoing GetList 0 0 0 0 Save ongoing GetList 0 0 0 0
Save ongoing Check 0 0 0 0
Save !ongoing GetList 0 0 0 0 Save !ongoing GetList 0 0 0 0
Save !ongoing Check 0 0 0 0
For more information, see documentation For more information, see documentation
*/ */
canSelect:function (job1,job2) { 'saveDocument':{
if (JSON.stringify (job1.storage) === 'on going':{
JSON.stringify (job2.storage) && 'saveDocument' :function(job1,job2){
JSON.stringify (job1.applicant) === if (job1.getCommand().getContent() ===
JSON.stringify (job2.applicant) && job2.getCommand().getContent()) {
job1.name === job2.name) { return that.dontAccept();
return true; } else {
return that.wait();
} }
return false;
}, },
canRemoveFailOrDone:function (job1,job2) { 'loadDocument' : that.wait,
if (job1.status === 'fail' || 'removeDocument' : that.wait,
job1.status === 'done') { 'getDocumentList' : that.none
return true;
}
return false;
}, },
canEliminate:function (job1,job2) { 'not on going':{
if (job1.status !== 'on_going' && 'saveDocument' : that.update,
(job1.method === 'removeDocument' && 'loadDocument' : that.wait,
job2.method === 'saveDocument' || 'removeDocument' : that.eliminate,
job1.method === 'saveDocument' && 'getDocumentList' : that.none
job2.method === 'removeDocument')) {
return true;
} }
return false;
}, },
canReplace:function (job1,job2) { 'loadDocument':{
if (job1.status !== 'on_going' && 'on going':{
job1.method === job2.method && 'saveDocument' : that.wait,
job1.date < job2.date) { 'loadDocument' : that.dontAccept,
return true; 'removeDocument' : that.wait,
} 'getDocumentList' : that.none
return false;
}, },
cannotAccept:function (job1,job2) { 'not on going':{
if (job1.status !== 'on_going' ) { 'saveDocument' : that.wait,
if (job1.method === 'removeDocument' && 'loadDocument' : that.update,
job2.method === 'loadDocument') { 'removeDocument' : that.wait,
return true; 'getDocumentList' : that.none
}
} else { // ongoing
if (job1.method === job2.method === 'loadDocument') {
return true;
} else if (job1.method === 'removeDocument' &&
(job2.method === 'loadDocument' ||
job2.method === 'removeDocument')) {
return true;
} else if (job1.method === job2.method === 'saveDocument' &&
job1.content === job2.content) {
return true;
} else if (job1.method === job2.method ===
'getDocumentList' ||
job1.method === job2.method ===
'checkNameAvailability') {
return true;
}
} }
return false;
}, },
mustWait:function (job1,job2) { 'removeDocument':{
if (job1.method === 'getDocumentList' || 'on going':{
job1.method === 'checkNameAvailability' || 'saveDocument' : that.wait,
job2.method === 'getDocumentList' || 'loadDocument' : that.dontAccept,
job2.method === 'checkNameAvailability' ) { 'removeDocument' : that.dontAccept,
return false; 'getDocumentList' : that.none
} },
return true; 'not on going':{
'saveDocument' : that.eliminate,
'loadDocument' : that.dontAccept,
'removeDocument' : that.update,
'getDocumentList' : that.none
} }
}, },
queue_id: 1, 'getDocumentList':{
storage_type_object: {}, // ex: {'type':'local','creator': fun ...} 'on going':{
max_wait_time: 10000 'saveDocument' : that.none,
'loadDocument' : that.none,
'removeDocument' : that.none,
'getDocumentList' : that.dontAccept
}, },
// end jio globals 'not on going':{
//////////////////////////////////////////////////////////////////////////// 'saveDocument' : that.none,
'loadDocument' : that.none,
//////////////////////////////////////////////////////////////////////////// 'removeDocument' : that.none,
// Tools 'getDocumentList' : that.update
// end Tools
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Classes
newPubSub,newJob,newJobQueue,newJobListener,newActivityUpdater,
newBaseStorage,newJioConstructor,newJioCreator;
// end Classes
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Publisher Subcriber
newPubSub = function (spec, my) {
var that = {}, priv = {},
topics = {}, callbacks, topic;
priv.eventAction = function (id) {
topic = id && topics[id];
if (!topic) {
callbacks = $.Callbacks();
topic = {
publish: callbacks.fire,
subscribe: callbacks.add,
unsubscribe: callbacks.remove
};
if (id) {
topics[id] = topic;
}
}
return topic;
};
that.publish = function (event_name,obj) {
// publish an event
priv.eventAction(event_name).publish(obj);
};
that.subscribe = function (event_name,callback) {
// subscribe and return the callback function
priv.eventAction(event_name).subscribe(callback);
return callback;
};
that.unsubscribe = function (event_name,callback) {
// unsubscribe the callback from eventname
priv.eventAction(event_name).unsubscribe(callback);
};
return that;
};
// end Publisher Subcriber
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Job & JobQueue
newJob = function ( spec, my ) {
// Job constructor
var job = $.extend(true,{},spec);
job['id']=0;
job['status']='initial';
job['date']=Date.now();
return job;
};
newJobQueue = function ( spec, my ) {
// JobQueue is a queue of jobs. It will regulary copy this queue
// into localStorage to resume undone tasks.
// spec.publisher: the publisher to use to send event
// spec.options.useLocalStorage: if true, save jobs into localStorage,
// else only save on memory.
var that = {}, priv = {}, jio_id_array_name = 'jio/id_array';
that.init = function ( options ) {
// initialize the JobQueue
// options.publisher : is the publisher to use to send events
// options.jio_id : the jio ID
var k, emptyFun = function (){}, jio_id_array;
if (priv.use_local_storage) {
jio_id_array = localOrCookieStorage.
getItem (jio_id_array_name)||[];
if (spec.publisher) {
priv.publisher = spec.publisher;
}
priv.jio_id = options.jio_id;
priv.job_object_name = 'jio/job_object/' + priv.jio_id;
jio_id_array.push (priv.jio_id);
localOrCookieStorage.setItem (jio_id_array_name,jio_id_array);
}
priv.job_object = {};
that.copyJobQueueToLocalStorage();
for (k in priv.recovered_job_object) {
priv.recovered_job_object[k].callback = emptyFun;
that.addJob (priv.recovered_job_object[k]);
}
};
that.close = function () {
// close the job queue.
// it also deletes from local storage only if the job list is
// empty.
if (JSON.stringify(priv.job_object) === '{}') {
localOrCookieStorage.deleteItem(priv.job_object_name);
}
};
that.getNewQueueID = function () {
// Returns a new queueID
var k = null, id = 0,
jio_id_array = localOrCookieStorage.getItem (jio_id_array_name)||[];
for (k = 0; k < jio_id_array.length; k += 1) {
if (jio_id_array[k] >= jio_global_obj.queue_id) {
jio_global_obj.queue_id = jio_id_array[k] + 1;
}
}
id = jio_global_obj.queue_id;
jio_global_obj.queue_id ++;
return id;
};
that.recoverOlderJobObject = function () {
// recover job object from older inactive jio
var k = null, new_jio_id_array = [], jio_id_array_changed = false,
jio_id_array;
if (priv.use_local_storage) {
jio_id_array = localOrCookieStorage.
getItem (jio_id_array_name)||[];
for (k = 0; k < jio_id_array.length; k += 1) {
if (localOrCookieStorage.getItem (
'jio/id/'+jio_id_array[k]) < Date.now () - 10000) {
// remove id from jio_id_array
// 10000 sec ? delete item
localOrCookieStorage.deleteItem('jio/id/'+
jio_id_array[k]);
// job recovery
priv.recovered_job_object = localOrCookieStorage.
getItem('jio/job_object/'+ jio_id_array[k]);
// remove ex job object
localOrCookieStorage.deleteItem(
'jio/job_object/'+ jio_id_array[k]);
jio_id_array_changed = true;
} else {
new_jio_id_array.push (jio_id_array[k]);
}
}
if (jio_id_array_changed) {
localOrCookieStorage.setItem(jio_id_array_name,
new_jio_id_array);
} }
} }
}; };
that.isThereJobsWhere = function( func ) { priv.default_action = 'none';
// Check if there is jobs, in the queue, // Methods //
// where [func](job) == true. priv.getAction = function(job1,job2) {
var j1label, j2label, j1status;
var id = 'id'; j1label = job1.getCommand().getLabel();
if (!func) { return true; } j2label = job2.getCommand().getLabel();
for (id in priv.job_object) { j1status = (job1.getStatus().getLabel()==='on going'?
if (func(priv.job_object[id])) { 'on going':'not on going');
return true; try {
} return priv.action[j1label][j1status][j2label](job1,job2);
} } catch (e) {
return false; return priv.default_action;
};
that.copyJobQueueToLocalStorage = function () {
// Copy job queue into localStorage.
if (priv.use_local_storage) {
return localOrCookieStorage.setItem(
priv.job_object_name,priv.job_object);
} else {
return false;
}
};
that.createJob = function ( options ) {
return that.addJob ( newJob ( options ) );
};
that.addJob = function ( job ) {
// Add a job to the queue, browsing all jobs
// and check if the new job can eliminate older ones,
// can replace older one, can be accepted, or must wait
// for older ones.
// It also clean fail or done jobs.
// job = the job object
var new_one = true, elim_array = [], wait_array = [],
remove_array = [], base_storage = null, id = 'id';
//// browsing current jobs
for (id in priv.job_object) {
if (jio_global_obj.job_managing_method.canRemoveFailOrDone(
priv.job_object[id],job)) {
remove_array.push(id);
continue;
}
if (jio_global_obj.job_managing_method.canSelect(
priv.job_object[id],job)) {
if (jio_global_obj.job_managing_method.canEliminate(
priv.job_object[id],job)) {
elim_array.push(id);
continue;
}
if (jio_global_obj.job_managing_method.canReplace(
priv.job_object[id],job)) {
base_storage = newBaseStorage(
{'queue':that,'job':priv.job_object[id]});
base_storage.replace(job);
new_one = false;
break;
}
if (jio_global_obj.job_managing_method.cannotAccept(
priv.job_object[id],job)) {
// Job not accepted
return false;
}
if (jio_global_obj.job_managing_method.mustWait(
priv.job_object[id],job)) {
wait_array.push(id);
continue;
}
// one of the previous tests must be ok.
// the program must not reach this part of the 'for'.
}
}
//// end browsing current jobs
if (new_one) {
// if it is a new job, we can eliminate deprecated jobs and
// set this job dependencies.
for (id = 0; id < elim_array.length; id += 1) {
base_storage = newBaseStorage(
{'queue':that,
'job':priv.job_object[elim_array[id]]});
base_storage.eliminate();
}
if (wait_array.length > 0) {
job.status = 'wait';
job.waiting_for = {'job_id_array':wait_array};
for (id = 0; id < wait_array.length; id += 1) {
if (priv.job_object[wait_array[id]]) {
priv.job_object[wait_array[id]].max_tries = 1;
}
}
}
for (id = 0; id < remove_array.length; id += 1) {
that.removeJob(priv.job_object[remove_array[id]]);
}
// set job id
job.id = priv.job_id;
job.tries = 0;
priv.job_id ++;
// save the new job into the queue
priv.job_object[job.id] = job;
}
// save into localStorage
that.copyJobQueueToLocalStorage();
return true;
}; // end addJob
that.removeJob = function ( options ) {
// Remove job(s) from queue where [options.where](job) === true.
// If there is no job in [options], then it will treat all job.
// If there is no [where] function, then it will remove all selected
// job. It means that if no option was given, it'll remove all jobs.
// options.job = the job object containing at least {id:..}.
// options.where = remove values where options.where(job) === true
var settings = $.extend ({where:function (job) {return true;}},
options),andwhere,found=false,k='key';
//// modify the job list
if (settings.job) {
if (priv.job_object[settings.job.id] && settings.where(
priv.job_object[settings.job.id]) ) {
delete priv.job_object[settings.job.id];
found = true;
}
}else {
for (k in priv.job_object) {
if (settings.where(priv.job_object[k])) {
delete priv.job_object[k];
found = true;
}
}
}
if (!found) {
console.error('No jobs was found, when trying to remove some.');
}
//// end modifying
that.copyJobQueueToLocalStorage();
};
that.resetAll = function () {
// Reset all job to 'initial'.
// TODO manage jobs ! All jobs are not 'initial'.
var id = 'id';
for (id in priv.job_object) {
priv.job_object[id].status = 'initial';
}
that.copyJobQueueToLocalStorage();
};
that.invokeAll = function () {
// Do all jobs in the queue.
var i = 'id', j, ok;
//// do All jobs
for (i in priv.job_object) {
ok = false;
if (priv.job_object[i].status === 'initial') {
// if status initial
// invoke new job
that.invoke(priv.job_object[i]);
} else if (priv.job_object[i].status === 'wait') {
ok = true;
// if status wait
if (priv.job_object[i].waiting_for.job_id_array) {
// wait job
// browsing job id array
for (j = 0;
j < priv.job_object[i].
waiting_for.job_id_array.length;
j += 1) {
if (priv.job_object[priv.job_object[i].
waiting_for.job_id_array[j]]) {
// if a job is still exist, don't invoke
ok = false;
break;
}
}
}
if (priv.job_object[i].waiting_for.time) {
// wait time
if (priv.job_object[i].waiting_for.time > Date.now()) {
// it is not time to restore the job!
ok = false;
}
}
// else wait nothing
if (ok) {
// invoke waiting job
that.invoke(priv.job_object[i]);
}
}
}
this.copyJobQueueToLocalStorage();
//// end, continue doing jobs asynchronously
};
that.invoke = function (job) {
// Do a job invoking the good method in the good storage.
var base_storage;
//// analysing job method
// if the method does not exist, do nothing
if (!jio_const_obj.job_method_object[job.method]) {
return false; // suppose never happen
}
// test if a similar job is on going, in order to publish a start
// event if it is the first of his kind (method).
if (!that.isThereJobsWhere(function (testjob){
return (testjob.method === job.method &&
testjob.method === 'initial');
})) {
job.status = 'on_going';
priv.publisher.publish(jio_const_obj.job_method_object[
job.method]['start_'+job.method]);
} else {
job.status = 'on_going';
}
// Create a storage object and use it to save,load,...!
base_storage = newBaseStorage({'queue':this,'job':job});
base_storage.execute();
//// end method analyse
};
that.ended = function (endedjob) {
// It is a callback function called just before user callback.
// It is called to manage job_object according to the ended job.
var job = $.extend(true,{},endedjob); // copy
// This job is supposed terminated, we can remove it from queue.
that.removeJob ({'job':job});
//// ended job analyse
// if the job method does not exists, return false
if (!jio_const_obj.job_method_object[job.method]) {
return false;
}
// if there isn't some job to do, then send stop event
if (!that.isThereJobsWhere(function(testjob){
return (testjob.method === job.method &&
// testjob.status === 'wait' || // TODO ?
testjob.status === 'on_going' ||
testjob.status === 'initial');
})) {
priv.publisher.publish(
jio_const_obj.job_method_object[
job.method]['stop_'+job.method]);
return;
} }
//// end returnedJobAnalyse
};
that.clean = function () {
// Clean the job list, removing all jobs that have failed.
// It also change the localStorage job queue
that.removeJob (
undefined,{
'where':function (job) {
return (job.status === 'fail');
} });
};
//// end Methods
//// Initialize
priv.use_local_storage = spec.options.use_local_storage;
priv.publisher = spec.publisher;
priv.job_id = 1;
priv.jio_id = 0;
priv.job_object_name = '';
priv.job_object = {};
priv.recovered_job_object = {};
//// end Initialize
return that;
};
// end Job & JobQueue
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// jio job listener
newJobListener = function ( spec, my ) {
// A little daemon which will start jobs from the joblist
var that = {}, priv = {};
priv.interval = 200;
priv.id = null;
priv.queue = spec.queue;
that.setIntervalDelay = function (interval) {
// Set the time between two joblist check in millisec
priv.interval = interval;
}; };
that.start = function () { priv.canCompare = function(job1,job2) {
// Start the listener. It will always check if there are jobs in the var key = priv.stringifyJobForCompare(job1,job2);
// queue if (priv.compare[key]) {
return priv.compare[key](job1,job2);
if (!priv.id) {
priv.id = setInterval (function () {
// recover older jobs
priv.queue.recoverOlderJobObject();
priv.queue.invokeAll();
},priv.interval);
return true;
} else {
return false;
} }
return priv.default_compare(job1,job2);
}; };
that.stop = function () { that.validateJobAccordingToJob = function(job1,job2) {
if (priv.id) { var key = priv.stringifyJobForAction(job1,job2);
clearInterval (priv.id); if (priv.canCompare(job1,job2)) {
priv.id = null; return {action:priv.getAction(job1,job2),job:job1};
return true;
} }
return false; return {action:priv.default_action,job:job1};
};
return that;
}; };
// end jio job listener
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// ActivityUpdater
newActivityUpdater = function () {
// The activity updater is a little thread that proves activity of this
// jio instance.
var that = {}, priv = {};
//// private vars
priv.interval = 400;
priv.id = null;
//// end private vars
//// methods
that.start = function (id) {
// start the updater
if (!priv.id) {
that.touch(id);
priv.id = setInterval (function () {
that.touch(id);
},priv.interval);
return true;
} else {
return false;
}
};
that.stop = function () {
// stop the updater
if (priv.id) {
clearInterval (priv.id);
priv.id = null;
return true;
}
return false;
};
that.touch = function (id) {
localOrCookieStorage.setItem ('jio/id/' + id,Date.now() );
};
//// end methods
return that; return that;
}; }());
// end ActivityUpdater
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// BaseStorage
newBaseStorage = function ( options ) {
// The base storage, will call the good method from the good storage,
// and will check and return the associated value.
var that = {}, priv = {};
//// Private attributes
priv.job = options.job;
priv.callback = options.job.callback;
priv.queue = options.queue;
priv.res = {'status':'done','message':''};
priv.sorted = false;
priv.limited = false;
priv.research_done = false;
//// end Private attributes
//// Private Methods
priv.fail_checkNameAvailability = function () {
priv.res.message = 'Unable to check name availability.';
};
priv.done_checkNameAvailability = function ( isavailable ) {
priv.res.message = priv.job.user_name + ' is ' +
(isavailable?'':'not ') + 'available.';
priv.res.return_value = isavailable;
};
priv.fail_loadDocument = function () {
priv.res.message = 'Unable to load document.';
};
priv.done_loadDocument = function ( returneddocument ) {
priv.res.message = 'Document loaded.';
priv.res.return_value = returneddocument;
// transform date into ms
priv.res.return_value.last_modified =
new Date(priv.res.return_value.last_modified).getTime();
priv.res.return_value.creation_date =
new Date(priv.res.return_value.creation_date).getTime();
};
priv.fail_saveDocument = function () {
priv.res.message = 'Unable to save document.';
};
priv.done_saveDocument = function () {
priv.res.message = 'Document saved.';
};
priv.fail_getDocumentList = function () {
priv.res.message = 'Unable to retrieve document list.';
};
priv.done_getDocumentList = function ( documentlist ) {
var i;
priv.res.message = 'Document list received.';
priv.res.return_value = documentlist;
for (i = 0; i < priv.res.return_value.length; i += 1) {
// transform current date format into ms since 1/1/1970
// useful for easy comparison
if (typeof priv.res.return_value[i].last_modified !== 'number') {
priv.res.return_value[i].last_modified =
new Date(priv.res.return_value[i].last_modified).
getTime();
}
if (typeof priv.res.return_value[i].creation_date !== 'number') {
priv.res.return_value[i].creation_date =
new Date(priv.res.return_value[i].creation_date).
getTime();
}
}
// check for sorting
if (!priv.sorted && typeof priv.job.sort !== 'undefined') {
that.sortDocumentArray(priv.res.return_value);
}
// check for limiting
if (!priv.limited &&
typeof priv.job.limit !== 'undefined' &&
typeof priv.job.limit.begin !== 'undefined' &&
typeof priv.job.limit.end !== 'undefined') {
priv.res.return_value =
that.limitDocumentArray(priv.res.return_value);
}
// check for research
if (!priv.research_done && typeof priv.job.search !== 'undefined') {
priv.res.return_value =
that.searchDocumentArray(priv.res.return_value);
}
};
priv.fail_removeDocument = function () {
priv.res.message = 'Unable to removed document.';
};
priv.done_removeDocument = function () {
priv.res.message = 'Document removed.';
};
priv.retryLater = function () {
// Change the job status to wait for time.
// The listener will invoke this job later.
var time = (priv.job.tries*priv.job.tries*1000);
if (time > jio_global_obj.max_wait_time) {
time = jio_global_obj.max_wait_time;
}
priv.job.status = 'wait';
priv.job.waiting_for = {'time':Date.now() + time};
};
//// end Private Methods
//// Getters Setters
that.cloneJob = function () {
return $.extend(true,{},priv.job);
};
that.getUserName = function () {
return priv.job.user_name || '';
};
that.getApplicantID = function () {
return priv.job.applicant.ID || '';
};
that.getStorageUserName = function () {
return priv.job.storage.user_name || '';
};
that.getStoragePassword = function () {
return priv.job.storage.password || '';
};
that.getStorageURL = function () {
return priv.job.storage.url || '';
};
that.getSecondStorage = function () {
return priv.job.storage.storage || {};
};
that.getStorageArray = function () {
return priv.job.storage.storage_array || [];
};
that.getFileName = function () {
return priv.job.name || '';
};
that.getFileContent = function () {
return priv.job.content || '';
};
that.cloneOptionObject = function () {
return $.extend(true,{},priv.job.options);
};
that.getMaxTries = function () {
return priv.job.max_tries;
};
that.getTries = function () {
return priv.job.tries || 0;
};
that.setMaxTries = function (max_tries) {
priv.job.max_tries = max_tries;
};
//// end Getters Setters
//// Public Methods
that.addJob = function ( newjob ) {
return priv.queue.createJob ( newjob );
};
that.eliminate = function () {
// Stop and remove a job !
priv.job.max_tries = 1;
priv.job.tries = 1;
that.fail('Job Stopped!',0);
};
that.replace = function ( newjob ) {
// It replace the current job by the new one.
// Replacing only the date
priv.job.tries = 0;
priv.job.date = newjob.date;
priv.job.callback = newjob.callback;
priv.res.status = 'fail';
priv.res.message = 'Job Stopped!';
priv.res.error = {};
priv.res.error.status = 0;
priv.res.error.statusText = 'Replaced';
priv.res.error.message = 'The job was replaced by a newer one.';
priv['fail_'+priv.job.method]();
priv.callback(priv.res);
};
that.fail = function ( errorobject ) {
// Called when a job has failed.
// It will retry the job from a certain moment or it will return
// a failure.
priv.res.status = 'fail';
priv.res.error = errorobject;
// init error object with default values
priv.res.error.status = priv.res.error.status || 0;
priv.res.error.statusText =
priv.res.error.statusText || 'Unknown Error';
priv.res.error.array = priv.res.error.array || [];
priv.res.error.message = priv.res.error.message || '';
// retry ?
if (!priv.job.max_tries ||
priv.job.tries < priv.job.max_tries) {
priv.retryLater();
} else {
priv.job.status = 'fail';
priv['fail_'+priv.job.method]();
priv.queue.ended(priv.job);
priv.callback(priv.res);
}
};
that.done = function ( retvalue ) {
// Called when a job has terminated successfully.
// It will return the return value by the calling the callback
// function.
priv.job.status = 'done';
priv['done_'+priv.job.method]( retvalue );
priv.queue.ended(priv.job);
priv.callback(priv.res);
};
that.execute = function () {
// Execute the good function from the good storage.
priv.job.tries = that.getTries() + 1;
if ( !jio_global_obj.storage_type_object[priv.job.storage.type] ) { // Class jio
return null; var that = {};
} spec = spec || {};
return jio_global_obj.storage_type_object[ priv.job.storage.type ]({ my = my || {};
'job':priv.job,'queue':priv.queue})[priv.job.method](); // Attributes //
}; var priv = {};
// These methods must be redefined! var jio_id_array_name = 'jio/id_array';
that.checkNameAvailability = function () { priv.id = 1;
that.fail({status:0, priv.storage = jioNamespace.storage(spec, that);
statusText:'Undefined Method',
message:'This method must be redefined!'}); // initialize //
}; (function () {
that.loadDocument = function () { // Initialize the jio id and add the new id to the list
that.fail({status:0, var i,
statusText:'Undefined Method', jio_id_a = LocalOrCookieStorage.getItem (jio_id_array_name) || [];
message:'This method must be redefined!'}); for (i = 0; i < jio_id_a.length; i+= 1) {
}; if (jio_id_a[i] >= priv.id) {
that.saveDocument = function () { priv.id = jio_id_a[i] + 1;
that.fail({status:0, }
statusText:'Undefined Method', }
message:'This method must be redefined!'}); jio_id_a.push(priv.id);
}; LocalOrCookieStorage.setItem (jio_id_array_name,jio_id_a);
that.getDocumentList = function () { }());
that.fail({status:0, (function (){
statusText:'Undefined Method', // Start Jio updater, and the jobManager
message:'This method must be redefined!'}); activityUpdater.setId(priv.id);
}; activityUpdater.start();
that.removeDocument = function () { jobManager.setId(priv.id);
that.fail({status:0, jobManager.start();
statusText:'Undefined Method', }());
message:'This method must be redefined!'});
// Methods //
that.start = function() {
jobManager.start();
};
that.stop = function() {
jobManager.stop();
}; };
/** /**
* Sorts a document list using sort parameters set in the job. * Returns the jio id.
* @method sortDocumentArray * @method getId
* @param {array} documentarray The array we want to sort. * @return {number} The jio id.
*/ */
that.sortDocumentArray = function (documentarray) { that.getId = function() {
documentarray.sort(function (row1,row2) { return priv.id;
var k, res;
for (k in priv.job.sort) {
var sign = (priv.job.sort[k] === 'descending' ? -1 : 1);
if (row1[k] === row2[k]) { continue; }
return (row1[k] > row2[k] ? sign : -sign);
}
return 0;
});
that.sortDone();
}; };
/** /**
* Tells to this storage that the sorting process is already done. * Checks if the storage description is valid or not.
* @method sortDone * @method validateStorageDescription
* @param {object} description The description object.
* @return {boolean} true if ok, else false.
*/ */
that.sortDone = function () { that.validateStorageDescription = function(description) {
priv.sorted = true; return jioNamespace.storage(description.type)(description).isValid();
}; };
/** /**
* Limits the document list. Clones only the document list between * Save a document.
* begin and end set in limit object in the job. * @method saveDocument
* @method limitDocumentArray * @param {string} path The document path name.
* @param {array} documentarray The array we want to limit * @param {string} content The document's content.
* @return {array} The new document list * @param {object} option (optional) Contains some options:
* - {function} onResponse The callback called when the job is terminated.
* - {function} onDone The callback called when the job has passed.
* - {function} onFail The callback called when the job has fail.
* - {number} max_retry The number max of retries, 0 = infinity.
* @param {object} specificstorage (optional) A specific storage, only if
* you want to save this document elsewhere.
*/ */
that.limitDocumentArray = function (documentarray) { that.saveDocument = function(path, content, option, specificstorage) {
that.limitDone(); option = option || {};
return documentarray.slice(priv.job.limit.begin, option.onResponse = option.onResponse || function(){};
priv.job.limit.end); option.onDone = option.onDone || function(){};
option.onFail = option.onFail || function(){};
option.max_retry = option.max_retry || 0;
console.log ('add job save: ' + JSON.stringify (priv.storage.serialized()));
jobManager.addJob(
job({storage:(specificstorage?
jioNamespace.storage(specificstorage):
priv.storage),
command:saveDocument(
{path:path,content:content,option:option})}));
}; };
/** /**
* Tells to this storage that the limiting process is already done. * Load a document.
* @method limitDone * @method loadDocument
* @param {string} path The document path name.
* @param {object} option (optional) Contains some options:
* - {function} onResponse The callback called when the job is terminated.
* - {function} onDone The callback called when the job has passed.
* - {function} onFail The callback called when the job has fail.
* - {number} max_retry The number max of retries, 0 = infinity.
* - {boolean} metadata_only Load only document metadata.
* @param {object} specificstorage (optional) A specific storage, only if
* you want to save this document elsewhere.
*/ */
that.limitDone = function () { that.loadDocument = function(path, option, specificstorage) {
priv.limited = true; option = option || {};
option.onResponse = option.onResponse || function(){};
option.onDone = option.onDone || function(){};
option.onFail = option.onFail || function(){};
option.max_retry = option.max_retry || 0;
option.metadata_only = (option.metadata_only !== undefined?
option.metadata_only:false);
jobManager.addJob(
job({storage:(specificstorage?
jioNamespace.storage(specificstorage):
priv.storage),
command:loadDocument(
{path:path,option:option})}));
}; };
/** /**
* Search the strings inside the document list. Clones the document list * Remove a document.
* containing only the matched strings. * @method removeDocument
* @method searchDocumentArray * @param {string} path The document path name.
* @param {array} documentarray The array we want to search into. * @param {object} option (optional) Contains some options:
* @return {array} The new document list. * - {function} onResponse The callback called when the job is terminated.
* - {function} onDone The callback called when the job has passed.
* - {function} onFail The callback called when the job has fail.
* - {number} max_retry The number max of retries, 0 = infinity.
* @param {object} specificstorage (optional) A specific storage, only if
* you want to save this document elsewhere.
*/ */
that.searchDocumentArray = function (documentarray) { that.removeDocument = function(path, option, specificstorage) {
var i, k, newdocumentarray = []; option = option || {};
for (i = 0; i < documentarray.length; i += 1) { option.onResponse = option.onResponse || function(){};
for (k in priv.job.search) { option.onDone = option.onDone || function(){};
if (typeof documentarray[i][k] === 'undefined') { option.onFail = option.onFail || function(){};
continue; option.max_retry = option.max_retry || 0;
} jobManager.addJob(
if (documentarray[i][k].search(priv.job.search[k]) > -1) { job({storage:(specificstorage?
newdocumentarray.push(documentarray[i]); jioNamespace.storage(specificstorage):
break; priv.storage),
} command:removeDocument(
} {path:path,option:option})}));
}
that.researchDone();
return newdocumentarray;
}; };
/** /**
* Tells to this storage that the research is already done. * Get a document list from a folder.
* @method researchDone * @method getDocumentList
* @param {string} path The folder path.
* @param {object} option (optional) Contains some options:
* - {function} onResponse The callback called when the job is terminated.
* - {function} onDone The callback called when the job has passed.
* - {function} onFail The callback called when the job has fail.
* - {number} max_retry The number max of retries, 0 = infinity.
* - {boolean} metadata_only Load only document metadata
* @param {object} specificstorage (optional) A specific storage, only if
* you want to save this document elsewhere.
*/ */
that.researchDone = function () { that.getDocumentList = function(path, option, specificstorage) {
priv.research_done = true; option = option || {};
option.onResponse = option.onResponse || function(){};
option.onDone = option.onDone || function(){};
option.onFail = option.onFail || function(){};
option.max_retry = option.max_retry || 0;
option.metadata_only = (option.metadata_only !== undefined?
option.metadata_only:true);
jobManager.addJob(
job({storage:(specificstorage?
jioNamespace.storage(specificstorage):
priv.storage),
command:getDocumentList(
{path:path,option:option})}));
}; };
//// end Public Methods
return that; return that;
}; }; // End Class jio
// end BaseStorage
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// JIO Constructor
newJioConstructor = function ( spec, my ) {
// JIO Constructor, create a new JIO object.
// It just initializes values.
// storage : the storage that contains {type:..,[storageinfos]}
// applicant : the applicant that contains {ID:...}
// these parameters are optional and may be 'string' or 'object'
var that = {}, priv = {};
priv.wrongParametersError = function (settings) {
var m = 'Method: '+ settings.method +
', One or some parameters are undefined.';
console.error (m);
settings.callback({status:'fail',
error: {status:0,
statusText:'Undefined Parameter',
message: m}});
return null;
};
//// Getters Setters
that.getID = function () {
return priv.id;
};
//// end Getters Setters
//// Methods
that.start = function () {
// Start JIO: start listening to jobs and make it ready
if (priv.id !== 0) { return false; }
// set a new jio id
priv.id = priv.queue.getNewQueueID();
// initializing objects
priv.queue.init({'jio_id':priv.id});
// start activity updater
if (priv.updater){
priv.updater.start(priv.id);
}
// start listening
priv.listener.start();
// is now ready
priv.ready = true;
return that.isReady();
};
that.stop = function () {
// Finish some job if possible and stop listening.
// It can be restarted later
priv.queue.close();
priv.listener.stop();
if (priv.updater) {
priv.updater.stop();
}
priv.ready = false;
priv.id = 0;
return true;
};
that.kill = function () {
// kill this JIO, job listening and job operation (event if they
// are on going!)
priv.queue.close();
priv.listener.stop();
if (priv.updater) {
priv.updater.stop();
}
// TODO
priv.ready = false;
return true;
};
that.isReady = function () {
// Check if Jio is ready to use.
return priv.ready;
};
that.publish = function (eventname, obj) {
// publish an event on this jio
// eventname : the event name
// obj : is an object containing some parameters for example
if (!that.isReady()) { return ; }
return priv.pubsub.publish(eventname,obj);
};
that.subscribe = function (eventname, callback) {
// subscribe to an event on this jio. We can subscribe to jio event
// even if jio is not started. Returns the callback function in
// order to unsubscribe it.
// eventname : the event name.
// callback : called after receiving event.
return priv.pubsub.subscribe(eventname,callback);
};
that.unsubscribe = function (eventname,callback) {
// unsubscribe callback from an event
return priv.pubsub.unsubscribe(eventname,callback);
};
that.checkNameAvailability = function ( options ) {
// Check the user availability in the storage set in [options]
// or in the storage set at init. At the end of the job,
// 'job_done' will be sent with this job and its 'isAvailable'
// return value.
// options.storage : the storage where to check (optional)
// options.applicant : the applicant (optional)
// options.callback(result) : called to get the result.
// returns: - null if dependencies are missing
// - false if the job was not added
// - true if the job was added or replaced
// example :
// jio.checkNameAvailability({'user_name':'myName','callback':
// function (result) {
// if (result.status === 'done') {
// if (result.return_value === true) { // available
// } else { } // not available
// } else { } // Error
// }});
var settings = $.extend (true,{
'user_name': priv.storage.user_name,
'storage': priv.storage,
'applicant': priv.applicant,
'method': 'checkNameAvailability',
'callback': function () {}
},options);
// check dependencies
if (that.isReady() && settings.user_name &&
settings.storage && settings.applicant) {
return priv.queue.createJob ( settings );
}
return priv.wrongParametersError(settings);
};
that.saveDocument = function ( options ) {
// Load a document in the storage set in [options]
// or in the storage set at init. At the end of the job,
// 'job_done' will be sent with this job.
// options.storage : the storage where to save (optional)
// options.applicant : the applicant (optional)
// options.callback(result) : called to get the result.
// returns: - null if dependencies are missing
// - false if the job was not added
// - true if the job was added or replaced
// jio.saveDocument({'name':'file','content':'content',
// 'callback': function (result) {
// if (result.status === 'done') { // Saved
// } else { } // Error
// }});
var settings = $.extend(true,{
'storage': priv.storage,
'applicant': priv.applicant,
'content': '',
'method':'saveDocument',
'callback': function () {}
},options);
// check dependencies
if (that.isReady() && settings.name &&
settings.storage && settings.applicant) {
return priv.queue.createJob ( settings );
}
return priv.wrongParametersError(settings);
};
that.loadDocument = function ( options ) {
// Load a document in the storage set in [options]
// or in the storage set at init. At the end of the job,
// 'job_done' will be sent with this job and its 'content'
// return value.
// options.storage : the storage where to load (optional)
// options.applicant : the applicant (optional)
// options.callback(result) : called to get the result.
// returns: - null if dependencies are missing
// - false if the job was not added
// - true if the job was added or replaced
// jio.loadDocument({'name':'file','callback':
// function (result) {
// if (result.status === 'done') { // Loaded
// } else { } // Error
// }});
// result.return_value is a document object that looks like {
// name:'string',content:'string',
// creation_date:123,last_modified:456 }
var settings = $.extend (true,{
'storage': priv.storage,
'applicant': priv.applicant,
'method':'loadDocument',
'callback': function(){}
},options);
// check dependencies
if (that.isReady() && settings.name &&
settings.storage && settings.applicant) {
return priv.queue.createJob ( settings );
}
return priv.wrongParametersError(settings);
};
that.getDocumentList = function ( options ) {
// Get a document list of the user in the storage set in [options]
// or in the storage set at init.
// options.storage : the storage where to get the list (optional)
// options.applicant : the applicant (optional)
// options.callback(result) : called to get the result.
// returns: - null if dependencies are missing
// - false if the job was not added
// - true if the job was added or replaced
// jio.getDocumentList({'callback':
// function (result) {
// if (result.status === 'done') { // OK
// console.log(result.return_value);
// } else { } // Error
// }});
// result.return_value is an Array that contains documents objects.
var settings = $.extend (true,{
'storage': priv.storage,
'applicant': priv.applicant,
'method':'getDocumentList',
'callback':function(){}
},options);
// check dependencies
if (that.isReady() && settings.storage && settings.applicant ) {
return priv.queue.createJob( settings );
}
return priv.wrongParametersError(settings);
};
that.removeDocument = function ( options ) {
// Remove a document in the storage set in [options]
// or in the storage set at init.
// options.storage : the storage where to remove (optional)
// options.applicant : the applicant (optional)
// options.callback(result) : called to get the result.
// returns: - null if dependencies are missing
// - false if the job was not added
// - true if the job was added or replaced
// jio.removeDocument({'name':'file','callback':
// function (result) {
// if(result.status === 'done') { // Removed
// } else { } // Not Removed
// }});
var settings = $.extend (true,{
'storage': priv.storage,
'applicant': priv.applicant,
'method':'removeDocument',
'callback':function (){}
},options);
if (that.isReady() && settings.name &&
settings.storage && settings.applicant ) {
return priv.queue.createJob ( settings );
}
return priv.wrongParametersError(settings);
};
//// end Methods
//// Initialize var jioNamespace = (function(spec, my) {
var settings = $.extend(true,{'use_local_storage':true},spec.options); var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var storage_type_o = {'base':storage,'handler':storageHandler};
// objectify storage and applicant // Methods //
if(typeof spec.storage === 'string') {
spec.storage = JSON.parse(spec.storage);
}
if(typeof spec.applicant === 'string') {
spec.applicant = JSON.parse(spec.applicant);
}
// set init values /**
priv['storage'] = spec.storage; * Returns a storage from a storage description.
priv['applicant'] = spec.applicant; * @method storage
priv['id'] = 0; * @param {object} spec The specifications.
priv['pubsub'] = newPubSub({options:settings}); * @param {object} my The protected object.
priv['queue'] = newJobQueue({publisher:priv.pubsub, * @return {object} The storage object.
options:settings}); */
priv['listener'] = newJobListener({queue:priv.queue, that.storage = function(spec, my) {
options:settings}); spec = spec || {};
priv['ready'] = false; var type = spec.type || 'base';
if (settings.use_local_storage) { if (!storage_type_o[type]) {
priv['updater'] = newActivityUpdater({options:settings}); throw invalidStorageType({type:type});
} else {
priv['updater'] = null;
} }
console.log ('create storage: ' + JSON.stringify (spec) + JSON.stringify (my));
return storage_type_o[type](spec, my);
};
// check storage type /**
if (priv.storage && * Creates a new jio instance.
!jio_global_obj.storage_type_object[priv.storage.type]){ * @method newJio
console.error('Unknown storage type "' + priv.storage.type +'"'); * @param {object} spec The parameters:
* - {object} spec.storage: A storage description
* - {string} spec.storage.type: The storage type
* - {string} spec.storage.username: The user name
* - {string} spec.storage.applicationname: The application name
* @return {object} The new Jio instance.
*/
that.newJio = function(spec) {
var storage = spec;
if (typeof storage === 'string') {
storage = JSON.parse (storage);
} }
storage = storage || {type:'base'};
// start jio process console.log ('new jio: storage: ' + JSON.stringify (spec));
that.start(); return jio(spec);
//// end Initialize
return that;
}; };
// end JIO
////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////// /**
// Jio creator * Add a storage type to jio.
newJioCreator = function ( spec, my ) { * @method addStorageType
var that = {}; * @param {string} type The storage type
// Jio creator object * @param {function} constructor The associated constructor
// this object permit to create jio object */
that.newJio = function ( storage, applicant, options ) { that.addStorageType = function(type, constructor) {
// Return a new instance of JIO constructor = constructor || function(){return null;};
// storage: the storage object or json string if (storage_type_o[type]) {
// applicant: the applicant object or json string throw invalidStorageType({type:type,message:'Already known.'});
// options.useLocalStorage: if true, save job queue on localStorage.
var settings = $.extend(true,{'use_local_storage':true},options);
return newJioConstructor({storage:storage,
applicant:applicant,
options:settings});
};
that.newBaseStorage = function ( spec, my ) {
// Create a Jio Storage which can be used to design new storage.
return newBaseStorage( spec, my );
};
that.addStorageType = function ( type, constructor ) {
// Add a storage type to jio. Jio must have keys/types which are
// bound to a storage creation function. ex: 'local', will
// create a LocalStorage (in jio.storage.js).
// It can replace a older type with a newer creation function.
// type : the type of the storage.
// constructor : the function which returns a new storage object.
if (type && constructor) {
jio_global_obj.storage_type_object[type] = constructor;
return true;
} }
return false; storage_type_o[type] = constructor;
}; console.log ('adding: '+type);
that.getGlobalObject = function () {
// Returns the global jio values
return jio_global_obj;
};
that.getConstObject = function () {
// Returns a copy of the constants
return $.extend(true,{},jio_const_obj);
}; };
return that; return that;
}; }());
return newJioCreator();
// end Jio Creator
////////////////////////////////////////////////////////////////////////////
};
if (window.requirejs) {
define ('JIO',['LocalOrCookieStorage','jQuery'],jioLoaderFunction);
return undefined;
} else {
return jioLoaderFunction ( LocalOrCookieStorage, jQuery );
}
return jioNamespace;
}()); }());
/*! JIO - v0.1.0 - 2012-06-05 /*! JIO - v0.1.0 - 2012-06-11
* Copyright (c) 2012 Nexedi; Licensed */ * Copyright (c) 2012 Nexedi; Licensed */
var JIO=function(){var a=function(a,b){var c={job_method_object:{checkNameAvailability:{},saveDocument:{},loadDocument:{},getDocumentList:{},removeDocument:{}}},d={job_managing_method:{canSelect:function(a,b){return JSON.stringify(a.storage)===JSON.stringify(b.storage)&&JSON.stringify(a.applicant)===JSON.stringify(b.applicant)&&a.name===b.name?!0:!1},canRemoveFailOrDone:function(a,b){return a.status==="fail"||a.status==="done"?!0:!1},canEliminate:function(a,b){return a.status!=="on_going"&&(a.method==="removeDocument"&&b.method==="saveDocument"||a.method==="saveDocument"&&b.method==="removeDocument")?!0:!1},canReplace:function(a,b){return a.status!=="on_going"&&a.method===b.method&&a.date<b.date?!0:!1},cannotAccept:function(a,b){if(a.status!=="on_going"){if(a.method==="removeDocument"&&b.method==="loadDocument")return!0}else{if(a.method===b.method==="loadDocument")return!0;if(a.method==="removeDocument"&&(b.method==="loadDocument"||b.method==="removeDocument"))return!0;if(a.method===b.method==="saveDocument"&&a.content===b.content)return!0;if(a.method===b.method==="getDocumentList"||a.method===b.method==="checkNameAvailability")return!0}return!1},mustWait:function(a,b){return a.method==="getDocumentList"||a.method==="checkNameAvailability"||b.method==="getDocumentList"||b.method==="checkNameAvailability"?!1:!0}},queue_id:1,storage_type_object:{},max_wait_time:1e4},e,f,g,h,i,j,k,l;return e=function(a,c){var d={},e={},f={},g,h;return e.eventAction=function(a){return h=a&&f[a],h||(g=b.Callbacks(),h={publish:g.fire,subscribe:g.add,unsubscribe:g.remove},a&&(f[a]=h)),h},d.publish=function(a,b){e.eventAction(a).publish(b)},d.subscribe=function(a,b){return e.eventAction(a).subscribe(b),b},d.unsubscribe=function(a,b){e.eventAction(a).unsubscribe(b)},d},f=function(a,c){var d=b.extend(!0,{},a);return d.id=0,d.status="initial",d.date=Date.now(),d},g=function(e,g){var h={},i={},k="jio/id_array";return h.init=function(b){var c,d=function(){},f;i.use_local_storage&&(f=a.getItem(k)||[],e.publisher&&(i.publisher=e.publisher),i.jio_id=b.jio_id,i.job_object_name="jio/job_object/"+i.jio_id,f.push(i.jio_id),a.setItem(k,f)),i.job_object={},h.copyJobQueueToLocalStorage();for(c in i.recovered_job_object)i.recovered_job_object[c].callback=d,h.addJob(i.recovered_job_object[c])},h.close=function(){JSON.stringify(i.job_object)==="{}"&&a.deleteItem(i.job_object_name)},h.getNewQueueID=function(){var b=null,c=0,e=a.getItem(k)||[];for(b=0;b<e.length;b+=1)e[b]>=d.queue_id&&(d.queue_id=e[b]+1);return c=d.queue_id,d.queue_id++,c},h.recoverOlderJobObject=function(){var b=null,c=[],d=!1,e;if(i.use_local_storage){e=a.getItem(k)||[];for(b=0;b<e.length;b+=1)a.getItem("jio/id/"+e[b])<Date.now()-1e4?(a.deleteItem("jio/id/"+e[b]),i.recovered_job_object=a.getItem("jio/job_object/"+e[b]),a.deleteItem("jio/job_object/"+e[b]),d=!0):c.push(e[b]);d&&a.setItem(k,c)}},h.isThereJobsWhere=function(a){var b="id";if(!a)return!0;for(b in i.job_object)if(a(i.job_object[b]))return!0;return!1},h.copyJobQueueToLocalStorage=function(){return i.use_local_storage?a.setItem(i.job_object_name,i.job_object):!1},h.createJob=function(a){return h.addJob(f(a))},h.addJob=function(a){var b=!0,c=[],e=[],f=[],g=null,k="id";for(k in i.job_object){if(d.job_managing_method.canRemoveFailOrDone(i.job_object[k],a)){f.push(k);continue}if(d.job_managing_method.canSelect(i.job_object[k],a)){if(d.job_managing_method.canEliminate(i.job_object[k],a)){c.push(k);continue}if(d.job_managing_method.canReplace(i.job_object[k],a)){g=j({queue:h,job:i.job_object[k]}),g.replace(a),b=!1;break}if(d.job_managing_method.cannotAccept(i.job_object[k],a))return!1;if(d.job_managing_method.mustWait(i.job_object[k],a)){e.push(k);continue}}}if(b){for(k=0;k<c.length;k+=1)g=j({queue:h,job:i.job_object[c[k]]}),g.eliminate();if(e.length>0){a.status="wait",a.waiting_for={job_id_array:e};for(k=0;k<e.length;k+=1)i.job_object[e[k]]&&(i.job_object[e[k]].max_tries=1)}for(k=0;k<f.length;k+=1)h.removeJob(i.job_object[f[k]]);a.id=i.job_id,a.tries=0,i.job_id++,i.job_object[a.id]=a}return h.copyJobQueueToLocalStorage(),!0},h.removeJob=function(a){var c=b.extend({where:function(a){return!0}},a),d,e=!1,f="key";if(c.job)i.job_object[c.job.id]&&c.where(i.job_object[c.job.id])&&(delete i.job_object[c.job.id],e=!0);else for(f in i.job_object)c.where(i.job_object[f])&&(delete i.job_object[f],e=!0);e||console.error("No jobs was found, when trying to remove some."),h.copyJobQueueToLocalStorage()},h.resetAll=function(){var a="id";for(a in i.job_object)i.job_object[a].status="initial";h.copyJobQueueToLocalStorage()},h.invokeAll=function(){var a="id",b,c;for(a in i.job_object){c=!1;if(i.job_object[a].status==="initial")h.invoke(i.job_object[a]);else if(i.job_object[a].status==="wait"){c=!0;if(i.job_object[a].waiting_for.job_id_array)for(b=0;b<i.job_object[a].waiting_for.job_id_array.length;b+=1)if(i.job_object[i.job_object[a].waiting_for.job_id_array[b]]){c=!1;break}i.job_object[a].waiting_for.time&&i.job_object[a].waiting_for.time>Date.now()&&(c=!1),c&&h.invoke(i.job_object[a])}}this.copyJobQueueToLocalStorage()},h.invoke=function(a){var b;if(!c.job_method_object[a.method])return!1;h.isThereJobsWhere(function(b){return b.method===a.method&&b.method==="initial"})?a.status="on_going":(a.status="on_going",i.publisher.publish(c.job_method_object[a.method]["start_"+a.method])),b=j({queue:this,job:a}),b.execute()},h.ended=function(a){var d=b.extend(!0,{},a);h.removeJob({job:d});if(!c.job_method_object[d.method])return!1;if(!h.isThereJobsWhere(function(a){return a.method===d.method&&a.status==="on_going"||a.status==="initial"})){i.publisher.publish(c.job_method_object[d.method]["stop_"+d.method]);return}},h.clean=function(){h.removeJob(undefined,{where:function(a){return a.status==="fail"}})},i.use_local_storage=e.options.use_local_storage,i.publisher=e.publisher,i.job_id=1,i.jio_id=0,i.job_object_name="",i.job_object={},i.recovered_job_object={},h},h=function(a,b){var c={},d={};return d.interval=200,d.id=null,d.queue=a.queue,c.setIntervalDelay=function(a){d.interval=a},c.start=function(){return d.id?!1:(d.id=setInterval(function(){d.queue.recoverOlderJobObject(),d.queue.invokeAll()},d.interval),!0)},c.stop=function(){return d.id?(clearInterval(d.id),d.id=null,!0):!1},c},i=function(){var b={},c={};return c.interval=400,c.id=null,b.start=function(a){return c.id?!1:(b.touch(a),c.id=setInterval(function(){b.touch(a)},c.interval),!0)},b.stop=function(){return c.id?(clearInterval(c.id),c.id=null,!0):!1},b.touch=function(b){a.setItem("jio/id/"+b,Date.now())},b},j=function(a){var c={},e={};return e.job=a.job,e.callback=a.job.callback,e.queue=a.queue,e.res={status:"done",message:""},e.sorted=!1,e.limited=!1,e.research_done=!1,e.fail_checkNameAvailability=function(){e.res.message="Unable to check name availability."},e.done_checkNameAvailability=function(a){e.res.message=e.job.user_name+" is "+(a?"":"not ")+"available.",e.res.return_value=a},e.fail_loadDocument=function(){e.res.message="Unable to load document."},e.done_loadDocument=function(a){e.res.message="Document loaded.",e.res.return_value=a,e.res.return_value.last_modified=(new Date(e.res.return_value.last_modified)).getTime(),e.res.return_value.creation_date=(new Date(e.res.return_value.creation_date)).getTime()},e.fail_saveDocument=function(){e.res.message="Unable to save document."},e.done_saveDocument=function(){e.res.message="Document saved."},e.fail_getDocumentList=function(){e.res.message="Unable to retrieve document list."},e.done_getDocumentList=function(a){var b;e.res.message="Document list received.",e.res.return_value=a;for(b=0;b<e.res.return_value.length;b+=1)typeof e.res.return_value[b].last_modified!="number"&&(e.res.return_value[b].last_modified=(new Date(e.res.return_value[b].last_modified)).getTime()),typeof e.res.return_value[b].creation_date!="number"&&(e.res.return_value[b].creation_date=(new Date(e.res.return_value[b].creation_date)).getTime());!e.sorted&&typeof e.job.sort!="undefined"&&c.sortDocumentArray(e.res.return_value),!e.limited&&typeof e.job.limit!="undefined"&&typeof e.job.limit.begin!="undefined"&&typeof e.job.limit.end!="undefined"&&(e.res.return_value=c.limitDocumentArray(e.res.return_value)),!e.research_done&&typeof e.job.search!="undefined"&&(e.res.return_value=c.searchDocumentArray(e.res.return_value))},e.fail_removeDocument=function(){e.res.message="Unable to removed document."},e.done_removeDocument=function(){e.res.message="Document removed."},e.retryLater=function(){var a=e.job.tries*e.job.tries*1e3;a>d.max_wait_time&&(a=d.max_wait_time),e.job.status="wait",e.job.waiting_for={time:Date.now()+a}},c.cloneJob=function(){return b.extend(!0,{},e.job)},c.getUserName=function(){return e.job.user_name||""},c.getApplicantID=function(){return e.job.applicant.ID||""},c.getStorageUserName=function(){return e.job.storage.user_name||""},c.getStoragePassword=function(){return e.job.storage.password||""},c.getStorageURL=function(){return e.job.storage.url||""},c.getSecondStorage=function(){return e.job.storage.storage||{}},c.getStorageArray=function(){return e.job.storage.storage_array||[]},c.getFileName=function(){return e.job.name||""},c.getFileContent=function(){return e.job.content||""},c.cloneOptionObject=function(){return b.extend(!0,{},e.job.options)},c.getMaxTries=function(){return e.job.max_tries},c.getTries=function(){return e.job.tries||0},c.setMaxTries=function(a){e.job.max_tries=a},c.addJob=function(a){return e.queue.createJob(a)},c.eliminate=function(){e.job.max_tries=1,e.job.tries=1,c.fail("Job Stopped!",0)},c.replace=function(a){e.job.tries=0,e.job.date=a.date,e.job.callback=a.callback,e.res.status="fail",e.res.message="Job Stopped!",e.res.error={},e.res.error.status=0,e.res.error.statusText="Replaced",e.res.error.message="The job was replaced by a newer one.",e["fail_"+e.job.method](),e.callback(e.res)},c.fail=function(a){e.res.status="fail",e.res.error=a,e.res.error.status=e.res.error.status||0,e.res.error.statusText=e.res.error.statusText||"Unknown Error",e.res.error.array=e.res.error.array||[],e.res.error.message=e.res.error.message||"",!e.job.max_tries||e.job.tries<e.job.max_tries?e.retryLater():(e.job.status="fail",e["fail_"+e.job.method](),e.queue.ended(e.job),e.callback(e.res))},c.done=function(a){e.job.status="done",e["done_"+e.job.method](a),e.queue.ended(e.job),e.callback(e.res)},c.execute=function(){return e.job.tries=c.getTries()+1,d.storage_type_object[e.job.storage.type]?d.storage_type_object[e.job.storage.type]({job:e.job,queue:e.queue})[e.job.method]():null},c.checkNameAvailability=function(){c.fail({status:0,statusText:"Undefined Method",message:"This method must be redefined!"})},c.loadDocument=function(){c.fail({status:0,statusText:"Undefined Method",message:"This method must be redefined!"})},c.saveDocument=function(){c.fail({status:0,statusText:"Undefined Method",message:"This method must be redefined!"})},c.getDocumentList=function(){c.fail({status:0,statusText:"Undefined Method",message:"This method must be redefined!"})},c.removeDocument=function(){c.fail({status:0,statusText:"Undefined Method",message:"This method must be redefined!"})},c.sortDocumentArray=function(a){a.sort(function(a,b){var c,d;for(c in e.job.sort){var f=e.job.sort[c]==="descending"?-1:1;if(a[c]===b[c])continue;return a[c]>b[c]?f:-f}return 0}),c.sortDone()},c.sortDone=function(){e.sorted=!0},c.limitDocumentArray=function(a){return c.limitDone(),a.slice(e.job.limit.begin,e.job.limit.end)},c.limitDone=function(){e.limited=!0},c.searchDocumentArray=function(a){var b,d,f=[];for(b=0;b<a.length;b+=1)for(d in e.job.search){if(typeof a[b][d]=="undefined")continue;if(a[b][d].search(e.job.search[d])>-1){f.push(a[b]);break}}return c.researchDone(),f},c.researchDone=function(){e.research_done=!0},c},k=function(a,c){var f={},j={};j.wrongParametersError=function(a){var b="Method: "+a.method+", One or some parameters are undefined.";return console.error(b),a.callback({status:"fail",error:{status:0,statusText:"Undefined Parameter",message:b}}),null},f.getID=function(){return j.id},f.start=function(){return j.id!==0?!1:(j.id=j.queue.getNewQueueID(),j.queue.init({jio_id:j.id}),j.updater&&j.updater.start(j.id),j.listener.start(),j.ready=!0,f.isReady())},f.stop=function(){return j.queue.close(),j.listener.stop(),j.updater&&j.updater.stop(),j.ready=!1,j.id=0,!0},f.kill=function(){return j.queue.close(),j.listener.stop(),j.updater&&j.updater.stop(),j.ready=!1,!0},f.isReady=function(){return j.ready},f.publish=function(a,b){if(!f.isReady())return;return j.pubsub.publish(a,b)},f.subscribe=function(a,b){return j.pubsub.subscribe(a,b)},f.unsubscribe=function(a,b){return j.pubsub.unsubscribe(a,b)},f.checkNameAvailability=function(a){var c=b.extend(!0,{user_name:j.storage.user_name,storage:j.storage,applicant:j.applicant,method:"checkNameAvailability",callback:function(){}},a);return f.isReady()&&c.user_name&&c.storage&&c.applicant?j.queue.createJob(c):j.wrongParametersError(c)},f.saveDocument=function(a){var c=b.extend(!0,{storage:j.storage,applicant:j.applicant,content:"",method:"saveDocument",callback:function(){}},a);return f.isReady()&&c.name&&c.storage&&c.applicant?j.queue.createJob(c):j.wrongParametersError(c)},f.loadDocument=function(a){var c=b.extend(!0,{storage:j.storage,applicant:j.applicant,method:"loadDocument",callback:function(){}},a);return f.isReady()&&c.name&&c.storage&&c.applicant?j.queue.createJob(c):j.wrongParametersError(c)},f.getDocumentList=function(a){var c=b.extend(!0,{storage:j.storage,applicant:j.applicant,method:"getDocumentList",callback:function(){}},a);return f.isReady()&&c.storage&&c.applicant?j.queue.createJob(c):j.wrongParametersError(c)},f.removeDocument=function(a){var c=b.extend(!0,{storage:j.storage,applicant:j.applicant,method:"removeDocument",callback:function(){}},a);return f.isReady()&&c.name&&c.storage&&c.applicant?j.queue.createJob(c):j.wrongParametersError(c)};var k=b.extend(!0,{use_local_storage:!0},a.options);return typeof a.storage=="string"&&(a.storage=JSON.parse(a.storage)),typeof a.applicant=="string"&&(a.applicant=JSON.parse(a.applicant)),j.storage=a.storage,j.applicant=a.applicant,j.id=0,j.pubsub=e({options:k}),j.queue=g({publisher:j.pubsub,options:k}),j.listener=h({queue:j.queue,options:k}),j.ready=!1,k.use_local_storage?j.updater=i({options:k}):j.updater=null,j.storage&&!d.storage_type_object[j.storage.type]&&console.error('Unknown storage type "'+j.storage.type+'"'),f.start(),f},l=function(a,e){var f={};return f.newJio=function(a,c,d){var e=b.extend(!0,{use_local_storage:!0},d);return k({storage:a,applicant:c,options:e})},f.newBaseStorage=function(a,b){return j(a,b)},f.addStorageType=function(a,b){return a&&b?(d.storage_type_object[a]=b,!0):!1},f.getGlobalObject=function(){return d},f.getConstObject=function(){return b.extend(!0,{},c)},f},l()};return window.requirejs?(define("JIO",["LocalOrCookieStorage","jQuery"],a),undefined):a(LocalOrCookieStorage,jQuery)}(); var jio=function(){var a=function(a,b){var c={};a=a||{},b=b||{};var d={};return d.path=a.path||"",d.option=a.option||{},d.respond=d.option.onResponse||function(){},d.done=d.option.onDone||function(){},d.fail=d.option.onFail||function(){},d.end=function(){},c.getLabel=function(){return"command"},c.getPath=function(){return d.path},c.getOption=function(a){return d.option[a]},c.validate=function(a){c.validateState()},c.execute=function(a){c.validate(a),a.execute(c)},c.executeOn=function(a){},c.validateState=function(){if(d.path==="")throw g({command:c,message:"Path is empty"})},c.done=function(a){console.log("test"),d.done(a),d.respond({value:a}),d.end()},c.fail=function(a){d.fail(a),d.respond({error:a}),d.end()},c.onEndDo=function(a){d.end=a},c.serialized=function(){return{label:c.getLabel(),path:d.path,option:d.option}},c},b=function(b,c){var d=a(b,c);return b=b||{},c=c||{},d.label=function(){return"getDocumentList"},d.executeOn=function(a){a.getDocumentList(d)},d},c=function(b,c){var d=a(b,c);return b=b||{},c=c||{},d.label=function(){return"loadDocument"},d.executeOn=function(a){a.loadDocument(d)},d},d=function(b,c){var d=a(b,c);return b=b||{},c=c||{},d.label=function(){return"removeDocument"},d.executeOn=function(a){a.removeDocument(d)},d},e=function(b,c){var d=a(b,c);b=b||{},c=c||{};var e=b.content;d.label=function(){return"saveDocument"},d.getContent=function(){return e};var f=d.validate;return d.validate=function(a){if(typeof e!="string")throw g({command:d,message:"No data to save"});f(a)},d.executeOn=function(a){a.saveDocument(d)},d},f=function(a,b){var c={};return a=a||{},b=b||{},c.name="jioException",c.message=a.message||"Unknown Reason.",c.toString=function(){return c.name+": "+c.message},c},g=function(a,b){var c=f(a,b);a=a||{};var d=a.command;return c.name="invalidCommandState",c.toString=function(){return c.name+": "+d.getLabel()+", "+c.message},c},h=function(a,b){var c=f(a,b);a=a||{};var d=a.storage.getType();return c.name="invalidStorage",c.toString=function(){return c.name+": "+'Type "'+d+'", '+c.message},c},i=function(a,b){var c=f(a,b),d=a.type;return c.name="invalidStorageType",c.toString=function(){return c.name+": "+d+", "+c.message},c},j=function(a,b){var c=f(a,b);return c.name="jobNotReadyException",c},k=function(a,b){var c=f(a,b);return c.name="tooMuchTriesJobException",c},l=function(a,b){var c=f(a,b);return c.name="invalidJobException",c},m=function(a,b){var c={};return a=a||{},b=b||{},c.getLabel=function(){return"job status"},c.canStart=function(){},c.canRestart=function(){},c.serialized=function(){return{label:c.getLabel()}},c},n=function(a,b){var c=m(a,b);return a=a||{},b=b||{},c.getLabel=function(){return"done"},c.canStart=function(){return!1},c.canRestart=function(){return!1},c},o=function(a,b){var c=m(a,b);return a=a||{},b=b||{},c.getLabel=function(){return"fail"},c.canStart=function(){return!1},c.canRestart=function(){return!0},c},p=function(a,b){var c=m(a,b);return a=a||{},b=b||{},c.getLabel=function(){return"initial"},c.canStart=function(){return!0},c.canRestart=function(){return!0},c},q=function(a,b){var c=m(a,b);return a=a||{},b=b||{},c.getLabel=function(){return"on going"},c.canStart=function(){return!1},c.canRestart=function(){return!1},c},r=function(a,b){var c=m(a,b);a=a||{},b=b||{};var d=a.job_id_array||[],e=0;return c.getLabel=function(){return"wait"},c.waitForJob=function(a){var b;for(b=0;b<d.length;b+=1)if(d[b]===a.getId())return;d.push(a.getId())},c.dontWaitForJob=function(a){var b,c=[];for(b=0;b<d.length;b+=1)d[b]!==a.getId()&&c.push(d[b]);d=c},c.waitForTime=function(a){e=Date.now()+a},c.stopWaitForTime=function(){e=0},c.canStart=function(){return d.length===0&&Date.now()>=e},c.canRestart=function(){return!1},c.serialized=function(){return{label:c.getLabel(),waitfortime:e,waitforjob:d}},c},s=function(a,b){var c={};a=a||{},b=b||{};var d={};return d.type=a.type||"",c.getType=function(){return d.type},c.execute=function(a){a.executeOn(c)},c.isValid=function(){return!0},c.validate=function(a){a.validate(c)},c.serialized=function(){return{type:c.getType()}},c.saveDocument=function(a){throw h({storage:c,message:"Unknown storage."})},c.loadDocument=function(a){c.saveDocument()},c.removeDocument=function(a){c.saveDocument()},c.getDocumentList=function(a){c.saveDocument()},c},t=function(a,b){var c=s(a,b);a=a||{},b=b||{};var d={};return d.storage_a=a.storagelist||[],c.beforeExecute=function(a,b){},c.execute=function(a,b){var e;c.validate(a),c.beforeExecute(a,b);for(e=0;e<d.storage_a.length;e++)d.storage_a[e].execute(a);c.afterExecute(a,b)},c.afterExecute=function(a,b){c.done()},c.serialized=function(){return{type:d.type,storagelist:d.storagelist}},c},u=function(a,b){var c={};a=a||{},b=b||{};var d={};return d.id=a.id||0,d.interval=400,d.interval_id=null,d.touch=function(){LocalOrCookieStorage.setItem("jio/id/"+d.id,Date.now())},c.setId=function(a){d.id=a},c.setIntervalDelay=function(a){d.interval=a},c.getIntervalDelay=function(){return d.interval},c.start=function(){d.interval_id||(d.touch(),d.interval_id=setInterval(function(){d.touch()},d.interval))},c.stop=function(){d.interval_id!==null&&(clearInterval(d.interval_id),d.interval_id=null)},c}(),v=function(a,f){var g=function(a,b){var c={};a=a||{},b=b||{};var d={};return d.id=m.nextId(),d.command=a.command,d.storage=a.storage,d.status=p(),d.tried=0,d.max_retry=0,d.date=new Date,function(){if(!d.storage)throw l({job:c,message:"No storage set"});if(!d.command)throw l({job:c,message:"No command set"})}(),c.getCommand=function(){return d.command},c.getStatus=function(){return d.status},c.getId=function(){return d.id},c.getStorage=function(){return d.storage},c.isReady=function(){return d.tried===0?d.status.canStart():d.status.canRestart()},c.serialized=function(){return{id:d.id,date:d.date.getTime(),tried:d.tried,max_retry:d.max_retry,status:d.status.serialized(),command:d.command.serialized(),storage:d.storage.serialized()}},c.waitForJob=function(a){d.status.getLabel()!=="wait"&&(d.status=r()),d.status.waitForJob(a)},c.dontWaitFor=function(a){d.status.getLabel()==="wait"&&d.status.dontWaitForJob(a)},c.waitForTime=function(a){d.status.getLabel()!=="wait"&&(d.status=r()),d.status.waitForTime(a)},c.stopWaitForTime=function(){d.status.getLabel()==="wait"&&d.status.stopWaitForTime()},c.update=function(a){d.date=a.getDate()},c.execute=function(){if(d.max_retry!==0&&d.tried>=d.max_retry)throw k({job:c,message:"The job was invoked too much time."});if(!c.isReady())throw j({message:"Can not execute this job."});d.status=q(),d.tried++,d.command.onEndDo(function(){n.terminateJob(c)}),d.command.execute(d.storage)},c},h=function(a,b){var c={};a=a||{},b=b||{};var d=[],e=a.name||"";return c.add=function(a){d.push(a)},c.remove=function(a){var b,c=[];for(b=0;b<d.length;b+=1)d[b]!==a&&c.push(d[b]);d=c},c.register=function(){i.register(c)},c.unregister=function(){i.unregister(c)},c.trigger=function(a){var b;for(b=0;b<d.length;b++)d[b].apply(null,a)},c},i=function(a,b){var c={};a=a||{},b=b||{};var d={};return c.register=function(a){d[a]||(d[a]=h())},c.unregister=function(a){d[a]&&delete d[a]},c.at=function(a){return d[a]},c.on=function(a,b){c.register(a),c.at(a).add(b)},c.trigger=function(a,b){c.at(a).trigger(b)},c}(),m=function(a,b){var c={};a=a||{},b=b||{};var d=0;return c.nextId=function(){return d=d+1,d},c}(),n=function(a,b){var c={};a=a||{},b=b||{};var d="jio/job_array",e={};return e.id=a.id,e.interval_id=null,e.interval=200,e.job_a=[],e.getJobArrayName=function(){return d+"/"+e.id},e.getJobArray=function(){return LocalOrCookieStorage.getItem(e.getJobArrayName())||[]},e.copyJobArrayToLocal=function(){var a=[],b;for(b=0;b<e.job_a.length;b+=1)a.push(e.job_a[b].serialized());LocalOrCookieStorage.setItem(e.getJobArrayName(),a)},e.removeJob=function(a){var b,c=[];for(b=0;b<e.job_a.length;b+=1)e.job_a[b]!==a&&c.push(e.job_a[b]);e.job_a=c,e.copyJobArrayToLocal()},c.setId=function(a){e.id=a},c.start=function(){var a;e.interval_id===null&&(e.interval_id=setInterval(function(){for(a=0;a<e.job_a.length;a+=1)c.execute(e.job_a[a])},e.interval))},c.stop=function(){e.interval_id!==null&&(clearInterval(e.interval_id),e.interval_id=null,e.job_a.length===0&&LocalOrCookieStorage.deleteItem(e.getJobArrayName()))},c.execute=function(a){try{a.execute()}catch(b){switch(b.name){case"jobNotReadyException":break;case"tooMuchTriesJobException":break;default:throw b}}e.copyJobArrayToLocal()},c.terminateJob=function(a){e.removeJob(a),e.copyJobArrayToLocal()},c.addJob=function(a){var b=c.validateJobAccordingToJobList(e.job_a,a);e.manage(a,b),e.copyJobArrayToLocal()},c.validateJobAccordingToJobList=function(a,b){var c,d=[];for(c=0;c<a.length;c+=1)d.push(o.validateJobAccordingToJob(a[c],b));return d},e.manage=function(a,b){var d;if(e.job_a.length!==b.length)throw new RangeError("Array out of bound");for(d=0;d<b.length;d+=1)if(b[d].action==="dont accept")return;for(d=0;d<b.length;d+=1)switch(b[d].action){case"eliminate":c.eliminate(b[d].job);break;case"replace":a.update(b[d].job),e.copyJobArrayToLocal();return;case"wait":a.waitForJob(b[d].job);break;default:}e.job_a.push(a),e.copyJobArrayToLocal()},c.eliminate=function(a){var b,c=[];for(b=0;b<e.job_a.length;b+=1)e.job_a[b].getId()!==a.getId()&&c.push(e.job_a[b]);e.job_a=c},c}(),o=function(a,b){var c={},d={};return c.eliminate=function(){return"eliminate"},c.update=function(){return"update"},c.dontAccept=function(){return"dont accept"},c.wait=function(){return"wait"},c.none=function(){return"none"},d.compare={},d.default_compare=function(a,b){return a.getCommand().getPath()===b.getCommand().getPath()&&JSON.stringify(a.getStorage())===JSON.stringify(b.getStorage())},d.action={saveDocument:{"on going":{saveDocument:function(a,b){return a.getCommand().getContent()===b.getCommand().getContent()?c.dontAccept():c.wait()},loadDocument:c.wait,removeDocument:c.wait,getDocumentList:c.none},"not on going":{saveDocument:c.update,loadDocument:c.wait,removeDocument:c.eliminate,getDocumentList:c.none}},loadDocument:{"on going":{saveDocument:c.wait,loadDocument:c.dontAccept,removeDocument:c.wait,getDocumentList:c.none},"not on going":{saveDocument:c.wait,loadDocument:c.update,removeDocument:c.wait,getDocumentList:c.none}},removeDocument:{"on going":{saveDocument:c.wait,loadDocument:c.dontAccept,removeDocument:c.dontAccept,getDocumentList:c.none},"not on going":{saveDocument:c.eliminate,loadDocument:c.dontAccept,removeDocument:c.update,getDocumentList:c.none}},getDocumentList:{"on going":{saveDocument:c.none,loadDocument:c.none,removeDocument:c.none,getDocumentList:c.dontAccept},"not on going":{saveDocument:c.none,loadDocument:c.none,removeDocument:c.none,getDocumentList:c.update}}},d.default_action="none",d.getAction=function(a,b){var c,e,f;c=a.getCommand().getLabel(),e=b.getCommand().getLabel(),f=a.getStatus().getLabel()==="on going"?"on going":"not on going";try{return d.action[c][f][e](a,b)}catch(g){return d.default_action}},d.canCompare=function(a,b){var c=d.stringifyJobForCompare(a,b);return d.compare[c]?d.compare[c](a,b):d.default_compare(a,b)},c.validateJobAccordingToJob=function(a,b){var c=d.stringifyJobForAction(a,b);return d.canCompare(a,b)?{action:d.getAction(a,b),job:a}:{action:d.default_action,job:a}},c}(),s={};a=a||{},f=f||{};var t={},v="jio/id_array";return t.id=1,t.storage=w.storage(a,s),function(){var a,b=LocalOrCookieStorage.getItem(v)||[];for(a=0;a<b.length;a+=1)b[a]>=t.id&&(t.id=b[a]+1);b.push(t.id),LocalOrCookieStorage.setItem(v,b)}(),function(){u.setId(t.id),u.start(),n.setId(t.id),n.start()}(),s.start=function(){n.start()},s.stop=function(){n.stop()},s.getId=function(){return t.id},s.validateStorageDescription=function(a){return w.storage(a.type)(a).isValid()},s.saveDocument=function(a,b,c,d){c=c||{},c.onResponse=c.onResponse||function(){},c.onDone=c.onDone||function(){},c.onFail=c.onFail||function(){},c.max_retry=c.max_retry||0,console.log("add job save: "+JSON.stringify(t.storage.serialized())),n.addJob(g({storage:d?w.storage(d):t.storage,command:e({path:a,content:b,option:c})}))},s.loadDocument=function(a,b,d){b=b||{},b.onResponse=b.onResponse||function(){},b.onDone=b.onDone||function(){},b.onFail=b.onFail||function(){},b.max_retry=b.max_retry||0,b.metadata_only=b.metadata_only!==undefined?b.metadata_only:!1,n.addJob(g({storage:d?w.storage(d):t.storage,command:c({path:a,option:b})}))},s.removeDocument=function(a,b,c){b=b||{},b.onResponse=b.onResponse||function(){},b.onDone=b.onDone||function(){},b.onFail=b.onFail||function(){},b.max_retry=b.max_retry||0,n.addJob(g({storage:c?w.storage(c):t.storage,command:d({path:a,option:b})}))},s.getDocumentList=function(a,c,d){c=c||{},c.onResponse=c.onResponse||function(){},c.onDone=c.onDone||function(){},c.onFail=c.onFail||function(){},c.max_retry=c.max_retry||0,c.metadata_only=c.metadata_only!==undefined?c.metadata_only:!0,n.addJob(g({storage:d?w.storage(d):t.storage,command:b({path:a,option:c})}))},s},w=function(a,b){var c={};a=a||{},b=b||{};var d={base:s,handler:t};return c.storage=function(a,b){a=a||{};var c=a.type||"base";if(!d[c])throw i({type:c});return console.log("create storage: "+JSON.stringify(a)+JSON.stringify(b)),d[c](a,b)},c.newJio=function(a){var b=a;return typeof b=="string"&&(b=JSON.parse(b)),b=b||{type:"base"},console.log("new jio: storage: "+JSON.stringify(a)),v(a)},c.addStorageType=function(a,b){b=b||function(){return null};if(d[a])throw i({type:a,message:"Already known."});d[a]=b,console.log("adding: "+a)},c}();return w}();
\ No newline at end of file \ No newline at end of file
...@@ -10,22 +10,16 @@ ...@@ -10,22 +10,16 @@
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Dummy Storage 1 : all ok // Dummy Storage 1 : all ok
var newDummyStorageAllOk = function ( spec, my ) { var newDummyStorageAllOk = function ( spec, my ) {
var that = Jio.newBaseStorage( spec, my ); var that = Jio.storage( {type:'base'}, my );
that.checkNameAvailability = function () {
// The [job.userName] IS available.
// wait a little in order to simulate asynchronous operation that.setType('dummyallok');
setTimeout(function () {
that.done(true);
}, 100);
}; // end userNameAvailable
that.saveDocument = function () { that.saveDocument = function (command) {
// Tells us that the document is saved. // Tells us that the document is saved.
// wait a little in order to simulate asynchronous saving // wait a little in order to simulate asynchronous saving
setTimeout (function () { setTimeout (function () {
that.done(); command.done();
}, 100); }, 100);
}; // end saveDocument }; // end saveDocument
...@@ -39,8 +33,8 @@ ...@@ -39,8 +33,8 @@
// wait a little in order to simulate asynchronous operation // wait a little in order to simulate asynchronous operation
setTimeout(function () { setTimeout(function () {
var doc = { var doc = {
'content': 'content',
'name': 'file', 'name': 'file',
'content': 'content',
'creation_date': 10000, 'creation_date': 10000,
'last_modified': 15000}; 'last_modified': 15000};
that.done(doc); that.done(doc);
...@@ -49,7 +43,7 @@ ...@@ -49,7 +43,7 @@
that.getDocumentList = function () { that.getDocumentList = function () {
// It returns a document array containing all the user documents // It returns a document array containing all the user documents
// informations, but not their content. // with/but their content.
// the list is [object,object] -> object = {'name':string, // the list is [object,object] -> object = {'name':string,
// 'last_modified':date,'creation_date':date} // 'last_modified':date,'creation_date':date}
...@@ -57,12 +51,18 @@ ...@@ -57,12 +51,18 @@
setTimeout(function () { setTimeout(function () {
var list = [ var list = [
{'name':'file', {'name':'file',
'content':'filecontent',
'creation_date':10000, 'creation_date':10000,
'last_modified':15000}, 'last_modified':15000},
{'name':'memo', {'name':'memo',
'content':'memocontent',
'creation_date':20000, 'creation_date':20000,
'last_modified':25000 'last_modified':25000
}]; }];
if (command.getOption('metadata_only')) {
delete list[0].content;
delete list[1].content;
}
that.done(list); that.done(list);
}, 100); }, 100);
}; // end getDocumentList }; // end getDocumentList
...@@ -75,211 +75,211 @@ ...@@ -75,211 +75,211 @@
}, 100); }, 100);
}; };
return that; return that;
},
// end Dummy Storage All Ok
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Dummy Storage 2 : all fail
newDummyStorageAllFail = function ( spec, my ) {
var that = Jio.newBaseStorage( spec, my );
that.checkNameAvailability = function () {
// Fails to check [job.userName].
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
that.fail({status:0,statusText:'Unknown Error',
message:'Unknown error.'});
}, 100);
}; // end userNameAvailable
that.saveDocument = function () {
// Tells us that the document is not saved.
// wait a little in order to simulate asynchronous saving
setTimeout (function () {
that.fail({status:0,statusText:'Unknown Error',
message:'Unknown error.'});
}, 100);
}; // end saveDocument
that.loadDocument = function () {
// Returns a document object containing nothing.
// document object is {'name':string,'content':string,
// 'creation_date':date,'last_modified':date}
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
that.fail({status:0,statusText:'Unknown Error',
message:'Unknown error.'});
}, 100);
}; // end loadDocument
that.getDocumentList = function () {
// It returns nothing.
// the list is [object,object] -> object = {'name':string,
// 'last_modified':date,'creation_date':date}
setTimeout(function () {
that.fail({status:0,statusText:'Unknown Error',
message:'Unknown error.'});
}, 100);
}; // end getDocumentList
that.removeDocument = function () {
// Remove a document from the storage.
// returns {'status':string,'message':string,'isRemoved':boolean}
// in the jobendcallback arguments.
setTimeout (function () {
that.fail({status:0,statusText:'Unknown Error',
message:'Unknown error.'});
}, 100);
};
return that;
},
// end Dummy Storage All Fail
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Dummy Storage 3 : all not found
newDummyStorageAllNotFound = function ( spec, my ) {
var that = Jio.newBaseStorage( spec, my );
that.checkNameAvailability = function () {
// [job.userName] not found, so the name is available.
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
that.done(true);
}, 100);
}; // end userNameAvailable
that.saveDocument = function () {
// Document does not exists yet, create it.
// wait a little in order to simulate asynchronous saving
setTimeout (function () {
that.done();
}, 100);
}; // end saveDocument
that.loadDocument = function () {
// Returns a document object containing nothing.
// document object is {'name':string,'content':string,
// 'creation_date':date,'last_modified':date}
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
that.fail({status:404,statusText:'Not Found',
message:'Document "'+ that.getFileName() +
'" not found.'});
}, 100);
}; // end loadDocument
that.getDocumentList = function () {
// It returns nothing.
// the list is [object,object] -> object = {'name':string,
// 'last_modified':date,'creation_date':date}
setTimeout(function () {
that.fail({status:404,statusText:'Not Found',
message:'User list not found.'});
}, 100);
}; // end getDocumentList
that.removeDocument = function () {
// Remove a document from the storage.
// returns {'status':string,'message':string,'isRemoved':boolean}
// in the jobendcallback arguments.
setTimeout (function () {
that.done();
}, 100);
}; };
return that; // end Dummy Storage All Ok
},
// end Dummy Storage All Not Found
////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Dummy Storage 4 : all 3 tries
newDummyStorageAll3Tries = function ( spec, my ) {
var that = Jio.newBaseStorage( spec, my ), priv = {};
priv.doJob = function (if_ok_return) {
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
priv.Try3OKElseFail (that.cloneJob().tries,if_ok_return);
}, 100);
};
priv.Try3OKElseFail = function (tries,if_ok_return) {
if ( tries === 3 ) {
return that.done(if_ok_return);
}
if ( tries < 3 ) {
return that.fail({message:'' + (3 - tries) + ' tries left.'});
}
if ( tries > 3 ) {
return that.fail({message:'Too much tries.'});
}
};
that.checkNameAvailability = function () { // ////////////////////////////////////////////////////////////////////////////
priv.doJob (true); // // Dummy Storage 2 : all fail
}; // end userNameAvailable // newDummyStorageAllFail = function ( spec, my ) {
// var that = Jio.newBaseStorage( spec, my );
that.saveDocument = function () {
priv.doJob (); // that.checkNameAvailability = function () {
}; // end saveDocument // // Fails to check [job.userName].
that.loadDocument = function () { // // wait a little in order to simulate asynchronous operation
priv.doJob ({ // setTimeout(function () {
'content': 'content2', // that.fail({status:0,statusText:'Unknown Error',
'name': 'file', // message:'Unknown error.'});
'creation_date': 11000, // }, 100);
'last_modified': 17000 // }; // end userNameAvailable
});
}; // end loadDocument // that.saveDocument = function () {
// // Tells us that the document is not saved.
that.getDocumentList = function () {
priv.doJob([{'name':'file', // // wait a little in order to simulate asynchronous saving
'creation_date':10000, // setTimeout (function () {
'last_modified':15000}, // that.fail({status:0,statusText:'Unknown Error',
{'name':'memo', // message:'Unknown error.'});
'creation_date':20000, // }, 100);
'last_modified':25000} // }; // end saveDocument
]);
}; // end getDocumentList // that.loadDocument = function () {
// // Returns a document object containing nothing.
that.removeDocument = function () {
priv.doJob(); // // document object is {'name':string,'content':string,
}; // end removeDocument // // 'creation_date':date,'last_modified':date}
return that; // // wait a little in order to simulate asynchronous operation
}; // setTimeout(function () {
// end Dummy Storage All 3 Tries // that.fail({status:0,statusText:'Unknown Error',
//////////////////////////////////////////////////////////////////////////// // message:'Unknown error.'});
// }, 100);
// }; // end loadDocument
// that.getDocumentList = function () {
// // It returns nothing.
// // the list is [object,object] -> object = {'name':string,
// // 'last_modified':date,'creation_date':date}
// setTimeout(function () {
// that.fail({status:0,statusText:'Unknown Error',
// message:'Unknown error.'});
// }, 100);
// }; // end getDocumentList
// that.removeDocument = function () {
// // Remove a document from the storage.
// // returns {'status':string,'message':string,'isRemoved':boolean}
// // in the jobendcallback arguments.
// setTimeout (function () {
// that.fail({status:0,statusText:'Unknown Error',
// message:'Unknown error.'});
// }, 100);
// };
// return that;
// },
// // end Dummy Storage All Fail
// ////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////
// // Dummy Storage 3 : all not found
// newDummyStorageAllNotFound = function ( spec, my ) {
// var that = Jio.newBaseStorage( spec, my );
// that.checkNameAvailability = function () {
// // [job.userName] not found, so the name is available.
// // wait a little in order to simulate asynchronous operation
// setTimeout(function () {
// that.done(true);
// }, 100);
// }; // end userNameAvailable
// that.saveDocument = function () {
// // Document does not exists yet, create it.
// // wait a little in order to simulate asynchronous saving
// setTimeout (function () {
// that.done();
// }, 100);
// }; // end saveDocument
// that.loadDocument = function () {
// // Returns a document object containing nothing.
// // document object is {'name':string,'content':string,
// // 'creation_date':date,'last_modified':date}
// // wait a little in order to simulate asynchronous operation
// setTimeout(function () {
// that.fail({status:404,statusText:'Not Found',
// message:'Document "'+ that.getFileName() +
// '" not found.'});
// }, 100);
// }; // end loadDocument
// that.getDocumentList = function () {
// // It returns nothing.
// // the list is [object,object] -> object = {'name':string,
// // 'last_modified':date,'creation_date':date}
// setTimeout(function () {
// that.fail({status:404,statusText:'Not Found',
// message:'User list not found.'});
// }, 100);
// }; // end getDocumentList
// that.removeDocument = function () {
// // Remove a document from the storage.
// // returns {'status':string,'message':string,'isRemoved':boolean}
// // in the jobendcallback arguments.
// setTimeout (function () {
// that.done();
// }, 100);
// };
// return that;
// },
// // end Dummy Storage All Not Found
// ////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////
// // Dummy Storage 4 : all 3 tries
// newDummyStorageAll3Tries = function ( spec, my ) {
// var that = Jio.newBaseStorage( spec, my ), priv = {};
// priv.doJob = function (if_ok_return) {
// // wait a little in order to simulate asynchronous operation
// setTimeout(function () {
// priv.Try3OKElseFail (that.cloneJob().tries,if_ok_return);
// }, 100);
// };
// priv.Try3OKElseFail = function (tries,if_ok_return) {
// if ( tries === 3 ) {
// return that.done(if_ok_return);
// }
// if ( tries < 3 ) {
// return that.fail({message:'' + (3 - tries) + ' tries left.'});
// }
// if ( tries > 3 ) {
// return that.fail({message:'Too much tries.'});
// }
// };
// that.checkNameAvailability = function () {
// priv.doJob (true);
// }; // end userNameAvailable
// that.saveDocument = function () {
// priv.doJob ();
// }; // end saveDocument
// that.loadDocument = function () {
// priv.doJob ({
// 'content': 'content2',
// 'name': 'file',
// 'creation_date': 11000,
// 'last_modified': 17000
// });
// }; // end loadDocument
// that.getDocumentList = function () {
// priv.doJob([{'name':'file',
// 'creation_date':10000,
// 'last_modified':15000},
// {'name':'memo',
// 'creation_date':20000,
// 'last_modified':25000}
// ]);
// }; // end getDocumentList
// that.removeDocument = function () {
// priv.doJob();
// }; // end removeDocument
// return that;
// };
// // end Dummy Storage All 3 Tries
// ////////////////////////////////////////////////////////////////////////////
// add key to storageObjectType of global jio // add key to storageObjectType of global jio
Jio.addStorageType('dummyallok', newDummyStorageAllOk); Jio.addStorageType('dummyallok', newDummyStorageAllOk);
Jio.addStorageType('dummyallfail', newDummyStorageAllFail); // Jio.addStorageType('dummyallfail', newDummyStorageAllFail);
Jio.addStorageType('dummyallnotfound', newDummyStorageAllNotFound); // Jio.addStorageType('dummyallnotfound', newDummyStorageAllNotFound);
Jio.addStorageType('dummyall3tries', newDummyStorageAll3Tries); // Jio.addStorageType('dummyall3tries', newDummyStorageAll3Tries);
}; };
if (window.requirejs) { if (window.requirejs) {
define ('JIODummyStorages',['JIO'], jioDummyStorageLoader); define ('JIODummyStorages',['JIO'], jioDummyStorageLoader);
} else { } else {
jioDummyStorageLoader ( JIO ); jioDummyStorageLoader ( jio );
} }
}()); }());
var activityUpdater = (function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var priv = {};
priv.id = spec.id || 0;
priv.interval = 400;
priv.interval_id = null;
// Methods //
priv.touch = function() {
LocalOrCookieStorage.setItem ('jio/id/'+priv.id, Date.now());
};
that.setId = function(id) {
priv.id = id;
};
that.setIntervalDelay = function(ms) {
priv.interval = ms;
};
that.getIntervalDelay = function() {
return priv.interval;
};
that.start = function() {
if (!priv.interval_id) {
priv.touch();
priv.interval_id = setInterval(function() {
priv.touch();
}, priv.interval);
}
};
that.stop = function() {
if (priv.interval_id !== null) {
clearInterval(priv.interval_id);
priv.interval_id = null;
}
};
return that;
}());
\ No newline at end of file
var announcement = function(spec) {
var spec = spec || {};
var that = {};
var callbacks = [];
that.name = spec.name;
that.add = function(callback) {
callbacks.push(callback);
};
that.remove = function(callback) {
//TODO;
};
that.register = function() {
announcer.register(that);
};
that.unregister = function() {
announcer.unregister(that);
};
that.trigger = function(args) {
for(var i=0; i<callbacks.length; i++) {
callbacks[i].apply(null, args);
};
};
return that;
};
var announcer = (function() {
var that = {};
var announcements = {};
that.register(name) {
if(!announcements[name]) {
announcements[name] = announcement();
}
};
that.unregister = function(name) {
//TODO
};
that.at = function(name) {
return announcements[name];
};
that.on = function(name, callback) {
that.register(name);
that.at(name).add(callback);
};
that.trigger(name, args) {
that.at(name).trigger(args);
}
return that;
}());
var announcement = function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var callback_a = [];
var name = spec.name || '';
// Methods //
that.add = function(callback) {
callback_a.push(callback);
};
that.remove = function(callback) {
var i, tmp_callback_a = [];
for (i = 0; i < callback_a.length; i+= 1) {
if (callback_a[i] !== callback) {
tmp_callback_a.push(callback_a[i]);
}
}
callback_a = tmp_callback_a;
};
that.register = function() {
announcer.register(that);
};
that.unregister = function() {
announcer.unregister(that);
};
that.trigger = function(args) {
var i;
for(i = 0; i < callback_a.length; i++) {
callback_a[i].apply(null, args);
}
};
return that;
};
var announcer = (function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var announcement_o = {};
// Methods //
that.register = function(name) {
if(!announcement_o[name]) {
announcement_o[name] = announcement();
}
};
that.unregister = function(name) {
if (announcement_o[name]) {
delete announcement_o[name];
}
};
that.at = function(name) {
return announcement_o[name];
};
that.on = function(name, callback) {
that.register(name);
that.at(name).add(callback);
};
that.trigger = function(name, args) {
that.at(name).trigger(args);
};
return that;
}());
var command = function(spec) { var command = function(spec, my) {
var spec = spec || {};
var that = {}; var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var priv = {};
priv.path = spec.path || '';
priv.option = spec.option || {};
priv.respond = priv.option.onResponse || function(){};
priv.done = priv.option.onDone || function(){};
priv.fail = priv.option.onFail || function(){};
priv.end = function() {};
var id = idHandler.nextId(); // Methods //
var date = new Date(); /**
* Returns the label of the command.
that.document = spec.document; * @method getLabel
* @return {string} The label.
that.getDate = function() { */
return date; that.getLabel = function() {
return 'command';
}; };
that.getId = function() { /**
return id; * Returns the path of the command.
* @method getPath
* @return {string} The path of the command.
*/
that.getPath = function() {
return priv.path;
}; };
that.label = function() { /**
return 'command'; * Returns the value of an option.
* @method getOption
* @param {string} optionname The option name.
* @return The option value.
*/
that.getOption = function(optionname) {
return priv.option[optionname];
}; };
/* /**
* Specialized commands that override this should also call `super` * Validates the storage.
* Override this function.
* @param {object} handler The storage handler
*/ */
that.validate = function(handler) { that.validate = function(handler) {
that.validateState(); that.validateState();
}; };
/* /**
* Delegate actual excecution the the handler object * Delegate actual excecution the storage handler.
* @param {object} handler The storage handler.
*/ */
that.execute = function(handler) { that.execute = function(handler) {
that.validate(handler);
handler.execute(that); handler.execute(that);
}; };
that.executeOn = function(storage) { /**
}; * Execute the good method from the storage.
* Override this function.
* @method executeOn
* @param {object} storage The storage.
*/
that.executeOn = function(storage) {};
/* /*
* Do not override. * Do not override.
* Override `validate()` instead * Override `validate()' instead
*/ */
that.validateState = function() { that.validateState = function() {
if(!that.document) { if (priv.path === '') {
throw invalidCommandState(that); throw invalidCommandState({command:that,message:'Path is empty'});
}
};
that.done = function(return_value) {
console.log ('test');
priv.done(return_value);
priv.respond({status:doneStatus(),value:return_value});
priv.end();
};
that.fail = function(return_error) {
priv.fail(return_error);
priv.respond({status:failStatus(),error:return_error});
priv.end();
};
that.onEndDo = function(fun) {
priv.end = fun;
}; };
/**
* Returns a serialized version of this command.
* Override this function.
* @method serialized
* @return {object} The serialized command.
*/
that.serialized = function() {
return {label:that.getLabel(),
path:priv.path,
option:priv.option};
}; };
return that; return that;
......
var getDocumentList = function(spec, my) {
var that = command(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.label = function() {
return 'getDocumentList';
};
that.executeOn = function(storage) {
storage.getDocumentList(that);
};
return that;
};
var removeCommand = function(spec) { var loadDocument = function(spec, my) {
var that = command(spec, my);
var spec = spec || {}; spec = spec || {};
var that = command(spec); my = my || {};
// Attributes //
// Methods //
that.label = function() { that.label = function() {
return 'removeCommand'; return 'loadDocument';
}; };
that.executeOn = function(storage) { that.executeOn = function(storage) {
storage.executeRemove(that); storage.loadDocument(that);
}; };
return that; return that;
......
var saveCommand = function(spec) { var removeDocument = function(spec, my) {
var that = command(spec, my);
var spec = spec || {}; spec = spec || {};
var that = command(spec); my = my || {};
// Attributes //
// Methods //
that.label = function() { that.label = function() {
return 'saveCommand'; return 'removeDocument';
}; };
that.executeOn = function(storage) { that.executeOn = function(storage) {
storage.executeSave(that); storage.removeDocument(that);
}; };
return that; return that;
......
var saveDocument = function(spec, my) {
var that = command(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
var content = spec.content;
// Methods //
that.label = function() {
return 'saveDocument';
};
that.getContent = function() {
return content;
};
/**
* Validates the storage handler.
* @param {object} handler The storage handler
*/
var super_validate = that.validate;
that.validate = function(handler) {
if (typeof content !== 'string') {
throw invalidCommandState({command:that,message:'No data to save'});
}
super_validate(handler);
};
that.executeOn = function(storage) {
storage.saveDocument(that);
};
return that;
};
var document = function(spec) {
var spec = spec || {};
var that = {};
var name = spec.name;
var content = spec.content;
that.getName = function() {
return name;
};
that.getContent = function() {
return content;
};
}
var jioException = function() { var jioException = function(spec, my) {
return {}; var that = {};
spec = spec || {};
my = my || {};
that.name = 'jioException';
that.message = spec.message || 'Unknown Reason.';
that.toString = function() {
return that.name + ': ' + that.message;
};
return that;
};
var invalidCommandState = function(spec, my) {
var that = jioException(spec, my);
spec = spec || {};
var command = spec.command;
that.name = 'invalidCommandState';
that.toString = function() {
return that.name +': ' +
command.getLabel() + ', ' + that.message;
};
return that;
}; };
var invalidCommandState = function(command) { var invalidStorage = function(spec, my) {
var that = jioException(); var that = jioException(spec, my);
that.command = command; spec = spec || {};
var type = spec.storage.getType();
that.name = 'invalidStorage';
that.toString = function() {
return that.name +': ' +
'Type "'+type + '", ' + that.message;
};
return that;
};
var invalidStorageType = function(spec, my) {
var that = jioException(spec, my);
var type = spec.type;
that.name = 'invalidStorageType';
that.toString = function() {
return that.name +': ' +
type + ', ' + that.message;
};
return that;
};
var jobNotReadyException = function(spec, my) {
var that = jioException(spec, my);
that.name = 'jobNotReadyException';
return that;
};
var tooMuchTriesJobException = function(spec, my) {
var that = jioException(spec, my);
that.name = 'tooMuchTriesJobException';
return that;
};
var invalidJobException = function(spec, my) {
var that = jioException(spec, my);
that.name = 'invalidJobException';
return that; return that;
}; };
// Class jio
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var priv = {};
var jio_id_array_name = 'jio/id_array';
priv.id = 1;
priv.storage = jioNamespace.storage(spec, that);
// initialize //
(function () {
// Initialize the jio id and add the new id to the list
var i,
jio_id_a = LocalOrCookieStorage.getItem (jio_id_array_name) || [];
for (i = 0; i < jio_id_a.length; i+= 1) {
if (jio_id_a[i] >= priv.id) {
priv.id = jio_id_a[i] + 1;
}
}
jio_id_a.push(priv.id);
LocalOrCookieStorage.setItem (jio_id_array_name,jio_id_a);
}());
(function (){
// Start Jio updater, and the jobManager
activityUpdater.setId(priv.id);
activityUpdater.start();
jobManager.setId(priv.id);
jobManager.start();
}());
// Methods //
that.start = function() {
jobManager.start();
};
that.stop = function() {
jobManager.stop();
};
/**
* Returns the jio id.
* @method getId
* @return {number} The jio id.
*/
that.getId = function() {
return priv.id;
};
/**
* Checks if the storage description is valid or not.
* @method validateStorageDescription
* @param {object} description The description object.
* @return {boolean} true if ok, else false.
*/
that.validateStorageDescription = function(description) {
return jioNamespace.storage(description.type)(description).isValid();
};
/**
* Save a document.
* @method saveDocument
* @param {string} path The document path name.
* @param {string} content The document's content.
* @param {object} option (optional) Contains some options:
* - {function} onResponse The callback called when the job is terminated.
* - {function} onDone The callback called when the job has passed.
* - {function} onFail The callback called when the job has fail.
* - {number} max_retry The number max of retries, 0 = infinity.
* @param {object} specificstorage (optional) A specific storage, only if
* you want to save this document elsewhere.
*/
that.saveDocument = function(path, content, option, specificstorage) {
option = option || {};
option.onResponse = option.onResponse || function(){};
option.onDone = option.onDone || function(){};
option.onFail = option.onFail || function(){};
option.max_retry = option.max_retry || 0;
console.log ('add job save: ' + JSON.stringify (priv.storage.serialized()));
jobManager.addJob(
job({storage:(specificstorage?
jioNamespace.storage(specificstorage):
priv.storage),
command:saveDocument(
{path:path,content:content,option:option})}));
};
/**
* Load a document.
* @method loadDocument
* @param {string} path The document path name.
* @param {object} option (optional) Contains some options:
* - {function} onResponse The callback called when the job is terminated.
* - {function} onDone The callback called when the job has passed.
* - {function} onFail The callback called when the job has fail.
* - {number} max_retry The number max of retries, 0 = infinity.
* - {boolean} metadata_only Load only document metadata.
* @param {object} specificstorage (optional) A specific storage, only if
* you want to save this document elsewhere.
*/
that.loadDocument = function(path, option, specificstorage) {
option = option || {};
option.onResponse = option.onResponse || function(){};
option.onDone = option.onDone || function(){};
option.onFail = option.onFail || function(){};
option.max_retry = option.max_retry || 0;
option.metadata_only = (option.metadata_only !== undefined?
option.metadata_only:false);
jobManager.addJob(
job({storage:(specificstorage?
jioNamespace.storage(specificstorage):
priv.storage),
command:loadDocument(
{path:path,option:option})}));
};
/**
* Remove a document.
* @method removeDocument
* @param {string} path The document path name.
* @param {object} option (optional) Contains some options:
* - {function} onResponse The callback called when the job is terminated.
* - {function} onDone The callback called when the job has passed.
* - {function} onFail The callback called when the job has fail.
* - {number} max_retry The number max of retries, 0 = infinity.
* @param {object} specificstorage (optional) A specific storage, only if
* you want to save this document elsewhere.
*/
that.removeDocument = function(path, option, specificstorage) {
option = option || {};
option.onResponse = option.onResponse || function(){};
option.onDone = option.onDone || function(){};
option.onFail = option.onFail || function(){};
option.max_retry = option.max_retry || 0;
jobManager.addJob(
job({storage:(specificstorage?
jioNamespace.storage(specificstorage):
priv.storage),
command:removeDocument(
{path:path,option:option})}));
};
/**
* Get a document list from a folder.
* @method getDocumentList
* @param {string} path The folder path.
* @param {object} option (optional) Contains some options:
* - {function} onResponse The callback called when the job is terminated.
* - {function} onDone The callback called when the job has passed.
* - {function} onFail The callback called when the job has fail.
* - {number} max_retry The number max of retries, 0 = infinity.
* - {boolean} metadata_only Load only document metadata
* @param {object} specificstorage (optional) A specific storage, only if
* you want to save this document elsewhere.
*/
that.getDocumentList = function(path, option, specificstorage) {
option = option || {};
option.onResponse = option.onResponse || function(){};
option.onDone = option.onDone || function(){};
option.onFail = option.onFail || function(){};
option.max_retry = option.max_retry || 0;
option.metadata_only = (option.metadata_only !== undefined?
option.metadata_only:true);
jobManager.addJob(
job({storage:(specificstorage?
jioNamespace.storage(specificstorage):
priv.storage),
command:getDocumentList(
{path:path,option:option})}));
};
return that;
}; // End Class jio
var jio = function(spec, my) {
var jioNamespace = (function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var storage_type_o = {'base':storage,'handler':storageHandler};
// Methods //
/**
* Returns a storage from a storage description.
* @method storage
* @param {object} spec The specifications.
* @param {object} my The protected object.
* @return {object} The storage object.
*/
that.storage = function(spec, my) {
spec = spec || {};
var type = spec.type || 'base';
if (!storage_type_o[type]) {
throw invalidStorageType({type:type});
}
console.log ('create storage: ' + JSON.stringify (spec) + JSON.stringify (my));
return storage_type_o[type](spec, my);
};
/**
* Creates a new jio instance.
* @method newJio
* @param {object} spec The parameters:
* - {object} spec.storage: A storage description
* - {string} spec.storage.type: The storage type
* - {string} spec.storage.username: The user name
* - {string} spec.storage.applicationname: The application name
* @return {object} The new Jio instance.
*/
that.newJio = function(spec) {
var storage = spec;
if (typeof storage === 'string') {
storage = JSON.parse (storage);
}
storage = storage || {type:'base'};
console.log ('new jio: storage: ' + JSON.stringify (spec));
return jio(spec);
};
/**
* Add a storage type to jio.
* @method addStorageType
* @param {string} type The storage type
* @param {function} constructor The associated constructor
*/
that.addStorageType = function(type, constructor) {
constructor = constructor || function(){return null;};
if (storage_type_o[type]) {
throw invalidStorageType({type:type,message:'Already known.'});
}
storage_type_o[type] = constructor;
console.log ('adding: '+type);
};
return that;
}());
var job = function(spec) { var job = function(spec, my) {
var spec = spec || {};
var that = {}; var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var priv = {};
priv.id = jobIdHandler.nextId();
priv.command = spec.command;
priv.storage = spec.storage;
priv.status = initialStatus();
priv.tried = 0;
priv.max_retry = 0;
priv.date = new Date();
var command = spec.command; // Initialize //
(function() {
if (!priv.storage){
throw invalidJobException({job:that,message:'No storage set'});
}
if (!priv.command){
throw invalidJobException({job:that,message:'No command set'});
}
}());
// Methods //
/**
* Returns the job command.
* @method getCommand
* @return {object} The job command.
*/
that.getCommand = function() { that.getCommand = function() {
return command; return priv.command;
};
that.getStatus = function() {
return priv.status;
};
that.getId = function() {
return priv.id;
}; };
that.getStorage = function() {
return priv.storage;
};
/**
* Checks if the job is ready.
* @method isReady
* @return {boolean} true if ready, else false.
*/
that.isReady = function() {
if (priv.tried === 0) {
return priv.status.canStart();
} else {
return priv.status.canRestart();
}
};
/**
* Returns a serialized version of this job.
* @method serialized
* @return {object} The serialized job.
*/
that.serialized = function() { that.serialized = function() {
return command.serialized(); return {id:priv.id,
date:priv.date.getTime(),
tried:priv.tried,
max_retry:priv.max_retry,
status:priv.status.serialized(),
command:priv.command.serialized(),
storage:priv.storage.serialized()};
};
/**
* Tells the job to wait for another one.
* @method waitForJob
* @param {object} job The job to wait for.
*/
that.waitForJob = function(job) {
if (priv.status.getLabel() !== 'wait') {
priv.status = waitStatus();
}
priv.status.waitForJob(job);
};
/**
* Tells the job to do not wait for a job.
* @method dontWaitForJob
* @param {object} job The other job.
*/
that.dontWaitFor = function(job) {
if (priv.status.getLabel() === 'wait') {
priv.status.dontWaitForJob(job);
}
};
/**
* Tells the job to wait for a while.
* @method waitForTime
* @param {number} ms Time to wait in millisecond.
*/
that.waitForTime = function(ms) {
if (priv.status.getLabel() !== 'wait') {
priv.status = waitStatus();
}
priv.status.waitForTime(ms);
};
/**
* Tells the job to do not wait for a while anymore.
* @method stopWaitForTime
*/
that.stopWaitForTime = function() {
if (priv.status.getLabel() === 'wait') {
priv.status.stopWaitForTime();
}
};
/**
* Updates the date of the job with the another one.
* @method update
* @param {object} job The other job.
*/
that.update = function(job) {
priv.date = job.getDate();
};
that.execute = function() {
if (priv.max_retry !== 0 && priv.tried >= priv.max_retry) {
throw tooMuchTriesJobException(
{job:that,message:'The job was invoked too much time.'});
}
if (!that.isReady()) {
throw jobNotReadyException({message:'Can not execute this job.'});
}
priv.status = onGoingStatus();
priv.tried ++;
priv.command.onEndDo (function() {
jobManager.terminateJob (that);
});
priv.command.execute (priv.storage);
}; };
return that; return that;
......
var idHandler = (function() { var jobIdHandler = (function(spec, my) {
var that = {}; var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var id = 0; var id = 0;
// Methods //
that.nextId = function() { that.nextId = function() {
id = id + 1; id = id + 1;
return id; return id;
......
var jobManager = (function(spec) { var jobManager = (function(spec, my) {
var spec = spec || {};
var that = {}; var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var job_array_name = 'jio/job_array';
var priv = {};
priv.id = spec.id;
priv.interval_id = null;
priv.interval = 200;
priv.job_a = [];
// Methods //
priv.getJobArrayName = function() {
return job_array_name + '/' + priv.id;
};
priv.getJobArray = function() {
return LocalOrCookieStorage.getItem(priv.getJobArrayName())||[];
};
priv.copyJobArrayToLocal = function() {
var new_a = [], i;
for (i = 0; i < priv.job_a.length; i+= 1) {
new_a.push(priv.job_a[i].serialized());
}
LocalOrCookieStorage.setItem(priv.getJobArrayName(),new_a);
};
priv.removeJob = function(job) {
var i, tmp_job_a = [];
for (i = 0; i < priv.job_a.length; i+= 1) {
if (priv.job_a[i] !== job) {
tmp_job_a.push(priv.job_a[i]);
}
}
priv.job_a = tmp_job_a;
priv.copyJobArrayToLocal();
};
/**
* Sets the job manager id.
* @method setId
* @param {number} id The id.
*/
that.setId = function(id) {
priv.id = id;
};
/**
* Starts listening to the job array, executing them regulary.
* @method start
*/
that.start = function() {
var i;
if (priv.interval_id === null) {
priv.interval_id = setInterval (function() {
for (i = 0; i < priv.job_a.length; i+= 1) {
that.execute(priv.job_a[i]);
}
},priv.interval);
}
};
/**
* Stops listening to the job array.
* @method stop
*/
that.stop = function() {
if (priv.interval_id !== null) {
clearInterval(priv.interval_id);
priv.interval_id = null;
if (priv.job_a.length === 0) {
LocalOrCookieStorage.deleteItem(priv.getJobArrayName());
}
}
};
/**
* Executes a job.
* @method execute
* @param {object} job The job object.
*/
that.execute = function(job) {
try {
job.execute();
} catch (e) {
switch (e.name) {
case 'jobNotReadyException': break; // do nothing
case 'tooMuchTriesJobException': break; // do nothing
default: throw e;
}
}
priv.copyJobArrayToLocal();
};
that.terminateJob = function(job) {
priv.removeJob(job);
priv.copyJobArrayToLocal();
};
that.addJob = function(job) {
var result_a = that.validateJobAccordingToJobList (priv.job_a,job);
priv.manage (job,result_a);
priv.copyJobArrayToLocal();
};
var jobs = []; that.validateJobAccordingToJobList = function(job_a,job) {
var i, result_a = [];
for (i = 0; i < job_a.length; i+= 1) {
result_a.push(jobRules.validateJobAccordingToJob (job_a[i],job));
}
return result_a;
};
priv.manage = function(job,result_a) {
var i;
if (priv.job_a.length !== result_a.length) {
throw new RangeError("Array out of bound");
}
for (i = 0; i < result_a.length; i+= 1) {
if (result_a[i].action === 'dont accept') {
return;
}
}
for (i = 0; i < result_a.length; i+= 1) {
switch (result_a[i].action) {
case 'eliminate':
that.eliminate(result_a[i].job);
break;
case 'replace':
job.update(result_a[i].job);
priv.copyJobArrayToLocal();
return;
case 'wait':
job.waitForJob(result_a[i].job);
break;
default: break;
}
}
priv.job_a.push(job);
priv.copyJobArrayToLocal();
};
that.eliminate = function(job) {
var i, tmp_a = [];
for (i = 0; i < priv.job_a.length; i+= 1) {
if (priv.job_a[i].getId() !== job.getId()) {
tmp_a.push(priv.job_a[i]);
}
}
priv.job_a = tmp_a;
};
return that;
}()); }());
\ No newline at end of file
var jobRules = (function(spec, my) {
var that = {};
// Attributes //
var priv = {};
that.eliminate = function() { return 'eliminate'; };
that.update = function() { return 'update'; };
that.dontAccept = function() { return 'dont accept'; };
that.wait = function() { return 'wait'; };
that.none = function() { return 'none'; };
priv.compare = {
};
priv.default_compare = function(job1,job2) {
return (job1.getCommand().getPath() === job2.getCommand().getPath() &&
JSON.stringify(job1.getStorage()) ===
JSON.stringify(job2.getStorage()));
};
priv.action = {
/*
LEGEND:
- s: storage
- m: method
- n: name
- c: content
- o: options
- =: are equal
- !: are not equal
select ALL s= n=
removefailordone fail|done
/ elim repl nacc wait
Remove !ongoing Save 1 x x x
Save !ongoing Remove 1 x x x
GetList !ongoing GetList 0 1 x x
Remove !ongoing Remove 0 1 x x
Load !ongoing Load 0 1 x x
Save c= !ongoing Save 0 1 x x
Save c! !ongoing Save 0 1 x x
GetList ongoing GetList 0 0 1 x
Remove ongoing Remove 0 0 1 x
Remove ongoing Load 0 0 1 x
Remove !ongoing Load 0 0 1 x
Load ongoing Load 0 0 1 x
Save c= ongoing Save 0 0 1 x
Remove ongoing Save 0 0 0 1
Load ongoing Remove 0 0 0 1
Load ongoing Save 0 0 0 1
Load !ongoing Remove 0 0 0 1
Load !ongoing Save 0 0 0 1
Save ongoing Remove 0 0 0 1
Save ongoing Load 0 0 0 1
Save c! ongoing Save 0 0 0 1
Save !ongoing Load 0 0 0 1
GetList ongoing Remove 0 0 0 0
GetList ongoing Load 0 0 0 0
GetList ongoing Save 0 0 0 0
GetList !ongoing Remove 0 0 0 0
GetList !ongoing Load 0 0 0 0
GetList !ongoing Save 0 0 0 0
Remove ongoing GetList 0 0 0 0
Remove !ongoing GetList 0 0 0 0
Load ongoing GetList 0 0 0 0
Load !ongoing GetList 0 0 0 0
Save ongoing GetList 0 0 0 0
Save !ongoing GetList 0 0 0 0
For more information, see documentation
*/
'saveDocument':{
'on going':{
'saveDocument' :function(job1,job2){
if (job1.getCommand().getContent() ===
job2.getCommand().getContent()) {
return that.dontAccept();
} else {
return that.wait();
}
},
'loadDocument' : that.wait,
'removeDocument' : that.wait,
'getDocumentList' : that.none
},
'not on going':{
'saveDocument' : that.update,
'loadDocument' : that.wait,
'removeDocument' : that.eliminate,
'getDocumentList' : that.none
}
},
'loadDocument':{
'on going':{
'saveDocument' : that.wait,
'loadDocument' : that.dontAccept,
'removeDocument' : that.wait,
'getDocumentList' : that.none
},
'not on going':{
'saveDocument' : that.wait,
'loadDocument' : that.update,
'removeDocument' : that.wait,
'getDocumentList' : that.none
}
},
'removeDocument':{
'on going':{
'saveDocument' : that.wait,
'loadDocument' : that.dontAccept,
'removeDocument' : that.dontAccept,
'getDocumentList' : that.none
},
'not on going':{
'saveDocument' : that.eliminate,
'loadDocument' : that.dontAccept,
'removeDocument' : that.update,
'getDocumentList' : that.none
}
},
'getDocumentList':{
'on going':{
'saveDocument' : that.none,
'loadDocument' : that.none,
'removeDocument' : that.none,
'getDocumentList' : that.dontAccept
},
'not on going':{
'saveDocument' : that.none,
'loadDocument' : that.none,
'removeDocument' : that.none,
'getDocumentList' : that.update
}
}
};
priv.default_action = 'none';
// Methods //
priv.getAction = function(job1,job2) {
var j1label, j2label, j1status;
j1label = job1.getCommand().getLabel();
j2label = job2.getCommand().getLabel();
j1status = (job1.getStatus().getLabel()==='on going'?
'on going':'not on going');
try {
return priv.action[j1label][j1status][j2label](job1,job2);
} catch (e) {
return priv.default_action;
}
};
priv.canCompare = function(job1,job2) {
var key = priv.stringifyJobForCompare(job1,job2);
if (priv.compare[key]) {
return priv.compare[key](job1,job2);
}
return priv.default_compare(job1,job2);
};
that.validateJobAccordingToJob = function(job1,job2) {
var key = priv.stringifyJobForAction(job1,job2);
if (priv.canCompare(job1,job2)) {
return {action:priv.getAction(job1,job2),job:job1};
}
return {action:priv.default_action,job:job1};
};
return that;
}());
var doneStatus = function(spec, my) {
var that = jobStatus(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.getLabel = function() {
return 'done';
};
that.canStart = function() {
return false;
};
that.canRestart = function() {
return false;
};
return that;
};
var failStatus = function(spec, my) {
var that = jobStatus(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.getLabel = function() {
return 'fail';
};
that.canStart = function() {
return false;
};
that.canRestart = function() {
return true;
};
return that;
};
\ No newline at end of file
var initialStatus = function(spec, my) {
var that = jobStatus(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.getLabel = function() {
return 'initial';
};
that.canStart = function() {
return true;
};
that.canRestart = function() {
return true;
};
return that;
};
\ No newline at end of file
var jobStatus = function(spec, my) {
var that = {};
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.getLabel = function() {
return 'job status';
};
that.canStart = function() {};
that.canRestart = function() {};
that.serialized = function() {
return {label:that.getLabel()};
};
return that;
};
\ No newline at end of file
var onGoingStatus = function(spec, my) {
var that = jobStatus(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
// Methods //
that.getLabel = function() {
return 'on going';
};
that.canStart = function() {
return false;
};
that.canRestart = function() {
return false;
};
return that;
};
\ No newline at end of file
var waitStatus = function(spec, my) {
var that = jobStatus(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
var job_id_a = spec.job_id_array || [];
var threshold = 0;
// Methods //
that.getLabel = function() {
return 'wait';
};
that.waitForJob = function(job) {
var i;
for (i = 0; i < job_id_a.length; i+= 1) {
if (job_id_a[i] === job.getId()) {
return;
}
}
job_id_a.push(job.getId());
};
that.dontWaitForJob = function(job) {
var i, tmp_job_id_a = [];
for (i = 0; i < job_id_a.length; i+= 1) {
if (job_id_a[i] !== job.getId()){
tmp_job_id_a.push(job_id_a[i]);
}
}
job_id_a = tmp_job_id_a;
};
that.waitForTime = function(ms) {
threshold = Date.now() + ms;
};
that.stopWaitForTime = function() {
threshold = 0;
};
that.canStart = function() {
return (job_id_a.length === 0 && Date.now() >= threshold);
};
that.canRestart = function() {
return false;
};
that.serialized = function() {
return {label:that.getLabel(),
waitfortime:threshold,
waitforjob:job_id_a};
};
return that;
};
var storage = function(spec) { var storage = function(spec, my) {
var spec = spec || {};
var that = {}; var that = {};
spec = spec || {};
my = my || {};
// Attributes //
var priv = {};
priv.type = spec.type || '';
// my.jio exists
// Methods //
that.getType = function() {
return priv.type;
};
that.setType = function(type) {
priv.type = type;
};
/**
* Execute the command on this storage.
* @method execute
* @param {object} command The command
*/
that.execute = function(command) { that.execute = function(command) {
command.executeOn(that); command.executeOn(that);
}; };
that.executeSave = function(command) {}; /**
that.executeRemove = function(command) {}; * Override this function to validate specifications.
* @method isValid
* @return {boolean} true if ok, else false.
*/
that.isValid = function() {
return true;
};
that.validate = function(command) {
command.validate(that);
};
/**
* Returns a serialized version of this storage.
* @method serialized
* @return {object} The serialized storage.
*/
that.serialized = function() {
return {type:that.getType()};
};
that.saveDocument = function(command) {
throw invalidStorage({storage:that,message:'Unknown storage.'});
};
that.loadDocument = function(command) {
that.saveDocument();
};
that.removeDocument = function(command) {
that.saveDocument();
};
that.getDocumentList = function(command) {
that.saveDocument();
};
return that; return that;
} };
var storageHandler = function(spec) { var storageHandler = function(spec, my) {
var that = storage(spec, my);
spec = spec || {};
my = my || {};
// Attributes //
var priv = {};
priv.storage_a = spec.storagelist || [];
var spec = spec || {}; // Methods //
var that = {}; /**
* It is called before the execution.
* Override this function.
* @method beforeExecute
* @param {object} command The command.
* @param {object} option Some options.
*/
that.beforeExecute = function(command,option) {};
var storages = spec.storages || []; /**
* Execute the command according to this storage.
that.execute = function(command) { * @method execute
* @param {object} command The command.
* @param {object} option Some options.
*/
that.execute = function(command,option) {
var i;
that.validate(command); that.validate(command);
that.doExecute(command); that.beforeExecute(command,option);
for(i = 0; i < priv.storage_a.length; i++) {
priv.storage_a[i].execute(command);
}
that.afterExecute(command,option);
}; };
that.doExecute = function(command) { /**
for(var i=0; i<storages.length; i++) { * Is is called after the execution.
storages[i].execute(command); * Override this function.
} * @method afterExecute
* @param {object} command The command.
* @param {object} option Some options.
*/
that.afterExecute = function(command,option) {
that.done();
}; };
that.validate = function(command) { /**
command.validate(that); * Returns a serialized version of this storage
* @method serialized
* @return {object} The serialized storage.
*/
that.serialized = function() {
return {type:priv.type,
storagelist:priv.storagelist};
}; };
return that; return that;
......
return jioNamespace;
}());
var jio = (function () {
...@@ -93,45 +93,41 @@ test ( "Jio simple methods", function () { ...@@ -93,45 +93,41 @@ test ( "Jio simple methods", function () {
o.jio2 = JIO.newJio(); o.jio2 = JIO.newJio();
ok ( o.jio2, 'another new jio -> 2'); ok ( o.jio2, 'another new jio -> 2');
ok ( JIO.addStorageType('qunit', function(){}) , JIO.addStorageType('qunit', function(){});
"adding storage type.");
deepEqual ( o.jio.isReady(), true, '1 must be not ready'); ok ( o.jio2.getId() !== o.jio.getId(), '1 and 2 must be different');
ok ( o.jio2.getID() !== o.jio.getID(), '1 and 2 must be different');
deepEqual ( o.jio.stop(), true, '1 must be stopped');
o.jio.stop();
o.jio2.stop(); o.jio2.stop();
}); });
test ( 'Jio Publish/Sububscribe/Unsubscribe methods', function () { // test ( 'Jio Publish/Sububscribe/Unsubscribe methods', function () {
// Test the Publisher, Subscriber of a single jio. // // Test the Publisher, Subscriber of a single jio.
// It is just testing if these function are working correctly. // // It is just testing if these function are working correctly.
// The test publishes an event, waits a little, and check if the // // The test publishes an event, waits a little, and check if the
// event has been received by the callback of the previous // // event has been received by the callback of the previous
// subscribe. Then, the test unsubscribe the callback function from // // subscribe. Then, the test unsubscribe the callback function from
// the event, and publish the same event. If it receives the event, // // the event, and publish the same event. If it receives the event,
// the unsubscribe method is not working correctly. // // the unsubscribe method is not working correctly.
var o = {}; // var o = {};
o.jio = JIO.newJio(); // o.jio = JIO.newJio();
var spy1 = this.spy(); // var spy1 = this.spy();
// Subscribe the pubsub_test event. // // Subscribe the pubsub_test event.
o.callback = o.jio.subscribe('pubsub_test',spy1); // o.callback = o.jio.subscribe('pubsub_test',spy1);
// And publish the event. // // And publish the event.
o.jio.publish('pubsub_test'); // o.jio.publish('pubsub_test');
ok (spy1.calledOnce, 'subscribing & publishing, event called once'); // ok (spy1.calledOnce, 'subscribing & publishing, event called once');
o.jio.unsubscribe('pubsub_test',spy1); // o.jio.unsubscribe('pubsub_test',spy1);
o.jio.publish('pubsub_test'); // o.jio.publish('pubsub_test');
ok (spy1.calledOnce, 'unsubscribing, same event not called twice'); // ok (spy1.calledOnce, 'unsubscribing, same event not called twice');
o.jio.stop(); // o.jio.stop();
}); // });
module ( 'Jio Dummy Storages' ); module ( 'Jio Dummy Storages' );
...@@ -140,11 +136,12 @@ test ('All tests', function () { ...@@ -140,11 +136,12 @@ test ('All tests', function () {
// It is simple tests, but they will be used by replicate storage later // It is simple tests, but they will be used by replicate storage later
// for sync operation. // for sync operation.
var o = {}, clock = this.sandbox.useFakeTimers(), t = this, var o = {}, clock = this.sandbox.useFakeTimers(),
mytest = function (message,method,retmethod,value){ mytest = function (message,method,retmethod,value){
o.f = function (result) { o.f = function (result) {
deepEqual (result[retmethod],value,message);}; deepEqual (result,value,message);
t.spy(o,'f'); };
this.spy(o,'f');
o.jio[method]({'user_name':'Dummy','name':'file', o.jio[method]({'user_name':'Dummy','name':'file',
'content':'content','onResponse':o.f, 'content':'content','onResponse':o.f,
'max_tries':1}); 'max_tries':1});
...@@ -154,40 +151,43 @@ test ('All tests', function () { ...@@ -154,40 +151,43 @@ test ('All tests', function () {
} }
}; };
// All Ok Dummy Storage // All Ok Dummy Storage
o.jio = JIO.newJio({'type':'dummyallok','user_name':'Dummy'}, o.jio = JIO.newJio({'type':'dummyallok','user_name':'Dummy',
{'ID':'jiotests'}); 'applicationname':'jiotests'});
mytest('check name availability OK','checkNameAvailability', o.f = function (result) {
'return_value',true); deepEqual (result,undefined,'');
mytest('save document OK','saveDocument','status','done'); };
mytest('load document OK','loadDocument','return_value', this.spy(o,'f');
{'name':'file','content':'content', o.jio.saveDocument('file','content',{onDone:o.f});
'last_modified':15000,'creation_date':10000}); clock.tick(1000);
mytest('get document list OK','getDocumentList','return_value', if (!o.f.calledOnce) {
[{'name':'file','creation_date':10000,'last_modified':15000}, ok(false, 'no response / too much results');
{'name':'memo','creation_date':20000,'last_modified':25000}]); }
mytest('remove document OK','removeDocument','status','done'); // mytest('save document OK','saveDocument','status','done');
o.jio.stop(); // mytest('load document OK','loadDocument','return_value',
// {'name':'file','content':'content',
// All Fail Dummy Storage // 'last_modified':15000,'creation_date':10000});
o.jio = JIO.newJio({'type':'dummyallfail','user_name':'Dummy'}, // mytest('get document list OK','getDocumentList','return_value',
{'ID':'jiotests'}); // [{'name':'file','creation_date':10000,'last_modified':15000},
mytest('check name availability FAIL','checkNameAvailability', // {'name':'memo','creation_date':20000,'last_modified':25000}]);
'status','fail'); // mytest('remove document OK','removeDocument','status','done');
mytest('save document FAIL','saveDocument','status','fail'); // o.jio.stop();
mytest('load document FAIL','loadDocument','status','fail');
mytest('get document list FAIL','getDocumentList','status','fail'); // // All Fail Dummy Storage
mytest('remove document FAIL','removeDocument','status','fail'); // o.jio = JIO.newJio({'type':'dummyallfail','user_name':'Dummy'},
o.jio.stop(); // {'ID':'jiotests'});
// mytest('save document FAIL','saveDocument','status','fail');
// All Not Found Dummy Storage // mytest('load document FAIL','loadDocument','status','fail');
o.jio = JIO.newJio({'type':'dummyallnotfound','user_name':'Dummy'}, // mytest('get document list FAIL','getDocumentList','status','fail');
{'ID':'jiotests'}); // mytest('remove document FAIL','removeDocument','status','fail');
mytest('check name availability NOT FOUND','checkNameAvailability', // o.jio.stop();
'return_value',true);
mytest('save document NOT FOUND','saveDocument','status','done'); // // All Not Found Dummy Storage
mytest('load document NOT FOUND','loadDocument','status','fail'); // o.jio = JIO.newJio({'type':'dummyallnotfound','user_name':'Dummy'},
mytest('get document list NOT FOUND','getDocumentList','status','fail'); // {'ID':'jiotests'});
mytest('remove document NOT FOUND','removeDocument','status','done'); // mytest('save document NOT FOUND','saveDocument','status','done');
// mytest('load document NOT FOUND','loadDocument','status','fail');
// mytest('get document list NOT FOUND','getDocumentList','status','fail');
// mytest('remove document NOT FOUND','removeDocument','status','done');
o.jio.stop(); o.jio.stop();
}); });
...@@ -1184,7 +1184,7 @@ if (window.requirejs) { ...@@ -1184,7 +1184,7 @@ if (window.requirejs) {
require(['jiotestsloader'],thisfun); require(['jiotestsloader'],thisfun);
} else { } else {
thisfun ({LocalOrCookieStorage:LocalOrCookieStorage, thisfun ({LocalOrCookieStorage:LocalOrCookieStorage,
JIO:JIO, JIO:jio,
sjcl:sjcl, sjcl:sjcl,
Base64:Base64, Base64:Base64,
jQuery:jQuery}); jQuery:jQuery});
......
...@@ -13,11 +13,34 @@ ...@@ -13,11 +13,34 @@
<script type="text/javascript" src="../lib/jquery/jquery.js"></script> <script type="text/javascript" src="../lib/jquery/jquery.js"></script>
<script type="text/javascript" src="../src/localorcookiestorage.js"> <script type="text/javascript" src="../src/localorcookiestorage.js">
</script> </script>
<script type="text/javascript" src="../src/jio.js"></script>
<script type="text/javascript" src="../lib/jio/jio.js"></script>
<script type="text/javascript" src="../src/jio/activityUpdater.js"></script>
<script type="text/javascript" src="../src/jio/announcements/announcement.js"></script>
<script type="text/javascript" src="../src/jio/announcements/announcer.js"></script>
<script type="text/javascript" src="../src/jio/commands/command.js"></script>
<script type="text/javascript" src="../src/jio/commands/getDocumentList.js"></script>
<script type="text/javascript" src="../src/jio/commands/loadDocument.js"></script>
<script type="text/javascript" src="../src/jio/commands/removeDocument.js"></script>
<script type="text/javascript" src="../src/jio/commands/saveDocument.js"></script>
<script type="text/javascript" src="../src/jio/exceptions.js"></script>
<script type="text/javascript" src="../src/jio/jobs/jobIdHandler.js"></script>
<script type="text/javascript" src="../src/jio/jobs/job.js"></script>
<script type="text/javascript" src="../src/jio/jobs/jobManager.js"></script>
<script type="text/javascript" src="../src/jio/jobs/jobRules.js"></script>
<script type="text/javascript" src="../src/jio/jobs/status/doneStatus.js"></script>
<script type="text/javascript" src="../src/jio/jobs/status/failStatus.js"></script>
<script type="text/javascript" src="../src/jio/jobs/status/initialStatus.js"></script>
<script type="text/javascript" src="../src/jio/jobs/status/jobStatus.js"></script>
<script type="text/javascript" src="../src/jio/jobs/status/onGoingStatus.js"></script>
<script type="text/javascript" src="../src/jio/jobs/status/waitStatus.js"></script>
<script type="text/javascript" src="../src/jio/storages/storageHandler.js"></script>
<script type="text/javascript" src="../src/jio/storages/storage.js"></script>
<script type="text/javascript" src="../lib/base64/base64.js"></script> <script type="text/javascript" src="../lib/base64/base64.js"></script>
<script type="text/javascript" src="../lib/sjcl/sjcl.min.js"></script> <script type="text/javascript" src="../lib/sjcl/sjcl.min.js"></script>
<script type="text/javascript" src="../src/jio.dummystorages.js"></script> <script type="text/javascript" src="../src/jio.dummystorages.js"></script>
<script type="text/javascript" src="../src/jio.storage.js"></script> <!-- <script type="text/javascript" src="../src/jio.storage.js"></script> -->
<script type="text/javascript" src="jiotests.js"></script> <script type="text/javascript" src="jiotests.js"></script>
</body> </body>
</html> </html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment