X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=manifoldapi%2Fstatic%2Fjs%2Fmanifold.js;h=7b2d54c139ee162aea34fb10bea4ef8e65188ab5;hb=26b2d32f6132a3e619f47411adeccfa693b71162;hp=b9cd225a94aa351c108c5a099f532d6974919bf6;hpb=1d7b0fb8b69c6eca9880a3966acf0352341882bb;p=myslice.git diff --git a/manifoldapi/static/js/manifold.js b/manifoldapi/static/js/manifold.js index b9cd225a..7b2d54c1 100644 --- a/manifoldapi/static/js/manifold.js +++ b/manifoldapi/static/js/manifold.js @@ -17,6 +17,32 @@ function debug_query (msg, query) { else messages.debug ("debug_query: " + msg + " query= " + query); } +// http://stackoverflow.com/questions/7837456/comparing-two-arrays-in-javascript +// attach the .equals method to Array's prototype to call it on any array +Array.prototype.equals = function (array) { + // if the other array is a falsy value, return + if (!array) + return false; + + // compare lengths - can save a lot of time + if (this.length != array.length) + return false; + + for (var i = 0, l=this.length; i < l; i++) { + // Check if we have nested arrays + if (this[i] instanceof Array && array[i] instanceof Array) { + // recurse into the nested arrays + if (!this[i].equals(array[i])) + return false; + } + else if (this[i] != array[i]) { + // Warning - two different object instances will never be equal: {x:20} != {x:20} + return false; + } + } + return true; +} + // http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ Object.toType = (function toType(global) { return function(obj) { @@ -44,42 +70,31 @@ var CLEAR_RECORDS = 8; * * Parameters: * dict : - * .request : ???? used to be FIELD_REQUEST_ADD / FIELD_REQUEST_REMOVE + * .state : ???? used to be FIELD_REQUEST_ADD / FIELD_REQUEST_REMOVE * .key : ??? the key fields of the record - * .value : the key of the record who has received an update - * .status : the new state of the record - * TODO rename to state, and use values from STATE_SET + * .op : the key of the record who has received an update + * .value : the new state of the record */ var FIELD_STATE_CHANGED = 9; var IN_PROGRESS = 101; -var DONE = 102; +var DONE = 102; //XXX Should be harmonized with query state /* Update requests related to subqueries */ -/** - * event: SET_ADD - * - * Parameters: - * string : The key of the element being added - */ +/* var SET_ADD = 201; - -/** - * event: SET_REMOVED - * - * Parameters: - * string : The key of the element being removed - */ var SET_REMOVED = 202; - +*/ // request +/* var FIELD_REQUEST_CHANGE = 301; var FIELD_REQUEST_ADD = 302; var FIELD_REQUEST_REMOVE = 303; var FIELD_REQUEST_ADD_RESET = 304; var FIELD_REQUEST_REMOVE_RESET = 305; +*/ // status (XXX Should be deprecated) var FIELD_REQUEST_PENDING = 401; var FIELD_REQUEST_SUCCESS = 402; @@ -126,9 +141,16 @@ var QUERY_STATE_DONE = 2; * RECORD STATES (for query_store) ******************************************************************************/ -var STATE_SET = 0; -var STATE_WARNINGS = 1; -var STATE_VISIBLE = 2; +var STATE_SET = 20; +var STATE_VALUE = 21; +var STATE_WARNINGS = 22; +var STATE_VISIBLE = 23; + +// ACTIONS +var STATE_SET_CHANGE = 0; +var STATE_SET_ADD = 1; +var STATE_SET_REMOVE = 2; +var STATE_SET_CLEAR = 3; // STATE_SET : enum var STATE_SET_IN = 0; @@ -139,6 +161,9 @@ var STATE_SET_IN_SUCCESS = 4; var STATE_SET_OUT_SUCCESS = 5; var STATE_SET_IN_FAILURE = 6; var STATE_SET_OUT_FAILURE = 7; +var STATE_VALUE_CHANGE_PENDING = 8; +var STATE_VALUE_CHANGE_SUCCESS = 9; +var STATE_VALUE_CHANGE_FAILURE = 10; // STATE_WARNINGS : dict @@ -150,6 +175,12 @@ var STATE_SET_OUT_FAILURE = 7; var CONSTRAINT_RESERVABLE_LEASE = 0; +var CONSTRAINT_RESERVABLE_LEASE_MSG = "Configuration required: this resource needs to be scheduled"; + +var CONSTRAINT_SLA = 1; + +var CONSTRAINT_SLA_MSG = "SLA acceptance required: testbed offers SLA for its resources" + // A structure for storing queries function QueryExt(query, parent_query_ext, main_query_ext, update_query_ext, disabled, domain_query_ext) { @@ -216,6 +247,7 @@ function QueryStore() { // XXX query.change_action() should become deprecated update_query = query.clone(); update_query.action = 'update'; + update_query.fields = []; update_query.analyzed_query.action = 'update'; update_query.params = {}; update_query_ext = new QueryExt(update_query); @@ -317,12 +349,20 @@ function QueryStore() { default_set = (default_set === undefined) ? STATE_SET_OUT : default_set; var self = this; - var query_ext = this.find_analyzed_query_ext(query_uuid); - var record_key = manifold.metadata.get_key(query_ext.query.object); + var key, object, query_ext, record_key; + + query_ext = this.find_analyzed_query_ext(query_uuid); + object = query_ext.query.object; + if (object.indexOf(':') != -1) { + object = object.split(':')[1]; + } + record_key = manifold.metadata.get_key(object); + + // ["start_time", "resource", "end_time"] + // ["urn"] + $.each(records, function(i, record) { - var key = manifold.metadata.get_key(query_ext.query.object); - // ["start_time", "resource", "end_time"] - // ["urn"] + //var key = manifold.metadata.get_key(query_ext.query.object); var record_key_value = manifold.record_get_value(record, record_key); query_ext.records.put(record_key_value, record); @@ -344,6 +384,18 @@ function QueryStore() { return query_ext.records.get(record_key); } + this.del_record = function(query_uuid, record_key) + { + var query_ext = this.find_analyzed_query_ext(query_uuid); + return query_ext.records.remove(record_key); + } + + this.del_state = function(query_uuid, record_key) + { + var query_ext = this.find_analyzed_query_ext(query_uuid); + return query_ext.state.remove(record_key); + } + this.add_record = function(query_uuid, record, new_state) { var query_ext, key, record_key; @@ -374,8 +426,15 @@ function QueryStore() { } else { record_key = record; } - - manifold.query_store.set_record_state(query_uuid, record_key, STATE_SET, new_state); + + if ((query_ext.query.object == 'lease') && (new_state == STATE_SET_OUT)) { + // Leases that are marked out are in fact leases from other slices + // We need to _remove_ leases that we mark as OUT + manifold.query_store.del_record(query_uuid, record_key); + manifold.query_store.del_state(query_uuid, record_key); + } else { + manifold.query_store.set_record_state(query_uuid, record_key, STATE_SET, new_state); + } } this.iter_records = function(query_uuid, callback) @@ -442,7 +501,7 @@ function QueryStore() { { var query_ext = this.find_analyzed_query_ext(query_uuid); query_ext.filters = $.grep(query_ext.filters, function(x) { - return x == filter; + return !(x.equals(filter)); }); this.apply_filters(query_uuid); @@ -506,6 +565,8 @@ function QueryStore() { this.iter_records(query_uuid, function(record_key, record) { var is_reserved, is_pending, in_set, is_unconfigured; + + /* By default, a record is visible unless a filter says the opposite */ var visible = true; var record_state = manifold.query_store.get_record_state(query_uuid, record_key, STATE_SET); @@ -575,13 +636,16 @@ function QueryStore() { if (op == '=' || op == '==') { if ( col_value != value || col_value==null || col_value=="" || col_value=="n/a") visible = false; + }else if (op == 'included') { + /* By default, the filter returns false unless the record + * field match at least one value of the included statement + */ + visible = false; $.each(value, function(i,x) { if(x == col_value){ visible = true; return false; // ~ break - }else{ - visible = false; } }); }else if (op == '!=') { @@ -612,7 +676,7 @@ function QueryStore() { }); var end = new Date().getTime(); - console.log("APPLY FILTERS took", end - start, "ms"); + console.log("APPLY FILTERS [", filters, "] took", end - start, "ms"); } @@ -677,6 +741,12 @@ var manifold = { } else { console.log('Unknown field'); } + // FIX if the record contains a string instead of a key:value + // example: select resource, slice_hrn from slice where slice_hrn=='xxx' + // Result will be {slice_hrn:'xxx', resource:'urn+zzz'} + // We don't have this resource:{urn:'urn+zzz'} + } else if(typeof(record) === 'string'){ + return record; } else { return record[fields]; } @@ -703,49 +773,73 @@ var manifold = { { return function() { ret = ""; - for (i=0; i < key_fields.length; i++) + for (var i=0; i < key_fields.length; i++) ret += "@@" + this[key_fields[i]]; return ret; }; }, - record_equals: function(key_fields) + _record_equals: function(self, other, key_fields) { - var self = this; + if ((typeof self === "string") && (typeof other === "string")) { + return self == other; + } + for (var i=0; i < key_fields.length; i++) { + var this_value = self[key_fields[i]]; + var other_value = other[key_fields[i]]; - return function(other) { - for (i=0; i < key_fields.length; i++) { - var this_value = this[key_fields[i]]; - var other_value = other[key_fields[i]]; + var this_type = manifold.get_type(this_value); + var other_type = manifold.get_type(other_value); + if (this_type != other_type) + return false; - var this_type = self.get_type(this_value); - var other_type = self.get_type(other_value); - if (this_type != other_type) - return false; + switch (this_type) { + case TYPE_VALUE: + case TYPE_LIST_OF_VALUES: + case TYPE_LIST_OF_RECORDS: + if (this_value != other_value) + return false; + break; + case TYPE_RECORD: + if (!(_record_equals(this_value, other_value, key_fields))) + return false; + break; + /* + XXX WARNING = disabled for OpenFlow plugin !!! - switch (this_type) { - case TYPE_VALUE: - case TYPE_LIST_OF_VALUES: - if (this_value != other_value) - return false; - break; - case TYPE_RECORD: - if (!(record_equals(this_value, other_value))) - return false; - break; - case TYPE_LIST_OF_RECORDS: - if (this_value.length != other_value.length) + case TYPE_LIST_OF_RECORDS: + if (this_value.length != other_value.length) + return false; + for (var j = 0; j < this_value.length; j++) + if (!(_record_equals(this_value[j], other_value[j], key_fields))) return false; - for (i = 0; i < this_value.length; i++) - if (!(record_equals(this_value, other_value))) - return false; - break; - } + break; + */ } - return true; + } + return true; + }, + + record_equals: function(key_fields) + { + return function(other) { + return manifold._record_equals(this, other, key_fields); }; }, + _in_array: function(element, array, key_fields) + { + if (key_fields.length > 1) { + for (var i = 0; i < array.length; i++) { + if (manifold._record_equals(element, array[i], key_fields)) + return true; + } + return false; + } else { + // XXX TODO If we have a dict, extract the key first + return ($.inArray(element, array) != -1); + } + }, /************************************************************************** * Metadata management @@ -890,18 +984,44 @@ var manifold = { var query_ext = manifold.query_store.find_query_ext(query.query_uuid); query_ext.query_state = QUERY_STATE_INPROGRESS; - var query_json = JSON.stringify(query); + /* + If the Query object concerns SFA AM objects, iterate on each AM platform + Loop per platform, allows a progressive loading per AM platform + Update is run on all platforms at the same time to get a final answer, we don't manage partial answers yet... + */ + // Removed slice from the per platform query - it's quick enough... + if((query.object == 'resource' || query.object == 'lease') && query.action != "update"){ + var obj = query.object; + $.post("/rest/platform/", function( data ) { + $.each(data, function(index, p) { + query.object = p.platform+":"+obj; + var query_json = JSON.stringify(query); + + // Inform plugins about the progress + query.iter_subqueries(function (sq) { + var sq_query_ext = manifold.query_store.find_analyzed_query_ext(sq.query_uuid); + sq_query_ext.query_state = QUERY_STATE_INPROGRESS; + manifold.raise_record_event(sq.query_uuid, IN_PROGRESS); + }); - // Inform plugins about the progress - query.iter_subqueries(function (sq) { - var sq_query_ext = manifold.query_store.find_analyzed_query_ext(sq.query_uuid); - sq_query_ext.query_state = QUERY_STATE_INPROGRESS; + $.post(manifold.proxy_url, {'json': query_json} , manifold.success_closure(query, null, callback)); - manifold.raise_record_event(sq.query_uuid, IN_PROGRESS); - }); + }); + }); + }else{ + var query_json = JSON.stringify(query); - $.post(manifold.proxy_url, {'json': query_json} , manifold.success_closure(query, null, callback)); + // Inform plugins about the progress + query.iter_subqueries(function (sq) { + var sq_query_ext = manifold.query_store.find_analyzed_query_ext(sq.query_uuid); + sq_query_ext.query_state = QUERY_STATE_INPROGRESS; + manifold.raise_record_event(sq.query_uuid, IN_PROGRESS); + }); + + $.post(manifold.proxy_url, {'json': query_json} , manifold.success_closure(query, null, callback)); + + } }, // XXX DEPRECATED @@ -1001,14 +1121,18 @@ var manifold = { if (query_ext.set_query_ext) { // We have a domain query // The results are stored in the corresponding set_query - manifold.query_store.set_records(query_ext.set_query_ext.query.query_uuid, records) + manifold.query_store.set_records(query_ext.set_query_ext.query.query_uuid, records); } else if (query_ext.domain_query_ext) { // We have a set query, it is only used to determine which objects are in the set, we should only retrieve the key // Has it a domain query, and has it completed ? $.each(records, function(i, record) { var key = manifold.metadata.get_key(query.object); - var record_key = manifold.record_get_value(record, key); + if ( typeof record === "string" ){ + var record_key = record; + }else{ + var record_key = manifold.record_get_value(record, key); + } manifold.query_store.set_record_state(query.query_uuid, record_key, STATE_SET, STATE_SET_IN); }); @@ -1069,7 +1193,8 @@ var manifold = { messages.debug ("<<<<< publish_result_rec " + query.object); }, - setup_update_query: function(query, records) { + setup_update_query: function(query, records) + { // We don't prepare an update query if the result has more than 1 entry if (records.length != 1) return; @@ -1079,7 +1204,6 @@ var manifold = { var update_query_ext = query_ext.update_query_ext; - console.log("Update case not handled yet!"); if (!update_query_ext) return; @@ -1136,7 +1260,20 @@ var manifold = { make_record: function(object, record) { // To make an object a record, we just add the hash function - var key = manifold.metadata.get_key(object); + var key, new_object; + + if (object.indexOf(':') != -1) { + new_object = object.split(':')[1]; + } else { + new_object = object; + } + + key = manifold.metadata.get_key(new_object); + if (!key){ + console.log("object type: " + new_object + " has no key"); + console.log(record); + return; + } record.hashCode = manifold.record_hashcode(key.sort()); record.equals = manifold.record_equals(key); @@ -1175,21 +1312,6 @@ var manifold = { * previous 'process_get_query_records' function. */ process_update_query_records: function(query, records) { - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX - // XXX XXX XXX XXX // First issue: we request everything, and not only what we modify, so will will have to ignore some fields var query_uuid = query.query_uuid; var query_ext = manifold.query_store.find_analyzed_query_ext(query_uuid); @@ -1216,10 +1338,10 @@ var manifold = { throw "Internal error"; data = { - request: FIELD_REQUEST_CHANGE, + state : STATE_SET, key : field, - value : update_value, - status: (update_value == result_value) ? FIELD_REQUEST_SUCCESS : FIELD_REQUEST_FAILURE, + op : update_value, + value : (update_value == result_value) ? STATE_VALUE_CHANGE_SUCCESS : STATE_VALUE_CHANGE_FAILURE, } manifold.raise_record_event(query_uuid, FIELD_STATE_CHANGED, data); @@ -1228,7 +1350,8 @@ var manifold = { throw "Not implemented"; break; - case TYPE_LIST_OF_VALUES: + /* +case TYPE_LIST_OF_VALUES: // Same as list of records, but we don't have to extract keys // The rest of exactly the same (XXX factorize) @@ -1277,66 +1400,86 @@ var manifold = { break; + */ + case TYPE_LIST_OF_VALUES: // XXX Until fixed case TYPE_LIST_OF_RECORDS: + var key, new_state, cur_query_uuid; + if($.inArray(field,Object.keys(query.analyzed_query.subqueries)) > -1){ + cur_query_uuid = query.analyzed_query.subqueries[field].query_uuid; + } + // example: slice.resource // - update_query_orig.params.resource = resources in slice before update // - update_query.params.resource = resource requested in slice // - keys from field = resources obtained - var key = manifold.metadata.get_key(field); + + if (field == 'lease') { + // lease_id has been added to be repeated when + // constructing request rspec. We don't want it for + // comparisons + key = ['start_time', 'end_time', 'resource']; + } else { + key = manifold.metadata.get_key(field); + } if (!key) continue; + /* if (key.length > 1) { throw "Not implemented"; continue; } key = key[0]; + */ /* XXX should be modified for multiple keys */ var result_keys = $.map(record[field], function(x) { return manifold.record_get_value(x, key); }); + // XXX All this could be deduced from record state : STATE_IN_PENDING and STATE_OUT_PENDING + // what we had at the begining var update_keys = update_query_orig.params[field]; + // what we asked var query_keys = update_query.params[field]; - var added_keys = $.grep(query_keys, function (x) { return $.inArray(x, update_keys) == -1 }); - var removed_keys = $.grep(update_keys, function (x) { return $.inArray(x, query_keys) == -1 }); + // what we added and removed + var added_keys = $.grep(query_keys, function (x) { return (!(manifold._in_array(x, update_keys, key))); }); + var removed_keys = $.grep(update_keys, function (x) { return (!(manifold._in_array(x, query_keys, key))); }); + // Send events related to parent query + $.each(added_keys, function(i, added_key) { + new_state = (manifold._in_array(added_key, result_keys, key)) ? STATE_SET_IN_SUCCESS : STATE_SET_IN_FAILURE; - $.each(added_keys, function(i, key) { - if ($.inArray(key, result_keys) == -1) { - data = { - request: FIELD_REQUEST_ADD, - key : field, - value : key, - status: FIELD_REQUEST_FAILURE, - } - } else { - data = { - request: FIELD_REQUEST_ADD, - key : field, - value : key, - status: FIELD_REQUEST_SUCCESS, - } - } + // Update record state for children queries + manifold.query_store.set_record_state(cur_query_uuid, added_key, STATE_SET, new_state); + + // XXX This could be optimized + manifold.query_store.recount(cur_query_uuid); + + data = { state: STATE_SET, key : field, op : new_state, value: added_key } manifold.raise_record_event(query_uuid, FIELD_STATE_CHANGED, data); + + // Inform subquery also + data.key = ''; + manifold.raise_record_event(cur_query_uuid, FIELD_STATE_CHANGED, data); + // XXX Passing no parameters so that they can redraw everything would + // be more efficient but is currently not supported + // XXX We could also need to inform plugins about nodes IN (not pending) that are no more, etc. + // XXX refactor all this when suppressing update_queries, and relying on state instead ! }); - $.each(removed_keys, function(i, key) { - if ($.inArray(key, result_keys) == -1) { - data = { - request: FIELD_REQUEST_REMOVE, - key : field, - value : key, - status: FIELD_REQUEST_SUCCESS, - } - } else { - data = { - request: FIELD_REQUEST_REMOVE, - key : field, - value : key, - status: FIELD_REQUEST_FAILURE, - } - } + $.each(removed_keys, function(i, removed_key) { + new_state = (manifold._in_array(removed_key, result_keys, key)) ? STATE_SET_OUT_FAILURE : STATE_SET_OUT_SUCCESS; + + // Update record state for children queries + manifold.query_store.set_record_state(cur_query_uuid, removed_key, STATE_SET, new_state); + + // XXX This could be optimized + manifold.query_store.recount(cur_query_uuid); + + data = { state: STATE_SET, key : field, op : new_state, value: removed_key } manifold.raise_record_event(query_uuid, FIELD_STATE_CHANGED, data); - }); + // Inform subquery also + data.key = ''; + manifold.raise_record_event(cur_query_uuid, FIELD_STATE_CHANGED, data); + }); break; } @@ -1344,6 +1487,18 @@ var manifold = { // XXX Now we need to adapt 'update' and 'update_orig' queries as if we had done a get this.setup_update_query(query, records); + + var query_ext = manifold.query_store.find_query_ext(query.query_uuid); + query_ext.query_state = QUERY_STATE_DONE; + + var tmp_query = manifold.query_store.find_analyzed_query(query.query_uuid); + manifold.publish_result_rec(tmp_query, records); + + // Send DONE message to plugins + query.iter_subqueries(function(sq, data, parent_query) { + manifold.raise_record_event(sq.query_uuid, DONE); + }); + }, process_query_records: function(query, records) { @@ -1454,342 +1609,448 @@ var manifold = { manifold.raise_event_handler('record', query_uuid, event_type, value); }, + /** + * Event handler helpers + */ + _get_next_state_add: function(prev_state) + { + switch (prev_state) { + case STATE_SET_OUT: + case STATE_SET_OUT_SUCCESS: + case STATE_SET_IN_FAILURE: + new_state = STATE_SET_IN_PENDING; + break; - raise_event: function(query_uuid, event_type, value) { - var query, query_ext; + case STATE_SET_OUT_PENDING: + new_state = STATE_SET_IN; + break; - // Query uuid has been updated with the key of a new element - query_ext = manifold.query_store.find_analyzed_query_ext(query_uuid); - query = query_ext.query; + case STATE_SET_IN: + case STATE_SET_IN_PENDING: + case STATE_SET_IN_SUCCESS: + case STATE_SET_OUT_FAILURE: + console.log("Inconsistent state: already in"); + return; + } + return new_state; + }, - switch(event_type) { + _get_next_state_remove: function(prev_state) + { + switch (prev_state) { + case STATE_SET_IN: + case STATE_SET_IN_SUCCESS: + case STATE_SET_OUT_FAILURE: + new_state = STATE_SET_OUT_PENDING; + break; - case FIELD_STATE_CHANGED: - // value is an object (request, key, value, status) - // update is only possible is the query is not pending, etc - // SET_ADD is on a subquery, FIELD_STATE_CHANGED on the query itself - // we should map SET_ADD on this... + case STATE_SET_IN_PENDING: + new_state = STATE_SET_OUT; + break; - // 1. Update internal query store about the change in status + case STATE_SET_OUT: + case STATE_SET_OUT_PENDING: + case STATE_SET_OUT_SUCCESS: + case STATE_SET_IN_FAILURE: + console.log("Inconsistent state: already out"); + return; + } + return new_state; + }, - // 2. Update the update query - update_query = query_ext.main_query_ext.update_query_ext.query; - update_query_orig = query_ext.main_query_ext.update_query_orig_ext.query; + _grep_active_lease_callback: function(lease_query, resource_key) { + return function(lease_key_lease) { + var state, lease_key, lease; + + lease_key = lease_key_lease[0]; + lease = lease_key_lease[1]; + + if (lease['resource'] != resource_key) + return false; + + state = manifold.query_store.get_record_state(lease_query.query_uuid, lease_key, STATE_SET);; + switch(state) { + case STATE_SET_IN: + case STATE_SET_IN_PENDING: + case STATE_SET_IN_SUCCESS: + case STATE_SET_OUT_FAILURE: + return true; + case STATE_SET_OUT: + case STATE_SET_OUT_PENDING: + case STATE_SET_OUT_SUCCESS: + case STATE_SET_IN_FAILURE: + return false; + } + } + }, - switch(value.request) { - case FIELD_REQUEST_CHANGE: - if (update_query.params[value.key] === undefined) - update_query.params[value.key] = Array(); - update_query.params[value.key] = value.value; - break; - case FIELD_REQUEST_ADD: - if ($.inArray(value.value, update_query_orig.params[value.key]) != -1) - value.request = FIELD_REQUEST_ADD_RESET; - if (update_query.params[value.key] === undefined) - update_query.params[value.key] = Array(); - update_query.params[value.key].push(value.value); - break; - case FIELD_REQUEST_REMOVE: - if ($.inArray(value.value, update_query_orig.params[value.key]) == -1) - value.request = FIELD_REQUEST_REMOVE_RESET; + _enforce_constraints: function(query_ext, record, record_key, event_type) + { + var query, data; - var arr = update_query.params[value.key]; - arr = $.grep(arr, function(x) { return x != value.value; }); - if (update_query.params[value.key] === undefined) - update_query.params[value.key] = Array(); - update_query.params[value.key] = arr; + query = query_ext.query; - break; - case FIELD_REQUEST_ADD_RESET: - case FIELD_REQUEST_REMOVE_RESET: - // XXX We would need to keep track of the original query - throw "Not implemented"; - break; - } + var testbeds_with_sla = localStorage.getItem("sla_testbeds").split(","); + + switch(query.object) { + + case 'resource': + + var warnings = manifold.query_store.get_record_state(query.query_uuid, record_key, STATE_WARNINGS); + // CONSTRAINT_RESERVABLE_LEASE + // + // +) If a reservable node is added to the slice, then it should have a corresponding lease + // XXX Not always a resource + var is_reservable = (record.exclusive == true); + if (is_reservable) { + // var warnings = manifold.query_store.get_record_state(query.query_uuid, record_key, STATE_WARNINGS); + + if (event_type == STATE_SET_ADD) { + // We should have a lease_query associated + var lease_query = query_ext.parent_query_ext.query.subqueries['lease']; // in options + var lease_query_ext = manifold.query_store.find_analyzed_query_ext(lease_query.query_uuid); + // Do we have lease records (in) with this resource + var lease_records = $.grep(lease_query_ext.records.entries(), this._grep_active_lease_callback(lease_query, record_key)); + if (lease_records.length == 0) { + // Sets a warning + // XXX Need for a better function to manage warnings + var warn = CONSTRAINT_RESERVABLE_LEASE_MSG; + warnings[CONSTRAINT_RESERVABLE_LEASE] = warn; + + /*manifold.query_store.set_record_state(query.query_uuid, record_key, STATE_WARNINGS, warnings); + // Signal the change to plugins (even if the constraint does not apply, so that the plugin can display a checkmark) + data = { + state: STATE_WARNINGS, + key : record_key, + op : null, + value : warnings + } + manifold.raise_record_event(query.query_uuid, FIELD_STATE_CHANGED, data);*/ - // 3. Inform others about the change - // a) the main query... - manifold.raise_record_event(query_uuid, event_type, value); + } else { + // Lease are defined, delete the warning in case it was set previously + delete warnings[CONSTRAINT_RESERVABLE_LEASE]; + } + } else { + // Remove warnings attached to this resource + delete warnings[CONSTRAINT_RESERVABLE_LEASE]; + } + } - // b) subqueries eventually (dot in the key) - // Let's unfold - var path_array = value.key.split('.'); - var value_key = value.key.split('.'); + var urn_regexp = /\+(.*?)\+/; + var testbed_urn = urn_regexp.exec(record.urn)[1]; + var has_sla = $.inArray(testbed_urn, testbeds_with_sla) != -1; - var cur_query = query; - if (cur_query.analyzed_query) - cur_query = cur_query.analyzed_query; - $.each(path_array, function(i, method) { - cur_query = cur_query.subqueries[method]; - value_key.shift(); // XXX check that method is indeed shifted - }); - value.key = value_key; + if (has_sla) { + // var warnings = manifold.query_store.get_record_state(query.query_uuid, record_key, STATE_WARNINGS); - manifold.query_store.recount(cur_query.query_uuid); - manifold.raise_record_event(cur_query.query_uuid, event_type, value); + if (event_type == STATE_SET_ADD) { + var warn = CONSTRAINT_SLA_MSG; + warnings[CONSTRAINT_SLA] = warn; + } else { + delete warnings[CONSTRAINT_SLA]; + } + } + manifold.query_store.set_record_state(query.query_uuid, record_key, STATE_WARNINGS, warnings); + // Signal the change to plugins (even if the constraint does not apply, so that the plugin can display a checkmark) + data = { + state: STATE_WARNINGS, + key : record_key, + op : null, + value : warnings + } + manifold.raise_record_event(query.query_uuid, FIELD_STATE_CHANGED, data); - // XXX make this DOT a global variable... could be '/' - break; + // JGLL: SLA code + /*get_testbeds_with_sla() + .done( function(testbeds) { + var urn_regexp = /\+(.*?)\+/; + var testbed_urn = urn_regexp.exec(record.urn)[1]; - case SET_ADD: - case SET_REMOVED: - - /* An object has been added to / removed from a set : its - * status become pending or reset to the original state. We - * update the record status in the analyzed queries. - * - * XXX Shall we update something in the main_query ? - */ - var prev_state, new_state; - - prev_state = manifold.query_store.get_record_state(query_uuid, value, STATE_SET); - if (prev_state === null) - prev_state = STATE_SET_OUT; - - if (event_type == SET_ADD) { - switch (prev_state) { - case STATE_SET_OUT: - case STATE_SET_OUT_SUCCESS: - case STATE_SET_IN_FAILURE: - new_state = STATE_SET_IN_PENDING; - break; - - case STATE_SET_OUT_PENDING: - new_state = STATE_SET_IN; - break; - - case STATE_SET_IN: - case STATE_SET_IN_PENDING: - case STATE_SET_IN_SUCCESS: - case STATE_SET_OUT_FAILURE: - console.log("Inconsistent state: already in"); - return; - } - } else { // SET_REMOVE - switch (prev_state) { - case STATE_SET_IN: - case STATE_SET_IN_SUCCESS: - case STATE_SET_OUT_FAILURE: - new_state = STATE_SET_OUT_PENDING; - break; - - case STATE_SET_IN_PENDING: - new_state = STATE_SET_OUT; - break; - - case STATE_SET_OUT: - case STATE_SET_OUT_PENDING: - case STATE_SET_OUT_SUCCESS: - case STATE_SET_IN_FAILURE: - console.log("Inconsistent state: already out"); - return; - } - } + var warnings = manifold.query_store.get_record_state(query.query_uuid, record_key, STATE_WARNINGS); - - var resource_key = value; + if ($.inArray(testbed_urn, testbeds) != -1) { + // JGLL: Set a warning on resources covered by testbeds offering SLAs + // CONSTRAINT_SLA - if (event_type == SET_ADD) - manifold.query_store.add_record(query_uuid, resource_key, new_state); - else - manifold.query_store.remove_record(query_uuid, resource_key, new_state); - - var record = manifold.query_store.get_record(query_uuid, resource_key); - - /* CONSTRAINTS */ - - // XXX When we add a lease we must update the warnings - - switch(query.object) { - - case 'resource': - // CONSTRAINT_RESERVABLE_LEASE - // - // +) If a reservable node is added to the slice, then it should have a corresponding lease - // XXX Not always a resource - var is_reservable = (record.exclusive == true); - if (is_reservable) { - var warnings = manifold.query_store.get_record_state(query_uuid, resource_key, STATE_WARNINGS); - - if (event_type == SET_ADD) { - // We should have a lease_query associated - var lease_query = query_ext.parent_query_ext.query.subqueries['lease']; // in options - var lease_query_ext = manifold.query_store.find_analyzed_query_ext(lease_query.query_uuid); - // Do we have lease records with this resource - var lease_records = $.grep(lease_query_ext.records, function(lease_key, lease) { - return lease['resource'] == value; - }); - if (lease_records.length == 0) { - // Sets a warning - // XXX Need for a better function to manage warnings - var warn = "No lease defined for this reservable resource."; - warnings[CONSTRAINT_RESERVABLE_LEASE] = warn; - } else { - // Lease are defined, delete the warning in case it was set previously - delete warnings[CONSTRAINT_RESERVABLE_LEASE]; - } + if (event_type == STATE_SET_ADD) { + var warn = CONSTRAINT_SLA_MSG; + warnings[CONSTRAINT_SLA] = warn; } else { - // Remove warnings attached to this resource - delete warnings[CONSTRAINT_RESERVABLE_LEASE]; + delete warnings[CONSTRAINT_SLA] } - - manifold.query_store.set_record_state(query_uuid, resource_key, STATE_WARNINGS, warnings); - break; } + manifold.query_store.set_record_state(query.query_uuid, record_key, STATE_WARNINGS, warnings); + // Signal the change to plugins (even if the constraint does not apply, so that the plugin can display a checkmark) data = { - request: null, - key : null, - value : resource_key, - status: STATE_WARNINGS - }; - manifold.raise_record_event(query_uuid, FIELD_STATE_CHANGED, data); + state: STATE_WARNINGS, + key : record_key, + op : null, + value : warnings + } - case 'lease': - var resource_key = record.resource; - var resource_query = query_ext.parent_query_ext.query.subqueries['resource']; - var warnings = manifold.query_store.get_record_state(resource_query.query_uuid, resource_key, STATE_WARNINGS); + manifold.raise_record_event(query.query_uuid, FIELD_STATE_CHANGED, data); + }) + .fail( function(err) { + console.log("SLA - Error retrieving testbeds that support SLAs"); + });*/ - if (event_type == SET_ADD) { - // A lease is added, it removes the constraint - delete warnings[CONSTRAINT_RESERVABLE_LEASE]; - } else { - // A lease is removed, it might trigger the warning - var lease_records = $.grep(query_ext.records, function(lease_key, lease) { - return lease['resource'] == value; - }); - if (lease_records.length == 0) { // XXX redundant cases - // Sets a warning - // XXX Need for a better function to manage warnings - var warn = "No lease defined for this reservable resource."; - warnings[CONSTRAINT_RESERVABLE_LEASE] = warn; - } else { - // Lease are defined, delete the warning in case it was set previously - delete warnings[CONSTRAINT_RESERVABLE_LEASE]; - } - - } + /* This was redundant */ + // manifold.query_store.recount(query.query_uuid); + + break; + + case 'lease': + var resource_key = record_key.resource; + var resource_query = query_ext.parent_query_ext.query.subqueries['resource']; + var warnings = manifold.query_store.get_record_state(resource_query.query_uuid, resource_key, STATE_WARNINGS); + + if (event_type == STATE_SET_ADD || event_type == STATE_SET_IN_PENDING) { + // A lease is added, it removes the constraint + delete warnings[CONSTRAINT_RESERVABLE_LEASE]; + } else { + // A lease is removed, it might trigger the warning + var lease_records = $.grep(query_ext.records.entries(), this._grep_active_lease_callback(query, resource_key)); + if (lease_records.length == 0) { // XXX redundant cases + // Sets a warning + // XXX Need for a better function to manage warnings + var warn = CONSTRAINT_RESERVABLE_LEASE_MSG; + warnings[CONSTRAINT_RESERVABLE_LEASE] = warn; // Signal the change to plugins (even if the constraint does not apply, so that the plugin can display a checkmark) data = { - request: null, - key : null, - value : resource_key, - status: STATE_WARNINGS - }; + state: STATE_WARNINGS, + key : resource_key, + op : null, + value : warnings + } manifold.raise_record_event(resource_query.query_uuid, FIELD_STATE_CHANGED, data); - break; + } else { + // Lease are defined, delete the warning in case it was set previously + delete warnings[CONSTRAINT_RESERVABLE_LEASE]; + } } + /* Adding a lease can remove a warning and reduce the unconfigured resources */ + manifold.query_store.recount(resource_query.query_uuid); + break; + } + + // -) When a lease is added, it might remove the warning associated to a reservable node + + // If a NITOS node is reserved, then at least a NITOS channel should be reserved + // - When a NITOS channel is added, it might remove a warning associated to all NITOS nodes + + // If a NITOS channel is reserved, then at least a NITOS node should be reserved + // - When a NITOS node is added, it might remove a warning associated to all NITOS channels + + // A lease is present while the resource has been removed => Require warnings on nodes not in set ! + }, - // -) When a lease is added, it might remove the warning associated to a reservable node + _get_query_path: function(query_ext) { + var path = ""; + var sq = query_ext; + while (sq.parent_query_ext) { + if (path != "") + path = '.' + path; + path = sq.query.object + path; + sq = sq.parent_query_ext; + } + return path; + }, - // If a NITOS node is reserved, then at least a NITOS channel should be reserved - // - When a NITOS channel is added, it might remove a warning associated to all NITOS nodes - // If a NITOS channel is reserved, then at least a NITOS node should be reserved - // - When a NITOS node is added, it might remove a warning associated to all NITOS channels + /** + * Handling events raised by plugins + */ + raise_event: function(query_uuid, event_type, data) + { + var query, query_ext; + + // Query uuid has been updated with the key of a new element + query_ext = manifold.query_store.find_analyzed_query_ext(query_uuid); + query = query_ext.query; - // A lease is present while the resource has been removed => Require warnings on nodes not in set ! + switch(event_type) { + case STATUS_REMOVE_WARNING: + record = manifold.query_store.get_record(query_uuid, data.value); + this._enforce_constraints(query_ext, record, data.value, STATE_SET_REMOVE); + break; - /* END CONSTRAINTS */ + // XXX At some point, should be renamed to RECORD_STATE_CHANGED + case FIELD_STATE_CHANGED: + // value is an object (request, key, value, status) // update is only possible is the query is not pending, etc - // CHECK status ! - - // XXX we can only update subqueries of the main query. Check ! - // assert query_ext.parent_query == query_ext.main_query - // old // update_query = query_ext.main_query_ext.update_query_ext.query; - - // This SET_ADD is called on a subquery, so we have to - // recontruct the path of the key in the main_query - // We then call FIELD_STATE_CHANGED which is the equivalent for the main query - - var path = ""; - var sq = query_ext; - while (sq.parent_query_ext) { - if (path != "") - path = '.' + path; - path = sq.query.object + path; - sq = sq.parent_query_ext; + // SET_ADD is on a subquery, FIELD_STATE_CHANGED on the query itself + // we should map SET_ADD on this... + + // 1. Update internal query store about the change in status + + // 2. Update the update query + update_query = query_ext.main_query_ext.update_query_ext.query; + update_query_orig = query_ext.main_query_ext.update_query_orig_ext.query; + + switch(data.state) { + + case STATE_VALUE: + switch(data.op) { + case STATE_CHANGE: + /* Set parameter data.key in the update_query to VALUE */ + if (update_query.params[data.key] === undefined) + update_query.params[data.key] = Array(); + update_query.params[data.key] = value.value; + break; + + } + break; + + case STATE_SET: + var prev_state, new_state; + var main_query, record, new_data, path; + + // We only track state in the analyzed query + prev_state = manifold.query_store.get_record_state(query_uuid, data.value, STATE_SET); + if (prev_state === null) + prev_state = STATE_SET_OUT; + + switch(data.op) { + case STATE_SET_ADD: + new_state = this._get_next_state_add(prev_state); + + /* data.value containts the resource key */ + manifold.query_store.add_record(query_uuid, data.value, new_state); + record = manifold.query_store.get_record(query_uuid, data.value); + this._enforce_constraints(query_ext, record, data.value, STATE_SET_ADD); + + /* Process update query in parent */ + path = this._get_query_path(query_ext); + if (update_query.params[path] === undefined) + update_query.params[path] = Array(); + update_query.params[path].push(data.value); + + break; + + case STATE_SET_REMOVE: + new_state = this._get_next_state_remove(prev_state); + + /* data.value contains the resource key */ + manifold.query_store.remove_record(query_uuid, data.value, new_state); + record = manifold.query_store.get_record(query_uuid, data.value); + this._enforce_constraints(query_ext, record, data.value, STATE_SET_REMOVE); + + /* Process update query in parent */ + path = this._get_query_path(query_ext); + arr = update_query.params[path]; + + var key = manifold.metadata.get_key(query.object); + arr = $.grep(arr, function(x) { return (!(manifold._record_equals(x, data.value, key))); }); + if (update_query.params[path] === undefined) + update_query.params[path] = Array(); + update_query.params[path] = arr; + break; + } + + /* Inform the parent query: important for update */ + new_data = { + state : STATE_SET, + key : path, + op : new_state, + value : data.value, + }; + main_query = query_ext.main_query_ext.query; + manifold.raise_record_event(main_query.query_uuid, event_type, new_data); + /* Propagate the event to other plugins subscribed to the query */ + manifold.query_store.recount(query_uuid); + new_data.key = '' + manifold.raise_record_event(query_uuid, event_type, new_data); + + break; } +/* + // 3. Inform others about the change + // a) the main query... + manifold.raise_record_event(query_uuid, event_type, data); - main_query = query_ext.main_query_ext.query; - data = { - request: (event_type == SET_ADD) ? FIELD_REQUEST_ADD : FIELD_REQUEST_REMOVE, - key : path, - value : value, - status: STATE_SET, // XXX used to be FIELD_REQUEST_PENDING, and not new_state - }; - this.raise_event(main_query.query_uuid, FIELD_STATE_CHANGED, data); - - // old //update_query.params[path].push(value); - // old // console.log('Updated query params', update_query); - // NOTE: update might modify the fields in Get - // NOTE : we have to modify all child queries - // NOTE : parts of a query might not be started (eg slice.measurements, how to handle ?) - - // if everything is done right, update_query should not be null. - // It is updated when we received results from the get query - // object = the same as get - // filter = key : update a single object for now - // fields = the same as get - manifold.raise_query_event(query_uuid, event_type, value); + // b) subqueries eventually (dot in the key) + // Let's unfold + + var cur_query = query; + if (cur_query.analyzed_query) + cur_query = cur_query.analyzed_query; + + if (data.key) { + var path_array = data.key.split('.'); + var value_key = data.key.split('.'); + $.each(path_array, function(i, method) { + cur_query = cur_query.subqueries[method]; + value_key.shift(); // XXX check that method is indeed shifted + }); + data.key = value_key; + } + manifold.raise_record_event(cur_query.query_uuid, event_type, data); +*/ break; case RUN_UPDATE: + query_ext.main_query_ext.update_query_ext.query.fields = []; manifold.run_query(query_ext.main_query_ext.update_query_ext.query); break; - /* FILTERS */ + /* QUERY STATE CHANGED */ + + // FILTERS case FILTER_ADDED: + console.log("FILTER ADDED", data); /* Update internal record state */ - manifold.query_store.add_filter(query_uuid, value); + manifold.query_store.add_filter(query_uuid, data); /* Propagate the message to plugins */ - manifold.raise_query_event(query_uuid, event_type, value); + manifold.raise_query_event(query_uuid, event_type, data); break; case FILTER_REMOVED: + console.log("FILTER REMOVED", data); /* Update internal record state */ - manifold.query_store.remove_filter(query_uuid, value); + manifold.query_store.remove_filter(query_uuid, data); /* Propagate the message to plugins */ - manifold.raise_query_event(query_uuid, event_type, value); + manifold.raise_query_event(query_uuid, event_type, data); break; case FIELD_ADDED: main_query = query_ext.main_query_ext.query; main_update_query = query_ext.main_query_ext.update_query; - query.select(value); + query.select(data); // Here we need the full path through all subqueries path = "" // XXX We might need the query name in the QueryExt structure - main_query.select(value); + main_query.select(data); // XXX When is an update query associated ? // XXX main_update_query.select(value); - manifold.raise_query_event(query_uuid, event_type, value); + manifold.raise_query_event(query_uuid, event_type, data); break; case FIELD_REMOVED: query = query_ext.query; main_query = query_ext.main_query_ext.query; main_update_query = query_ext.main_query_ext.update_query; - query.unselect(value); - main_query.unselect(value); + query.unselect(data); + main_query.unselect(data); // We need to inform about changes in these queries to the respective plugins // Note: query & main_query have the same UUID - manifold.raise_query_event(query_uuid, event_type, value); + manifold.raise_query_event(query_uuid, event_type, data); break; } // We need to inform about changes in these queries to the respective plugins