Commit 39836f9f authored by Tristan Cavelier's avatar Tristan Cavelier Committed by Sebastien Robin

We can give a parameter to Jio to not store job queue in localStorage.

New class on jio.js, it permit to make easier storage development.
Add one test.
parent e74f4914
......@@ -2,19 +2,42 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>JIO QUnit/Sinon Test</title>
<title>Test</title>
<link rel="stylesheet" href="qunit/qunit-1.5.0.css" />
</head>
<body>
<div id="qunit"></div>
<script type="text/javascript" src="js/jquery/jquery.js"></script>
<script type="text/javascript" src="unhosted/localorcookiestorage.js"></script>
<script type="text/javascript" src="unhosted/jio.js"></script>
<!-- <script type="text/javascript" src="unhosted/base64.js"></script> -->
<script type="text/javascript" src="unhosted/base64.js"></script>
<script type="text/javascript" src="unhosted/jio.storage.js"></script>
<script type="text/javascript">
<!--
var j = JIO.createNew();
var mammal = function (description) {
this.caracteristics = description;
};
mammal.prototype = {
createMammal: function () {
// c'est un chat alors
var mycat = new cat(this.caracteristics);
var t = this;
mycat.say = function () { return t.caracteristics.say; };
mycat.name = function () { return t.caracteristics.name; };
return mycat;
}
};
var cat = function (detaileddescription) {
// (...)
};
cat.prototype = {
talk: function () {
alert('My name is ' + this.name() + ', ' + this.say());
}
};
var mam = new mammal({'say':'meow','name':'nyancat'});
var mycat = mam.createMammal();
mycat.talk();
//-->
</script>
</body>
......
......@@ -21,89 +21,63 @@
////////////////////////////////////////////////////////////////////////////
// Dummy Storage 1 : all ok
var DummyStorageAllOk = function ( options ) {
var DummyStorageAllOk = function ( args ) {
this.job = args.job;
};
DummyStorageAllOk.prototype = {
checkNameAvailability: function ( job , jobendcallback) {
checkNameAvailability: function () {
// The [job.userName] IS available.
// job: the job object
// job.userName: the name we want to check.
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isAvailable':boolean}
// in the jobendcallback arguments.
var t = this;
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
job.status = 'done';
jobendcallback(job);
job.callback({'status':'done',
'message':''+job.userName+' is available.',
'isAvailable':true});
t.done(true);
}, 100);
}, // end userNameAvailable
saveDocument: function ( job, jobendcallback ) {
saveDocument: function () {
// Tells us that the document is saved.
// job : the job object
// job.options : the save options object
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isSaved':boolean}
// in the jobendcallback arguments.
var t = this;
// wait a little in order to simulate asynchronous saving
setTimeout (function () {
var res = {};
res.status = job.status = 'done';
res.message = 'Document saved.';
res.isSaved = true;
jobendcallback(job);
job.callback(res);
t.done();
}, 100);
}, // end saveDocument
loadDocument: function ( job, jobendcallback ) {
loadDocument: function () {
// Returns a document object containing all information of the
// document and its content.
// job : the job object
// job.fileName : the document name we want to load.
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'document':object}
// in the jobendcallback arguments.
// document object is {'fileName':string,'fileContent':string,
// 'creationDate':date,'lastModified':date}
var t = this;
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
var res = {};
res.status = job.status = 'done';
res.message = 'Document loaded.';
res.document = {
var doc = {
'fileContent': 'content',
'fileName': 'file',
'creationDate': 10000,
'lastModified': 15000};
jobendcallback(job);
job.callback(res);
t.done(doc);
}, 100);
}, // end loadDocument
getDocumentList: function ( job, jobendcallback) {
getDocumentList: function () {
// It returns a document array containing all the user documents
// informations, but not their content.
// job : the job object
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'list':array}
// in the jobendcallback arguments.
// the list is [object,object] -> object = {'fileName':string,
// 'lastModified':date,'creationDate':date}
var t = this;
setTimeout(function () {
var res = {};
res.list = [
var list = [
{'fileName':'file',
'creationDate':10000,
'lastModified':15000},
......@@ -111,28 +85,17 @@
'creationDate':20000,
'lastModified':25000
}];
res.status = job.status = 'done';
res.message = 'List received.';
jobendcallback(job);
job.callback(res);
t.done(list);
}, 100);
}, // end getDocumentList
removeDocument: function ( job, jobendcallback ) {
removeDocument: function () {
// Remove a document from the storage.
// job : the job object
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isRemoved':boolean}
// in the jobendcallback arguments.
var t = this;
setTimeout (function () {
var res = {};
res.status = job.status = 'done';
res.message = 'Document removed.';
res.isRemoved = true;
jobendcallback(job);
job.callback(res);
t.done();
}, 100);
}
};
......@@ -141,113 +104,74 @@
Jio.addStorageType('dummyallok', function (options) {
return new DummyStorageAllOk(options);
});
// end Dummy Storage All Ok
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Dummy Storage 2 : all fail
var DummyStorageAllFail = function ( options ) {
var DummyStorageAllFail = function ( args ) {
this.job = args.job;
};
DummyStorageAllFail.prototype = {
checkNameAvailability: function ( job , jobendcallback) {
checkNameAvailability: function () {
// Fails to check [job.userName].
// job: the job object
// job.userName: the name we want to check.
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isAvailable':boolean}
// in the jobendcallback arguments.
var t = this;
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
job.status = 'fail';
jobendcallback(job);
job.callback({'status':'fail',
'message':'Cannot check name availability',
'isAvailable':false});
t.fail('Cannot check name availability.',0);
}, 100);
}, // end userNameAvailable
saveDocument: function ( job, jobendcallback ) {
saveDocument: function () {
// Tells us that the document is not saved.
// job : the job object
// job.options : the save options object
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isSaved':boolean}
// in the jobendcallback arguments.
var t = this;
// wait a little in order to simulate asynchronous saving
setTimeout (function () {
var res = {};
res.status = job.status = 'fail';
res.message = 'Unable to save document.';
res.errno = 0;
res.isSaved = false;
jobendcallback(job);
job.callback(res);
t.fail('Unable to save document.',0);
}, 100);
}, // end saveDocument
loadDocument: function ( job, jobendcallback ) {
loadDocument: function () {
// Returns a document object containing nothing.
// job : the job object
// job.fileName : the document name we want to load.
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'document':object}
// in the jobendcallback arguments.
// document object is {'fileName':string,'fileContent':string,
// 'creationDate':date,'lastModified':date}
var t = this;
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
var res = {};
res.status = job.status = 'fail';
res.message = 'Unable to load document.';
res.errno = 0;
res.document = {};
jobendcallback(job);
job.callback(res);
t.fail('Unable to load document.',0);
}, 100);
}, // end loadDocument
getDocumentList: function ( job, jobendcallback) {
getDocumentList: function () {
// It returns nothing.
// job : the job object
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'list':array}
// in the jobendcallback arguments.
// the list is [object,object] -> object = {'fileName':string,
// 'lastModified':date,'creationDate':date}
var t = this;
setTimeout(function () {
var res = {};
res.status = job.status = 'fail';
res.message = 'Cannot get document list.';
res.errno = 0;
jobendcallback(job);
job.callback(res);
t.fail('Cannot get document list.',0);
}, 100);
}, // end getDocumentList
removeDocument: function ( job, jobendcallback ) {
// Remove a document from the storage.
// job : the job object
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isRemoved':boolean}
// in the jobendcallback arguments.
var t = this;
setTimeout (function () {
var res = {};
res.status = job.status = 'fail';
res.message = 'Unable to remove anything.';
res.isRemoved = false;
jobendcallback(job);
job.callback(res);
t.fail('Unable to remove anything.',0);
}, 100);
}
};
......@@ -262,106 +186,69 @@
////////////////////////////////////////////////////////////////////////////
// Dummy Storage 3 : all not found
var DummyStorageAllNotFound = function ( options ) {
var DummyStorageAllNotFound = function ( args ) {
this.job = args.job;
};
DummyStorageAllNotFound.prototype = {
checkNameAvailability: function ( job , jobendcallback) {
checkNameAvailability: function () {
// [job.userName] not found, so the name is available.
// job: the job object
// job.userName: the name we want to check.
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isAvailable':boolean}
// in the jobendcallback arguments.
var t = this;
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
job.status = 'done';
jobendcallback(job);
job.callback({'status':'done',
'message':''+job.userName+' is available.',
'isAvailable':true});
t.done(true);
}, 100);
}, // end userNameAvailable
saveDocument: function ( job, jobendcallback ) {
saveDocument: function () {
// Document does not exists yet, create it.
// job : the job object
// job.options : the save options object
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isSaved':boolean}
// in the jobendcallback arguments.
var t = this;
// wait a little in order to simulate asynchronous saving
setTimeout (function () {
var res = {};
res.status = job.status = 'done';
res.message = 'Document saved.';
res.isSaved = true;
jobendcallback(job);
job.callback(res);
t.done();
}, 100);
}, // end saveDocument
loadDocument: function ( job, jobendcallback ) {
// Returns a document object containing nothing.
// job : the job object
// job.fileName : the document name we want to load.
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'document':object}
// in the jobendcallback arguments.
// document object is {'fileName':string,'fileContent':string,
// 'creationDate':date,'lastModified':date}
var t = this;
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
var res = {};
res.status = job.status = 'fail';
res.message = 'Document not found.';
res.errno = 404;
res.document = {};
jobendcallback(job);
job.callback(res);
t.fail('Document not found.',404);
}, 100);
}, // end loadDocument
getDocumentList: function ( job, jobendcallback) {
// It returns nothing.
// job : the job object
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'list':array}
// in the jobendcallback arguments.
// the list is [object,object] -> object = {'fileName':string,
// 'lastModified':date,'creationDate':date}
var t = this;
setTimeout(function () {
var res = {};
res.status = job.status = 'fail';
res.message = 'User collection not found.';
res.errno = 404;
jobendcallback(job);
job.callback(res);
t.fail('User collection not found.',404);
}, 100);
}, // end getDocumentList
removeDocument: function ( job, jobendcallback ) {
// Remove a document from the storage.
// job : the job object
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isRemoved':boolean}
// in the jobendcallback arguments.
var t = this;
setTimeout (function () {
var res = {};
res.status = job.status = 'done';
res.message = 'Document already removed.';
res.isRemoved = true;
jobendcallback(job);
job.callback(res);
t.done();
}, 100);
}
};
......@@ -374,4 +261,81 @@
// end Dummy Storage All Not Found
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Dummy Storage 4 : all 3 tries
var DummyStorageAll3Tries = function ( args ) {
this.job = args.job;
};
DummyStorageAllNotFound.prototype = {
checkNameAvailability: function () {
// [job.userName] not found, so the name is available.
var t = this;
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
t.done(true);
}, 100);
}, // end userNameAvailable
saveDocument: function () {
// Document does not exists yet, create it.
var t = this;
// wait a little in order to simulate asynchronous saving
setTimeout (function () {
t.done();
}, 100);
}, // end saveDocument
loadDocument: function () {
// Returns a document object containing nothing.
// document object is {'fileName':string,'fileContent':string,
// 'creationDate':date,'lastModified':date}
var t = this;
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
t.fail('Document not found.',404);
}, 100);
}, // end loadDocument
getDocumentList: function () {
// It returns nothing.
// the list is [object,object] -> object = {'fileName':string,
// 'lastModified':date,'creationDate':date}
var t = this;
setTimeout(function () {
t.fail('User collection not found.',404);
}, 100);
}, // end getDocumentList
removeDocument: function () {
// Remove a document from the storage.
// returns {'status':string,'message':string,'isRemoved':boolean}
// in the jobendcallback arguments.
var t = this;
setTimeout (function () {
t.done();
}, 100);
}
};
// add key to storageObjectType of global jio
Jio.addStorageType('dummyall3tries', function (options) {
return new DummyStorageAll3Tries(options);
});
// end Dummy Storage All 3 Tries
////////////////////////////////////////////////////////////////////////////
})( JIO );
......@@ -87,7 +87,8 @@ test ('All tests', function () {
deepEqual (result[retmethod],value,message);};
t.spy(o,'f');
o.jio[method]({'userName':'Dummy','fileName':'file',
'fileContent':'content','callback':o.f});
'fileContent':'content','callback':o.f,
'maxtries':1});
clock.tick(510);
if (!o.f.calledOnce)
ok(false, 'no response / too much results');
......@@ -114,7 +115,7 @@ test ('All tests', function () {
'isAvailable',false);
mytest('save document FAIL','saveDocument','isSaved',false);
mytest('load document FAIL','loadDocument','document',{});
mytest('get document list FAIL','getDocumentList','list',undefined);
mytest('get document list FAIL','getDocumentList','list',[]);
mytest('remove document FAIL','removeDocument','isRemoved',false);
o.jio.stop();
......@@ -125,7 +126,7 @@ test ('All tests', function () {
'isAvailable',true);
mytest('save document NOT FOUND','saveDocument','isSaved',true);
mytest('load document NOT FOUND','loadDocument','document',{});
mytest('get document list NOT FOUND','getDocumentList','list',undefined);
mytest('get document list NOT FOUND','getDocumentList','list',[]);
mytest('remove document NOT FOUND','removeDocument','isRemoved',true);
o.jio.stop();
});
......@@ -140,35 +141,40 @@ test ('Simple Job Elimination', function () {
{'ID':'jiotests'});
id = o.jio.id;
o.jio.saveDocument({'fileName':'file','fileContent':'content',
'callback':o.f1});
'callback':o.f1,'maxtries':1});
ok(LocalOrCookieStorage.getItem('jio/jobObject/'+id)['1'],
'job creation');
clock.tick(10);
o.jio.removeDocument({'fileName':'file','fileContent':'content',
'callback':o.f2});
deepEqual(LocalOrCookieStorage.getItem('jio/jobObject/'+id)['1'],
undefined,'job elimination');
'callback':o.f2,'maxtries':1});
o.tmp = LocalOrCookieStorage.getItem('jio/jobObject/'+id)['1'];
ok(!o.tmp || o.tmp.status === 'fail','job elimination');
});
test ('Simple Job Replacement', function () {
// Test if the second job write over the first one
var o = {}, clock = this.sandbox.useFakeTimers(), id = 0;
o.f1 = this.spy(); o.f2 = this.spy()
o.f1 = function (result) {
o.status = result.status;
};
this.spy(o,'f1');
o.f2 = this.spy()
o.jio = JIO.createNew({'type':'dummyallok','userName':'dummy'},
{'ID':'jiotests'});
id = o.jio.id;
o.jio.saveDocument({'fileName':'file','fileContent':'content',
'callback':o.f1});
'callback':o.f1,'maxtries':1});
clock.tick(10);
o.jio.saveDocument({'fileName':'file','fileContent':'content',
'callback':o.f2});
'callback':o.f2,'maxtries':1});
deepEqual(LocalOrCookieStorage.getItem(
'jio/jobObject/'+id)['1'].date,10,
'The first job date have to be equal to the second job date.');
clock.tick(500);
ok(!o.f1.calledOnce,'no callback for the first save request');
deepEqual([o.f1.calledOnce,o.status],[true,'fail'],
'callback for the first save request -> result fail');
ok(o.f2.calledOnce,'second callback is called once');
o.jio.stop();
......@@ -184,10 +190,10 @@ test ('Simple Job Waiting', function () {
{'ID':'jiotests'});
id = o.jio.id;
o.jio.saveDocument({'fileName':'file','fileContent':'content',
'callback':o.f3});
'callback':o.f3,'maxtries':1});
clock.tick(200);
o.jio.saveDocument({'fileName':'file','fileContent':'content',
'callback':o.f4});
'callback':o.f4,'maxtries':1});
ok(LocalOrCookieStorage.getItem(
'jio/jobObject/'+id)['2'] &&
LocalOrCookieStorage.getItem(
......@@ -206,6 +212,27 @@ test ('Simple Job Waiting', function () {
o.jio.stop();
});
test ('Simple Time Waiting' , function () {
// Test if the job that have fail wait until a certain moment to restart.
var o = {}, clock = this.sandbox.useFakeTimers(), id = 0;
o.f1 = this.spy();
o.jio = JIO.createNew({'type':'dummyallfail','userName':'dummy'},
{'ID':'jiotests'});
id = o.jio.id;
o.jio.saveDocument({'fileName':'file','fileContent':'content',
'callback':o.f1,'maxtries':2});
clock.tick(400);
o.tmp = LocalOrCookieStorage.getItem('jio/jobObject/'+id)['1'];
ok(o.tmp.status === 'wait' && o.tmp.waitingFor && o.tmp.waitingFor.time,
'is waiting for time');
clock.tick(1500);
o.tmp = LocalOrCookieStorage.getItem('jio/jobObject/'+id)['1'];
ok(o.tmp.status === 'fail','it restores itself after time');
console.log (localStorage);
o.jio.stop();
});
module ( 'Jio LocalStorage' );
test ('Check name availability', function () {
......@@ -219,7 +246,7 @@ test ('Check name availability', function () {
deepEqual(result.isAvailable,value,'checking name availabality');};
t.spy(o,'f');
o.jio.checkNameAvailability(
{'userName':'MrCheckName','callback': o.f});
{'userName':'MrCheckName','callback': o.f,'maxtries':1});
clock.tick(510);
if (!o.f.calledOnce)
ok(false, 'no response / too much results');
......@@ -245,23 +272,25 @@ test ('Document save', function () {
// We launch a saving to localstorage and we check if the file is
// realy saved. Then save again and check if
var o = {}, clock = this.sandbox.useFakeTimers(), t = this,
mytest = function (message,value,lm,cd,tick){
var tmp;
var o = {}, clock = this.sandbox.useFakeTimers(), t = this, tmp,
mytest = function (message,value,lmcd){
o.f = function (result) {
deepEqual(result.isSaved,value,message);};
t.spy(o,'f');
o.jio.saveDocument(
{'fileName':'file','fileContent':'content','callback': o.f});
if (tick === undefined) { clock.tick(510); }
else { clock.tick(tick); }
{'fileName':'file','fileContent':'content','callback': o.f,
'maxtries':1});
clock.tick(510);
if (!o.f.calledOnce)
ok(false, 'no response / too much results');
else {
// check content
tmp = LocalOrCookieStorage.getItem ('jio/local/MrSaveName/jiotests/file');
tmp.lmcd = lmcd(tmp.creationDate,tmp.lastModified);
delete tmp.lastModified;
delete tmp.creationDate;
deepEqual (tmp,{'fileName':'file','fileContent':'content',
'lastModified':lm,'creationDate':cd},'check content');
'lmcd':true},'check content');
}
};
......@@ -270,16 +299,15 @@ test ('Document save', function () {
LocalOrCookieStorage.deleteItem ('jio/local/MrSaveName/jiotests/file');
// save and check document existence
clock.tick(200);
mytest('saving document',true,200,200); // value, lastmodified, creationdate
// message, value, fun ( creationdate, lastmodified )
mytest('saving document',true,function(cd,lm){
return (cd === lm);
});
// re-save and check modification date
// 710 = 200 + 510 ms (clock tick)
mytest('saving again',true,710,200);
// re-save and check modification date
// 1220 = 710 + 510 ms (clock tick)
clock.tick(-1000);
mytest('saving a older document',false,710,200,1510);
mytest('saving again',true,function(cd,lm){
return (cd < lm);
});
o.jio.stop();
});
......@@ -296,7 +324,7 @@ test ('Document load', function () {
deepEqual(result[res],value,'loading document');};
t.spy(o,'f');
o.jio.loadDocument(
{'fileName':'file','callback': o.f});
{'fileName':'file','callback': o.f,'maxtries':1});
clock.tick(510);
if (!o.f.calledOnce)
ok(false, 'no response / too much results');
......@@ -333,7 +361,7 @@ test ('Get document list', function () {
objectifyDocumentArray(value),'getting list');
};
t.spy(o,'f');
o.jio.getDocumentList({'callback': o.f});
o.jio.getDocumentList({'callback': o.f,'maxtries':1});
clock.tick(510);
if (!o.f.calledOnce)
ok(false, 'no response / too much results');
......@@ -364,7 +392,7 @@ test ('Document remove', function () {
deepEqual(result.isRemoved,true,'removing document');};
t.spy(o,'f');
o.jio.removeDocument(
{'fileName':'file','callback': o.f});
{'fileName':'file','callback': o.f,'maxtries':1});
clock.tick(510);
if (!o.f.calledOnce)
ok(false, 'no response / too much results');
......@@ -398,7 +426,8 @@ test ('Check name availability', function () {
o.f = function (result) {
deepEqual (result.isAvailable,value,'checking name availability');};
t.spy(o,'f');
o.jio.checkNameAvailability({'userName':'davcheck','callback':o.f});
o.jio.checkNameAvailability({'userName':'davcheck','callback':o.f,
'maxtries':1});
clock.tick(500);
server.respond();
if (!o.f.calledOnce)
......@@ -436,7 +465,7 @@ test ('Document load', function () {
o.f = function (result) {
deepEqual (result.document,doc,message);};
t.spy(o,'f');
o.jio.loadDocument({'fileName':'file','callback':o.f});
o.jio.loadDocument({'fileName':'file','callback':o.f,'maxtries':1});
clock.tick(500);
server.respond();
if (!o.f.calledOnce)
......@@ -467,8 +496,7 @@ test ('Document save', function () {
var davsave = getXML('responsexml/davsave'),
o = {}, clock = this.sandbox.useFakeTimers(), t = this,
mytest = function (message,value,errnoput,errnoprop,
overwrite,force,tick) {
mytest = function (message,value,errnoput,errnoprop) {
var server = t.sandbox.useFakeServer();
server.respondWith (
// lastmodified = 7000, creationdate = 5000
......@@ -493,8 +521,7 @@ test ('Document save', function () {
deepEqual (result.isSaved,value,message);};
t.spy(o,'f');
o.jio.saveDocument({'fileName':'file','fileContent':'content',
'options':{'force':force,'overwrite':overwrite},
'callback':o.f});
'callback':o.f,'maxtries':1});
clock.tick(500);
server.respond();
if (!o.f.calledOnce)
......@@ -516,21 +543,10 @@ test ('Document save', function () {
// true,201,404);
// the document does not exist, we want to create it
mytest('create document',true,201,404);
// the document is already exists, it is younger than the one we want
// to save.
mytest('younger than the one we want to save',
false,204,207,true,false);
// the document is already exists, it is the youngest but we want to
// force overwriting
mytest('youngest but force overwrite',
true,204,207,true,true);
clock.tick(8000);
// the document already exists, we want to overwrite it
mytest('overwrite document',
true,204,207,true);
// the document already exists, we don't want to overwrite it
mytest('do not overwrite document',
false,204,207,false);
true,204,207);
o.jio.stop();
});
......@@ -555,7 +571,7 @@ test ('Get Document List', function () {
objectifyDocumentArray(value),message);
};
t.spy(o,'f');
o.jio.getDocumentList({'callback':o.f});
o.jio.getDocumentList({'callback':o.f,'maxtries':1});
clock.tick(500);
server.respond();
if (!o.f.calledOnce)
......@@ -585,7 +601,7 @@ test ('Remove document', function () {
o.f = function (result) {
deepEqual (result.isRemoved,value,message);};
t.spy(o,'f');
o.jio.removeDocument({'fileName':'file','callback':o.f});
o.jio.removeDocument({'fileName':'file','callback':o.f,'maxtries':1});
clock.tick(500);
server.respond();
if (!o.f.calledOnce)
......@@ -614,7 +630,8 @@ test ('Check name availability', function () {
o.f = function (result) {
deepEqual (result.isAvailable,value,message)};
t.spy(o,'f');
o.jio.checkNameAvailability({'userName':'Dummy','callback':o.f});
o.jio.checkNameAvailability({'userName':'Dummy','callback':o.f,
'maxtries':1});
clock.tick(1000);
if (!o.f.calledOnce)
ok(false,'no respose / too much results');
......
......@@ -32,8 +32,76 @@
////////////////////////////////////////////////////////////////////////////
// jio globals
jioGlobalObj = {
// For more information, see documentation
'jobManagingMethod':{
/*
LEGEND:
- s: storage
- a: applicant
- m: method
- n: fileName
- c: fileContent
- o: options
- =: are equal
- !: are not equal
select ALL s= a= 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
Check !ongoing Check 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
Check ongoing Check 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 Check 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
GetList !ongoing Check 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
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 Check 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 Check 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 Check 0 0 0 0
Save !ongoing GetList 0 0 0 0
Save !ongoing Check 0 0 0 0
For more information, see documentation
*/
'canSelect':function (job1,job2) {
if (JSON.stringify (job1.storage) ===
JSON.stringify (job2.storage) &&
......@@ -45,9 +113,8 @@
return false;
},
'canRemoveFailOrDone':function (job1,job2) {
if (job1.method === job2.method &&
(job1.status === 'fail' ||
job1.status === 'done')) {
if (job1.status === 'fail' ||
job1.status === 'done') {
return true;
}
return false;
......@@ -63,10 +130,8 @@
},
'canReplace':function (job1,job2) {
if (job1.status !== 'ongoing' &&
job1.method === job2.method &&
JSON.stringify (job1.options) ===
JSON.stringify (job2.options) &&
job1.fileContent === job2.fileContent) {
job1.method === job2.method &&
job1.date < job2.date) {
return true;
}
return false;
......@@ -77,26 +142,32 @@
job2.method === 'loadDocument') {
return true;
}
} else {
if (job1.method === 'loadDocument') {
if (job2.method === 'loadDocument') {
return true;
}
} else if (job1.method === 'removeDocument') {
if (job2.method === 'loadDocument' ||
job2.method === 'removeDocument') {
return true;
}
} 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.fileContent === job2.fileContent &&
JSON.stringify (job1.options) ===
JSON.stringify (job2.options)) {
job1.fileContent === job2.fileContent) {
return true;
} else if (job1.method === job2.method ===
'getDocumentList' ||
job1.method === job2.method ===
'checkNameAvailability') {
return true;
}
}
return false;
},
'mustWait':function (job1,job2) {
if (job1.method === 'getDocumentList' ||
job1.method === 'checkNameAvailability' ||
job2.method === 'getDocumentList' ||
job2.method === 'checkNameAvailability' ) {
return false;
}
return true;
}
},
......@@ -123,14 +194,6 @@
catch (e) { err('LocalOrCookieStorage'); }
return retval;
},
createStorageObject = function ( options ) {
// Create a storage thanks to storages types set with 'addStorageType'.
if (!jioGlobalObj.storageTypeObject[ options.storage.type ])
return null; // error!
return jioGlobalObj.storageTypeObject[
options.storage.type ](options);
},
getNewQueueID = function () {
// Returns a new queueID
var localStor = jioGlobalObj.localStorage.getAll(), k = 'key',
......@@ -156,7 +219,7 @@
////////////////////////////////////////////////////////////////////////////
// Classes
PubSub,Job,JobQueue,JobListener,ActivityUpdater,JioCons,Jio;
PubSub,Job,JobQueue,JobListener,ActivityUpdater,BaseStorage,JioCons,Jio;
// end Classes
////////////////////////////////////////////////////////////////////////////
......@@ -213,11 +276,14 @@
return job;
};
JobQueue = function ( publisher ) {
JobQueue = function ( publisher, options ) {
// JobQueue is a queue of jobs. It will regulary copy this queue
// into localStorage to resume undone tasks.
// pubsub: the publisher to use to send event
// publisher: the publisher to use to send event
// options.useLocalStorage: if true, save jobs into localStorage,
// else only save on memory.
this.useLocalStorage = options.useLocalStorage;
this.publisher = publisher;
this.jobid = 1;
this.jioID = 0;
......@@ -265,20 +331,27 @@
},
copyJobQueueToLocalStorage: function () {
// Copy job queue into localStorage.
return jioGlobalObj.localStorage.setItem(
this.jobObjectName,this.jobObject);
if (this.useLocalStorage) {
return jioGlobalObj.localStorage.setItem(
this.jobObjectName,this.jobObject);
} else {
return false;
}
},
createJob: function ( options ) {
return this.addJob ( new Job ( options ) );
},
addJob: function ( job ) {
// Add a job to the queue TODO DocString
// 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 res = {'newone':true,'elimArray':[],'waitArray':[],
'removeArray':[]},
id=0;
'removeArray':[]}, basestorage = null, id=0;
//// browsing current jobs
for (id in this.jobObject) {
......@@ -287,6 +360,7 @@
if (jioGlobalObj.jobManagingMethod.canRemoveFailOrDone(
this.jobObject[id],job)) {
res.removeArray.push(id);
continue;
}
if (jioGlobalObj.jobManagingMethod.canEliminate(
this.jobObject[id],job)) {
......@@ -299,21 +373,21 @@
this.jobObject[id],job)) {
console.log ('Replaced: ' +
JSON.stringify (this.jobObject[id]));
this.jobObject[id].date = job.date;
// no need to copy fileContent or userName
this.jobObject[id].callback = job.callback;
basestorage = new BaseStorage(
{'queue':this,'job':this.jobObject[id]});
basestorage.replace(job);
res.newone = false;
break;
}
if (jioGlobalObj.jobManagingMethod.cannotAccept(
this.jobObject[id],job)) {
console.log ('Make not accepted: ' +
console.log ('Not accepted: ' + JSON.stringify (job) + '\nby: ' +
JSON.stringify (this.jobObject[id]));
// Job not accepted
return false;
}
if (jioGlobalObj.jobManagingMethod.mustWait(
this.jobObject[id].job)) {
this.jobObject[id],job)) {
console.log ('Waited: ' +
JSON.stringify (this.jobObject[id]) +
'\nby : ' + JSON.stringify (job));
......@@ -330,13 +404,17 @@
// if it is a new job, we can eliminate deprecated jobs and
// set this job dependencies.
for (id in res.elimArray) {
this.removeJob(this.jobObject[res.elimArray[id]]);
basestorage = new BaseStorage(
{'queue':this,'job':this.jobObject[res.elimArray[id]]});
basestorage.eliminate();
}
if (res.waitArray.length > 0) {
job.status = 'wait';
job.waitingFor = {'jobIdArray':res.waitArray};
for (id in res.waitArray) {
this.jobObject[res.waitArray[id]].maxtries = 1;
if (this.jobObject[res.waitArray[id]]) {
this.jobObject[res.waitArray[id]].maxtries = 1;
}
}
}
for (id in res.removeArray) {
......@@ -389,6 +467,8 @@
resetAll: function () {
// Reset all job to 'initial'.
// TODO manage jobs ! All jobs are not 'initial'.
var id = 'id';
for (id in this.jobObject) {
this.jobObject[id].status = 'initial';
......@@ -407,10 +487,10 @@
// invoke new job
this.invoke(this.jobObject[i]);
} else if (this.jobObject[i].status === 'wait') {
ok = true;
// if status wait
if (this.jobObject[i].waitingFor.jobIdArray) {
// wait job
ok = true;
// browsing job id array
for (j in this.jobObject[i].waitingFor.jobIdArray) {
if (this.jobObject[this.jobObject[i].
......@@ -420,18 +500,17 @@
break;
}
}
if (ok) {
// invoke waiting job
this.invoke(this.jobObject[i]);
}
} else if (this.jobObject[i].waitingFor.time) {
}
if (this.jobObject[i].waitingFor.time) {
// wait time
if (this.jobObject[i].waitingFor.time > Date.now()) {
// it is time to restore the job!
this.invoke(this.jobObject[i]);
}
} else {
// wait nothing
// it is not time to restore the job!
ok = false;
}
}
// else wait nothing
if (ok) {
// invoke waiting job
this.invoke(this.jobObject[i]);
}
}
......@@ -443,7 +522,8 @@
invoke: function (job) {
// Do a job invoking the good method in the good storage.
var t = this;
var t = this, basestorage,
userName = job.userName ? job.userName : job.storage.userName;
//// analysing job method
// if the method does not exist, do nothing
......@@ -462,13 +542,8 @@
job.status = 'ongoing';
}
// Create a storage object and use it to save,load,...!
createStorageObject(
{'queue':this,
'storage':job.storage,
'applicant':jioGlobalObj.applicant})[job.method](
job,function (endedjob){
t.ended(endedjob);
});
basestorage = new BaseStorage({'queue':this,'job':job});
basestorage.execute();
//// end method analyse
},
......@@ -486,6 +561,8 @@
// save to local storage
this.copyJobQueueToLocalStorage ();
break;
case 'wait':
break;
default:
break;
}
......@@ -497,7 +574,9 @@
// if there isn't some job to do, then send stop event
if (!this.isThereJobsWhere(function(testjob){
return (testjob.method === job.method &&
testjob.status !== 'fail');
// testjob.status === 'wait' || // TODO ?
testjob.status === 'ongoing' ||
testjob.status === 'initial');
})) {
this.publisher.publish(
jioConstObj.jobMethodObject[
......@@ -510,10 +589,11 @@
// Clean the job list, removing all jobs that have failed.
// It also change the localStorage job queue
this.removeJob (undefined,
{'where':function (job) {
return (job.status === 'fail');
} });
this.removeJob (
undefined,{
'where':function (job) {
return (job.status === 'fail');
} });
}
};
// end Job & JobQueue
......@@ -606,15 +686,147 @@
// end ActivityUpdater
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// BaseStorage
BaseStorage = function ( options ) {
// The base storage, will call the good method from the good storage,
// and will check and return the associated value.
this.job = options.job;
this.callback = options.job.callback;
this.queue = options.queue;
this.res = {'status':'done','message':''};
};
BaseStorage.prototype = {
createStorageObject: function ( options ) {
// Create a storage thanks to storages types set
// with 'addStorageType'.
if (!jioGlobalObj.storageTypeObject[ options.job.storage.type ])
return null; // error!
return jioGlobalObj.storageTypeObject[
options.job.storage.type ](options);
},
retryLater: function () {
// Change the job status to wait for time.
// The listener will invoke this job later.
this.job.status = 'wait';
this.job.waitingFor = {'time':Date.now() +
(this.job.tries*this.job.tries*1000)};
},
eliminate: function () {
this.job.maxtries = 0;
this.fail('Job Stopped!',0);
},
replace: function ( newjob ) {
// It replace the current job by the new one.
// Replacing only the date
this.job.tries = 0;
this.job.date = newjob.date;
this.job.callback = newjob.callback;
this.res.status = 'fail';
this.res.message = 'Job Stopped!';
this.res.errno = 0;
this['fail_'+this.job.method]();
this.callback(this.res);
},
fail: function ( message, errno ) {
// Called when a job has failed.
// It will retry the job from a certain moment or it will return
// a failure.
this.res.status = 'fail';
this.res.message = message;
this.res.errno = errno;
if (this.job.maxtries && this.job.tries < this.job.maxtries) {
this.retryLater();
} else {
this.job.status = 'fail';
this['fail_'+this.job.method]();
this.queue.ended(this.job);
this.callback(this.res);
}
},
done: function ( retvalue ) {
// Called when a job has terminated successfully.
// It will return the return value by the calling the callback
// function.
this.job.status = 'done';
this['done_'+this.job.method]( retvalue );
this.queue.ended(this.job);
this.callback(this.res);
},
execute: function () {
// Execute the good function from the good storage.
var t = this, stor = null;
if (!this.job.tries) {
this.job.tries = 0;
}
this.job.tries ++;
stor = this.createStorageObject (
{'job':this.job,'queue':this.queue}
);
stor.done = function (retval) { t.done(retval); };
stor.fail = function (mess,errno) { t.fail(mess,errno); };
stor[this.job.method]();
},
fail_checkNameAvailability: function () {
this.res.isAvailable = false;
},
done_checkNameAvailability: function ( isavailable ) {
this.res.message = this.job.userName + ' is ' +
(isavailable?'':'not ') + 'available.';
this.res.isAvailable = isavailable;
},
fail_saveDocument: function () {
this.res.isSaved = false;
},
done_saveDocument: function () {
this.res.message = 'Document saved.';
this.res.isSaved = true;
},
fail_loadDocument: function () {
this.res.document = {};
},
done_loadDocument: function ( returneddocument ) {
this.res.message = 'Document loaded.';
this.res.document = returneddocument;
},
fail_getDocumentList: function () {
this.res.list = [];
},
done_getDocumentList: function ( documentlist ) {
this.res.message = 'Document list received.';
this.res.list = documentlist;
},
fail_removeDocument: function () {
this.res.isRemoved = false;
},
done_removeDocument: function () {
this.res.message = 'Document removed.';
this.res.isRemoved = true;
}
};
// end BaseStorage
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// JIO Constructor
JioCons = function ( storage , applicant ) {
JioCons = function ( storage , applicant, options ) {
// 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 settings = $.extend({'useLocalStorage':true},options);
// objectify storage and applicant
if(typeof storage === 'string')
storage = JSON.parse(options.storage);
......@@ -625,11 +837,15 @@
this['storage'] = storage;
this['applicant'] = applicant;
this['id'] = 0;
this['pubsub'] = new PubSub();
this['queue'] = new JobQueue(this.pubsub);
this['listener'] = new JobListener(this.queue);
this['updater'] = new ActivityUpdater();
this['pubsub'] = new PubSub(settings);
this['queue'] = new JobQueue(this.pubsub,settings);
this['listener'] = new JobListener(this.queue,settings);
this['ready'] = false;
if (settings.useLocalStorage) {
this['updater'] = new ActivityUpdater(settings);
} else {
this['updater'] = null;
}
// check storage type
if (this.storage)
......@@ -648,8 +864,10 @@
this.id = getNewQueueID();
// initializing objects
this.queue.init({'jioID':this.id});
// start touching
this.updater.start(this.id);
// start activity updater
if (this.updater){
this.updater.start(this.id);
}
// start listening
this.listener.start();
// is now ready
......@@ -662,7 +880,9 @@
this.queue.close();
this.listener.stop();
this.updater.stop();
if (this.updater) {
this.updater.stop();
}
this.ready = false;
this.id = 0;
return true;
......@@ -673,7 +893,9 @@
this.queue.close();
this.listener.stop();
this.updater.stop();
if (this.updater) {
this.updater.stop();
}
// TODO
this.ready = false;
return true;
......@@ -864,14 +1086,21 @@
// this object permit to create jio object
};
Jio.prototype = {
createNew: function ( storage, applicant) {
// return a new instance of JIO
createNew: function ( storage, applicant, options ) {
// Return a new instance of JIO
// storage: the storage object or json string
// applicant: the applicant object or json string
// options.useLocalStorage: if true, save job queue on localStorage.
var settings = $.extend({'useLocalStorage':true},options);
if (jioGlobalObj.localStorage===null) {
jioGlobalObj.localStorage = LocalOrCookieStorage;
}
return new JioCons(storage,applicant);
return new JioCons(storage,applicant,settings);
},
getStoragePrototype: function () {
return new BaseStorage();
},
addStorageType: function ( type, constructor ) {
// Add a storage type to jio. Jio must have keys/types which are
......
......@@ -38,26 +38,20 @@
////////////////////////////////////////////////////////////////////////////
// Local Storage
LocalStorage = function ( options ) {
LocalStorage = function ( args ) {
// LocalStorage constructor
// initializes the local storage for jio and create user if necessary.
this.userName = options.storage.userName;
this.job = args.job;
};
LocalStorage.prototype = {
checkNameAvailability: function ( job , jobendcallback) {
checkNameAvailability: function () {
// checks the availability of the [job.userName].
// if the name already exists, it is not available.
// job: the job object
// job.userName: the name we want to check.
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isAvailable':boolean}
// in the jobendcallback arguments.
// this.job.userName: the name we want to check.
var available = true, localStor = null,
var t = this, localStor = null,
k = 'key', splitk = ['splitedkey'];
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
localStor = jioGlobalObj.localStorage.getAll();
......@@ -65,221 +59,127 @@
splitk = k.split('/');
if (splitk[0] === 'jio' &&
splitk[1] === 'local' &&
splitk[2] === job.userName) {
available = false;
break;
splitk[2] === t.job.userName) {
return t.done(false);
}
}
if (!available) {
job.status = 'done';
jobendcallback(job);
job.callback({'status':'done',
'message':''+job.userName+
' is not available.',
'isAvailable':false});
} else {
job.status = 'done';
jobendcallback(job);
job.callback({'status':'done',
'message':''+job.userName+
' is available.',
'isAvailable':true});
}
return t.done(true);
}, 100);
}, // end userNameAvailable
saveDocument: function ( job, jobendcallback ) {
saveDocument: function () {
// Save a document in the local storage
// job : the job object
// job.options : the save options object
// job.options.overwrite : true -> overwrite
// job.options.force : true -> save even if jobdate < existingdate
// or overwrite: false
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isSaved':boolean}
// in the jobendcallback arguments.
var settings = $.extend({
'overwrite':true,'force':false},job.options),
res = {}, doc = null;
// this.job.fileName: the document name.
// this.job.fileContent: the document content.
// this.job.storage: the storage information.
// this.job.storage.userName: the user name
// this.job.applicant.ID: the applicant id.
var t = this, doc = null;
// wait a little in order to simulate asynchronous saving
setTimeout (function () {
// reading
doc = jioGlobalObj.localStorage.getItem(
'jio/local/'+job.storage.userName+'/'+job.applicant.ID+'/'+
job.fileName);
if (!doc) { // create document
'jio/local/'+t.job.storage.userName+'/'+
t.job.applicant.ID+'/'+
t.job.fileName);
if (!doc) {
// create document
doc = {
'fileName': job.fileName,
'fileContent': job.fileContent,
'creationDate': job.date,
'lastModified': job.date
'fileName': t.job.fileName,
'fileContent': t.job.fileContent,
'creationDate': Date.now(),
'lastModified': Date.now()
}
// writing
jioGlobalObj.localStorage.setItem(
'jio/local/'+job.storage.userName+'/'+job.applicant.ID+'/'+
job.fileName, doc);
// return
res.status = job.status = 'done';
res.message = 'Document saved.';
res.isSaved = true;
jobendcallback(job);
job.callback(res);
return;
}
if ( settings.overwrite || settings.force ) {
// if it doesn't force writing
// checking modification date
if ( ! settings.force &&
doc.lastModified >= job.date ) {
// date problem!
// return
res.status = job.status = 'fail';
res.message = 'Document is older than the'+
' existing one.';
res.isSaved = false;
jobendcallback(job);
job.callback(res);
return;
}
} else {
// overwriting
doc.lastModified = job.date;
doc.fileContent = job.fileContent;
// writing
jioGlobalObj.localStorage.setItem(
'jio/local/'+job.storage.userName+'/'+job.applicant.ID+'/'+
job.fileName, doc);
// return
res.status = job.status = 'done';
res.message = 'Document saved';
res.isSaved = true;
jobendcallback(job);
job.callback(res);
return;
doc.lastModified = Date.now();
doc.fileContent = t.job.fileContent;
}
// already exists
res.status = job.status = 'fail';
res.message = 'Document already exists.';
res.errno = 403;
res.isSaved = false;
jobendcallback(job);
job.callback(res);
return;
jioGlobalObj.localStorage.setItem(
'jio/local/'+t.job.storage.userName+'/'+
t.job.applicant.ID+'/'+
t.job.fileName, doc);
return t.done();
}, 100);
}, // end saveDocument
loadDocument: function ( job, jobendcallback ) {
loadDocument: function () {
// Load a document from the storage. It returns a document object
// containing all information of the document and its content.
// job : the job object
// job.fileName : the document name we want to load.
// jobendcallback : the function called at the end of the job.
// this.job.fileName : the document name we want to load.
// this.job.options.getContent: if true, also get the file content.
// returns {'status':string,'message':string,'document':object}
// in the jobendcallback arguments.
// document object is {'fileName':string,'fileContent':string,
// 'creationDate':date,'lastModified':date}
var t = this, res = {}, doc = null;
var t = this, doc = null, settings = $.extend(
{'getContent':true},this.job.options);
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
doc = jioGlobalObj.localStorage.getItem(
'jio/local/'+job.storage.userName+'/'+job.applicant.ID+'/'+
job.fileName);
'jio/local/'+t.job.storage.userName+'/'+
t.job.applicant.ID+'/'+t.job.fileName);
if (!doc) {
res.status = job.status = 'fail';
res.errno = 404;
res.message = 'Document not found.';
jobendcallback(job);
job.callback(res);
t.fail('Document not found.',404);
} else {
res.status = job.status = 'done';
res.message = 'Document loaded.';
res.document = {
'fileContent': doc.fileContent,
'fileName': doc.fileName,
'creationDate': doc.creationDate,
'lastModified': doc.lastModified};
jobendcallback(job);
job.callback(res);
if (!settings.getContent) {
delete doc.fileContent;
}
t.done(doc);
}
}, 100);
}, // end loadDocument
getDocumentList: function ( job, jobendcallback) {
getDocumentList: function () {
// Get a document list from the storage. It returns a document
// array containing all the user documents informations, but not
// their content.
// job : the job object
// jobendcallback : the function called at the end of the job.
// this.job.storage: the storage informations.
// this.job.storage.userName: the userName.
// this.job.storage.applicant.ID: the applicant ID.
// returns {'status':string,'message':string,'list':array}
// in the jobendcallback arguments.
// the list is [object,object] -> object = {'fileName':string,
// 'lastModified':date,'creationDate':date}
var t = this, res = {}, localStor = null, k = 'key',
var t = this, list = [], localStor = null, k = 'key',
splitk = ['splitedkey'];
setTimeout(function () {
localStor = jioGlobalObj.localStorage.getAll();
res.list = [];
for (k in localStor) {
splitk = k.split('/');
if (splitk[0] === 'jio' &&
splitk[1] === 'local' &&
splitk[2] === job.storage.userName &&
splitk[3] === job.applicant.ID) {
splitk[2] === t.job.storage.userName &&
splitk[3] === t.job.applicant.ID) {
fileObject = JSON.parse(localStor[k]);
res.list.push ({
list.push ({
'fileName':fileObject.fileName,
'creationDate':fileObject.creationDate,
'lastModified':fileObject.lastModified});
}
}
res.status = job.status = 'done';
res.message = 'List received.';
jobendcallback(job);
job.callback(res);
t.done(list);
}, 100);
}, // end getDocumentList
removeDocument: function ( job, jobendcallback ) {
removeDocument: function () {
// Remove a document from the storage.
// job : the job object
// jobendcallback : the function called at the end of the job.
// returns {'status':string,'message':string,'isRemoved':boolean}
// in the jobendcallback arguments.
// this.job.storage.userName: the userName.
// this.job.applicant.ID: the applicant ID.
// this.job.fileName: the document name.
var t = this, res = {}, doc = null;
var t = this;
setTimeout (function () {
doc = jioGlobalObj.localStorage.getItem(
'jio/local/'+job.storage.userName+'/'+job.applicant.ID+'/'+
job.fileName);
// already deleted
if (!doc) {
res.status = job.status = 'done';
res.message = 'Document already removed.';
res.isRemoved = true;
jobendcallback(job);
job.callback(res);
return;
}
// deleting
jioGlobalObj.localStorage.deleteItem(
'jio/local/'+
job.storage.userName+'/'+job.applicant.ID+'/'+
job.fileName);
res.status = job.status = 'done';
res.message = 'Document removed.';
res.isRemoved = true;
jobendcallback(job);
job.callback(res);
return;
t.job.storage.userName+'/'+t.job.applicant.ID+
'/'+t.job.fileName);
return t.done();
}, 100);
}
},
......@@ -289,8 +189,8 @@
////////////////////////////////////////////////////////////////////////////
// DAVStorage
DAVStorage = function ( options ) {
DAVStorage = function ( args ) {
this.job = args.job;
};
DAVStorage.prototype = {
mkcol: function ( options ) {
......@@ -354,274 +254,177 @@
} );
}
},
checkNameAvailability: function ( job, jobendcallback ) {
checkNameAvailability: function () {
// checks the availability of the [job.userName].
// if the name already exists, it is not available.
// job: the job object.
// job.userName: the name we want to check.
// jobendcallback: the function called at the end of the job.
// this.job.storage: the storage informations.
// this.job.storage.location: the dav storage location.
// this.job.userName: the name we want to check.
// this.job.storage.userName: the user name.
// this.job.storage.password: the user password.
// returns {'status':string,'message':string,'isAvailable':boolean}
// in the jobendcallback arguments.
var res = {};
var t = this;
$.ajax ( {
url: job.storage.location + '/dav/' + job.storage.userName + '/',
url: t.job.storage.location + '/dav/' + t.job.userName + '/',
async: true,
type: 'PROPFIND',
dataType: 'xml',
headers: {'Authorization': 'Basic '+Base64.encode(
job.storage.userName + ':' +
job.storage.password ), Depth: '1'},
t.job.storage.userName + ':' +
t.job.storage.password ), Depth: '1'},
success: function (xmlData) {
res.status = job.status = 'done';
res.message = job.userName + ' is not available.';
res.isAvailable = false;
jobendcallback(job);
job.callback(res);
t.done(false);
},
error: function (type) {
switch(type.status){
case 404:
res.status = job.status = 'done';
res.message = job.userName + ' is available.';
res.isAvailable = true;
t.done(true);
break;
default:
res.status = job.status = 'fail';
res.message = 'Cannot check if ' + job.userName +
' is available.';
res.isAvailable = false;
t.fail('Cannot check if ' + t.job.userName +
' is available.',type.status);
break;
}
res.errno = type.status;
jobendcallback(job);
job.callback(res);
}
} );
},
saveDocument: function ( job, jobendcallback ) {
saveDocument: function () {
// Save a document in a DAVStorage
// job: the job object
// job.options: the save options object
// job.options.overwrite: true -> overwrite
// job.options.force: true -> save even if jobdate < existingdate
// or overwrite: false
// jobendcallback: the function called at the end of the job.
// returns {'status':string,'message':string,'isSaved':boolean}
// in the jobendcallback arguments.
var settings = $.extend ({
'overwrite':true,'force':false},job.options), res = {},
t = this, tmpjob = {},
// this.job.storage: the storage informations.
// this.job.storage.userName: the user name.
// this.job.storage.password: the user password.
// this.job.applicant.ID: the applicant ID.
// this.job.fileName: the document name.
// this.job.fileContent: the document content.
var t = this;
// TODO if path of /dav/user/applic does not exists, it won't work!
saveOnDav = function () {
//// save on dav
$.ajax ( {
url: job.storage.location + '/dav/' +
job.storage.userName + '/' +
job.applicant.ID + '/' +
job.fileName,
type: 'PUT',
data: job.fileContent,
async: true,
dataType: 'text', // TODO is it necessary ?
headers: {'Authorization':'Basic '+Base64.encode(
job.storage.userName + ':' + job.storage.password )},
// xhrFields: {withCredentials: 'true'}, // cross domain
success: function () {
res.status = job.status = 'done';
res.message = 'Document saved.';
res.isSaved = true;
jobendcallback(job);
job.callback(res);
},
error: function (type) {
res.status = job.status = 'fail';
res.message = 'Cannot save document.';
res.errno = type.status;
res.isSaved = false;
jobendcallback(job);
job.callback(res);
}
} );
//// end saving on dav
};
// if force, do not check anything, just save
if (settings.force) {
return saveOnDav();
}
//// start loading document
tmpjob = $.extend({},job);
tmpjob.callback = function(result) {
if(result.status === 'fail') {
switch (result.errno) {
case 404: // Document not found
// TODO MKCOL
// // we can save on it
// t.mkcol({ // create col if not exist
// userName:job.storage.userName,
// password:job.storage.password,
// location:job.storage.location,
// path:'/dav/'+job.storage.userName+'/'+
// job.applicant.ID,
// success:function(){
// // and finaly save document
// saveOnDav()
// },
// error:function(){
// res.status = job.status = 'fail';
// res.message = 'Cannot create document.';
// res.errno = type.status;
// res.isSaved = false;
// jobendcallback(job);
// job.callback(res);
// }});
saveOnDav();
break;
default:
res.status = job.status = 'fail';
res.message = 'Unknown error.';
res.errno = type.status;
res.isSaved = false;
jobendcallback(job);
job.callback(res);
break;
}
} else { // done
// TODO merge files
// Document already exists
if (settings.overwrite) { // overwrite
if (result.document.lastModified >= job.date) {
// date ploblem !
res.status = job.status = 'fail';
res.message = 'Document is older than the '+
'existing one.';
res.isSaved = false;
jobendcallback(job);
job.callback(res);
return;
}
return saveOnDav();
}
// do not overwrite
res.status = job.status = 'fail';
res.message = 'Document already exists.';
res.errno = 403;
res.isSaved = false;
jobendcallback(job);
job.callback(res);
//// save on dav
$.ajax ( {
url: t.job.storage.location + '/dav/' +
t.job.storage.userName + '/' +
t.job.applicant.ID + '/' +
t.job.fileName,
type: 'PUT',
data: t.job.fileContent,
async: true,
dataType: 'text', // TODO is it necessary ?
headers: {'Authorization':'Basic '+Base64.encode(
t.job.storage.userName + ':' + t.job.storage.password )},
// xhrFields: {withCredentials: 'true'}, // cross domain
success: function () {
t.done();
},
error: function (type) {
t.fail('Cannot save document.',type.status);
}
};
this.loadDocument(tmpjob,function(){});
//// end loading document
} );
//// end saving on dav
},
loadDocument: function ( job, jobendcallback ) {
loadDocument: function () {
// Load a document from a DAVStorage. It returns a document object
// containing all information of the document and its content.
// job: the job object
// job.fileName: the document name we want to load.
// jobendcallback: the function called at the end of the job.
// this.job.fileName: the document name we want to load.
// this.job.storage: the storage informations.
// this.job.storage.location: the dav storage location.
// this.job.storage.userName: the user name.
// this.job.storage.password: the user password.
// this.job.options.getContent: if true, also get the file content.
// returns {'status':string,'message':string,'document':object}
// in the jobendcallback arguments.
// document object is {'fileName':string,'fileContent':string,
// 'creationDate':date,'lastModified':date}
var t = this, doc = {},
settings = $.extend({'getContent':true},this.job.options),
// TODO check if job's features are good
var res = {'document':{}},
getContent = function () {
$.ajax ( {
url: job.storage.location + '/dav/' +
job.storage.userName + '/' +
job.applicant.ID + '/' +
job.fileName,
url: t.job.storage.location + '/dav/' +
t.job.storage.userName + '/' +
t.job.applicant.ID + '/' +
t.job.fileName,
type: "GET",
async: true,
dataType: 'text', // TODO is it necessary ?
headers: {'Authorization':'Basic '+Base64.encode(
job.storage.userName + ':' +
job.storage.password )},
t.job.storage.userName + ':' +
t.job.storage.password )},
// xhrFields: {withCredentials: 'true'}, // cross domain
success: function (content) {
res.status = job.status = 'done';
res.message = 'Document loaded.';
res.document.fileContent = content;
jobendcallback(job);
job.callback(res);
doc.fileContent = content;
t.done(doc);
},
error: function (type) {
var message;
switch (type.status) {
case 404:
res.message = 'Document not found.'; break;
message = 'Document not found.'; break;
default:
res.message = 'Cannot load "' + job.fileName + '".';
message = 'Cannot load "' + job.fileName + '".';
break;
}
res.status = job.status = 'fail';
res.errno = type.status;
jobendcallback(job);
job.callback(res);
t.fail(message,type.status);
}
} );
}
// Get properties
$.ajax ( {
url: job.storage.location + '/dav/' +
job.storage.userName + '/' +
job.applicant.ID + '/' +
job.fileName,
url: t.job.storage.location + '/dav/' +
t.job.storage.userName + '/' +
t.job.applicant.ID + '/' +
t.job.fileName,
type: "PROPFIND",
async: true,
dataType: 'xml',
headers: {'Authorization':'Basic '+Base64.encode(
job.storage.userName + ':' +
job.storage.password )},
t.job.storage.userName + ':' +
t.job.storage.password )},
success: function (xmlData) {
res.document.lastModified = (
doc.lastModified = (
new Date($($("lp1\\:getlastmodified",
xmlData).get(0)).text())).getTime();
res.document.creationDate = (
doc.creationDate = (
new Date($($("lp1\\:creationdate",
xmlData).get(0)).text())).getTime();
res.document.fileName = job.fileName;
getContent();
doc.fileName = t.job.fileName;
if (settings.getContent) {
getContent();
} else {
t.done(doc);
}
},
error: function (type) {
res.status = job.status = 'fail';
res.message = 'Cannot get document informations.';
res.errno = type.status;
jobendcallback(job);
job.callback(res);
t.fail('Cannot get document informations.',type.status);
}
} );
},
getDocumentList: function ( job, jobendcallback ) {
getDocumentList: function () {
// Get a document list from a DAVStorage. It returns a document
// array containing all the user documents informations, but their
// content.
// job: the job object
// jobendcallback: the function called at the end of the job.
// returns {'status':string,'message':string,'list':array}
// in the jobendcallback arguments.
// this.job.storage: the storage informations.
// this.job.storage.location: the dav storage location.
// this.job.storage.userName: the user name.
// this.job.storage.password: the user password.
// this.job.applicant.ID: the applicant id.
// the list is [object,object] -> object = {'fileName':string,
// 'lastModified':date,'creationDate':date}
var res = {}, documentArrayList = [], file = {}, pathArray = [];
var t = this, documentArrayList = [], file = {}, pathArray = [];
$.ajax ( {
url: job.storage.location + '/dav/' +
job.storage.userName + '/' + job.applicant.ID + '/',
url: t.job.storage.location + '/dav/' +
t.job.storage.userName + '/' + t.job.applicant.ID + '/',
async: true,
type: 'PROPFIND',
dataType: 'xml',
headers: {'Authorization': 'Basic '+Base64.encode(
job.storage.userName + ':' +
job.storage.password ), Depth: '1'},
t.job.storage.userName + ':' +
t.job.storage.password ), Depth: '1'},
success: function (xmlData) {
$("D\\:response",xmlData).each(function(i,data) {
if(i>0) { // exclude parent folder
......@@ -642,101 +445,78 @@
documentArrayList.push (file);
}
});
res.status = job.status = 'done';
res.message = 'List received.';
res.list = documentArrayList;
jobendcallback(job);
job.callback(res);
t.done(documentArrayList);
},
error: function (type) {
res.status = job.status = 'fail';
res.message = 'Cannot get list.';
res.errno = type.status;
jobendcallback(job);
job.callback(res);
t.fail('Cannot get list.',type.status);
}
} );
},
removeDocument: function ( job, jobendcallback ) {
// Remove a document from a DAVStorage.
// job: the job object
// jobendcallback: the function called at the end of the job.
// this.job.fileName: the document name we want to remove.
// this.job.storage: the storage informations.
// this.job.storage.location: the dav storage location.
// this.job.storage.userName: the user name.
// this.job.storage.password: the user password.
// this.job.applicant.ID: the applicant id.
// returns {'status':string,'message':string,'isRemoved':boolean}
// in the jobendcallback arguments.
var res = {};
var t = this;
$.ajax ( {
url: job.storage.location + '/dav/' +
job.storage.userName + '/' +
job.applicant.ID + '/' +
job.fileName,
url: t.job.storage.location + '/dav/' +
t.job.storage.userName + '/' +
t.job.applicant.ID + '/' +
t.job.fileName,
type: "DELETE",
async: true,
headers: {'Authorization':'Basic '+Base64.encode(
job.storage.userName + ':' +
job.storage.password )},
t.job.storage.userName + ':' +
t.job.storage.password )},
// xhrFields: {withCredentials: 'true'}, // cross domain
success: function () {
res.status = job.status = 'done';
res.message = 'Document removed.';
res.isRemoved = true;
jobendcallback(job);
job.callback(res);
t.done();
},
error: function (type) {
switch (type.status) {
case 404:
res.stauts = job.status = 'done';
res.message = 'Document already removed.';
res.errno = type.status;
res.isRemoved = true;
t.done();
break;
default:
res.status = job.status = 'fail';
res.message = 'Cannot remove "' + job.fileName + '".';
res.isRemoved = false;
res.errno = type.status;
t.fail('Cannot remove "' + t.job.fileName + '".',type.status);
break;
}
jobendcallback(job);
job.callback(res);
}
} );
}
},
// end DAVStorage
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// ReplicateStorage
ReplicateStorage = function ( options ) {
ReplicateStorage = function ( args ) {
// TODO Add a tests that check if there is no duplicate storages.
this.queue = options.queue;
this.queue = args.queue;
this.job = args.job;
this.id = null;
this.length = options.storage.storageArray.length;
this.length = args.job.storage.storageArray.length;
this.returnsValuesArray = [];
};
ReplicateStorage.prototype = {
checkNameAvailability: function ( job, jobendcallback ) {
checkNameAvailability: function () {
// Checks the availability of the [job.userName].
// if the name already exists in a storage, it is not available.
// job: the job object.
// job.userName: the name we want to check.
// job.storage.storageArray: An Array of storages.
// jobendcallback: the function called at the end of the job.
// this.job.userName: the name we want to check.
// this.job.storage.storageArray: An Array of storages.
// returns {'status':string,'message':string,'isAvailable':boolean,
// 'resultArray':Array} in the jobendcallback arguments.
var t = this, newjob = {}, isavailable = true,
res = {'status':'done'}, i = 'ind';
for (i in job.storage.storageArray) {
newjob = $.extend({},job);
newjob.storage = job.storage.storageArray[i];
newjob.callback = function (result){
for (i in t.job.storage.storageArray) {
newjob = $.extend({},t.job);
newjob.storage = t.job.storage.storageArray[i];
newjob.callback = function (result) {
t.returnsValuesArray.push(result);
if (result.status === 'fail') {
res.status = 'fail';
......@@ -744,17 +524,13 @@
if (!result.isAvailable) { isavailable = false; }
if (t.returnsValuesArray.length === t.length) {
// if this is the last callback
job.status = res.status;
res.resultArray = t.returnsValuesArray;
res.isAvailable = isavailable;
jobendcallback(job);
job.callback(res);
t.done(isavailable);
}
};
this.queue.createJob ( newjob ) ;
}
},
saveDocument: function ( job, jobendcallback ) {
saveDocument: function () {
// Save a single document in several storages.
// If a storage failed to save the document, it modify the job in
// in order to invoke it sometime later.
......@@ -770,13 +546,13 @@
// TODO
},
loadDocument: function ( job, jobendcallback ) {
loadDocument: function () {
// TODO
},
getDocumentList: function ( job, jobendcallback ) {
getDocumentList: function () {
// TODO
},
removeDocument: function ( job, jobendcallback ) {
removeDocument: function () {
// TODO
}
};
......
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