src/js/libs/tracemanager.js
changeset 899 445631dffdf8
parent 841 8da49ff273e0
child 901 12b2cd7e9159
equal deleted inserted replaced
897:94fea76c883e 899:445631dffdf8
    10      // then "compress" them as a single "ktbsFullBuffer"
    10      // then "compress" them as a single "ktbsFullBuffer"
    11      MAX_BUFFER_SIZE = 500;
    11      MAX_BUFFER_SIZE = 500;
    12 
    12 
    13      var BufferedService_prototype = {
    13      var BufferedService_prototype = {
    14          /*
    14          /*
    15           *  Buffered service for traces
    15 * Buffered service for traces
    16           */
    16 */
    17          // url: "",
    17          // url: "",
    18          // buffer: [],
    18          // buffer: [],
    19          // isReady: false,
    19          // isReady: false,
    20          // timer: null,
    20          // timer: null,
    21          // failureCount: 0,
    21          // failureCount: 0,
    41                      // prefixing it with c
    41                      // prefixing it with c
    42                      var data = 'c' + JSON.stringify(temp.map(function (o) { return o.toCompactJSON(); }));
    42                      var data = 'c' + JSON.stringify(temp.map(function (o) { return o.toCompactJSON(); }));
    43                      // Swap " (very frequent, which will be
    43                      // Swap " (very frequent, which will be
    44                      // serialized into %22) and ; (rather rare), this
    44                      // serialized into %22) and ; (rather rare), this
    45                      // saves some bytes
    45                      // saves some bytes
    46                      data = data.replace(/[;"]/g, function(s){ return s == ';' ? '"' : ';'; }).replace(/#/g, '%23');
    46                      data = data.replace(/[;"#]/g, function(s){ return s == ';' ? '"' : ( s == '"' ? ';' : '%23'); });
    47                      // FIXME: check data length (< 2K is safe)
    47                      // FIXME: check data length (< 2K is safe)
    48                      var request=$('<img />').error( function() { this.failureCount += 1; })
    48                      var request=$('<img />').error( function() { this.failureCount += 1; })
    49                          .load( function() { this.failureCount = 0; })
    49                          .load( function() { this.failureCount = 0; })
    50                          .attr('src', this.url + 'trace/?data=' + data);
    50                          .attr('src', this.url + 'trace/?data=' + data);
    51                  }
    51                  }
    70                  }
    70                  }
    71              }
    71              }
    72          },
    72          },
    73 
    73 
    74          /* Sync mode: delayed, sync (immediate sync), none (no
    74          /* Sync mode: delayed, sync (immediate sync), none (no
    75           * synchronisation with server, the trace has to be explicitly saved
    75 * synchronisation with server, the trace has to be explicitly saved
    76           * if needed */
    76 * if needed */
    77          set_sync_mode: function(mode) {
    77          set_sync_mode: function(mode, default_subject) {
    78              this.sync_mode = mode;
    78              this.sync_mode = mode;
    79              if (! this.isReady && mode !== "none")
    79              if (! this.isReady && mode !== "none")
    80                  this.init();
    80                  this.init(default_subject);
    81              if (mode == 'delayed') {
    81              if (mode == 'delayed') {
    82                  this.start_timer();
    82                  this.start_timer();
    83              } else {
    83              } else {
    84                  this.stop_timer();
    84                  this.stop_timer();
    85              }
    85              }
   116                  this.timer = null;
   116                  this.timer = null;
   117              }
   117              }
   118          },
   118          },
   119 
   119 
   120          /*
   120          /*
   121           * Initialize the sync service
   121 * Initialize the sync service
   122           */
   122 */
   123          init: function() {
   123          init: function(default_subject) {
   124              var self = this;
   124              var self = this;
   125              if (this.isReady)
   125              if (this.isReady)
   126                  /* Already initialized */
   126                  /* Already initialized */
   127                  return;
   127                  return;
       
   128              if (typeof default_subject === 'undefined')
       
   129                  default_subject = 'anonymous';
   128              if (this.mode == 'GET')
   130              if (this.mode == 'GET')
   129              {
   131              {
   130                  var request=$('<img/>').attr('src', this.url + 'login?userinfo={"name":"ktbs4js"}');
   132                  var request=$('<img/>').attr('src', this.url + 'login?userinfo={"default_subject": "' + default_subject + '"}');
   131                  // Do not wait for the return, assume it is
   133                  // Do not wait for the return, assume it is
   132                  // initialized. This assumption will not work anymore
   134                  // initialized. This assumption will not work anymore
   133                  // if login returns some necessary information
   135                  // if login returns some necessary information
   134                  this.isReady = true;
   136                  this.isReady = true;
   135              }
   137              }
   136              else
   138              else
   137              {
   139              {
   138                  $.ajax({ url: this.url + 'login',
   140                  $.ajax({ url: this.url + 'login',
   139                           type: 'POST',
   141                           type: 'POST',
   140                           data: 'userinfo={"name":"ktbs4js"}',
   142                           data: 'userinfo={"default_subject":"' + default_subject + '"}',
   141                           success: function(data, textStatus, jqXHR) {
   143                           success: function(data, textStatus, jqXHR) {
   142                               self.isReady = true;
   144                               self.isReady = true;
   143                               if (self.buffer.length) {
   145                               if (self.buffer.length) {
   144                                   self.flush();
   146                                   self.flush();
   145                               }
   147                               }
   166      };
   168      };
   167      BufferedService.prototype = BufferedService_prototype;
   169      BufferedService.prototype = BufferedService_prototype;
   168 
   170 
   169      var Trace_prototype = {
   171      var Trace_prototype = {
   170          /* FIXME: We could/should use a sorted list such as
   172          /* FIXME: We could/should use a sorted list such as
   171           http://closure-library.googlecode.com/svn/docs/class_goog_structs_AvlTree.html
   173 http://closure-library.googlecode.com/svn/docs/class_goog_structs_AvlTree.html
   172           to speed up queries based on time */
   174 to speed up queries based on time */
   173          obsels: [],
   175          obsels: [],
   174          /* Trace URI */
   176          /* Trace URI */
   175          uri: "",
   177          uri: "",
   176          default_subject: "",
   178          default_subject: "",
   177          /* baseuri is used as the base URI to resolve relative
   179          /* baseuri is used as the base URI to resolve relative
   178           * attribute-type names in obsels. Strictly speaking, this
   180 * attribute-type names in obsels. Strictly speaking, this
   179           * should rather be expressed as a reference to model, or
   181 * should rather be expressed as a reference to model, or
   180           * more generically, as a qname/URI dict */
   182 * more generically, as a qname/URI dict */
   181          baseuri: "",
   183          baseuri: "",
   182          /* Mapping of obsel type or property name to a compact
   184          /* Mapping of obsel type or property name to a compact
   183           * representation (shorthands).
   185 * representation (shorthands).
   184           */
   186 */
   185          shorthands: null,
   187          shorthands: null,
   186          syncservice: null,
   188          syncservice: null,
   187 
   189 
   188          /* Define the trace URI */
   190          /* Define the trace URI */
   189          set_uri: function(uri) {
   191          set_uri: function(uri) {
   190              this.uri = uri;
   192              this.uri = uri;
   191          },
   193          },
   192 
   194 
   193          /* Sync mode: delayed, sync (immediate sync), none (no
   195          /* Sync mode: delayed, sync (immediate sync), none (no
   194           * synchronisation with server, the trace has to be explicitly saved
   196 * synchronisation with server, the trace has to be explicitly saved
   195           * if needed */
   197 * if needed */
   196          set_sync_mode: function(mode) {
   198          set_sync_mode: function(mode) {
   197              if (this.syncservice !== null) {
   199              if (this.syncservice !== null) {
   198                  this.syncservice.set_sync_mode(mode);
   200                  this.syncservice.set_sync_mode(mode, this.default_subject);
   199              }
   201              }
   200          },
   202          },
   201 
   203 
   202          /*
   204          /*
   203           * Return a list of the obsels of this trace matching the parameters
   205 * Return a list of the obsels of this trace matching the parameters
   204           */
   206 */
   205          list_obsels: function(_begin, _end, _reverse) {
   207          list_obsels: function(_begin, _end, _reverse) {
   206              var res;
   208              var res;
   207              if (typeof _begin !== 'undefined' || typeof _end !== 'undefined') {
   209              if (typeof _begin !== 'undefined' || typeof _end !== 'undefined') {
   208                  /*
   210                  /*
   209                   * Not optimized yet.
   211 * Not optimized yet.
   210                   */
   212 */
   211                  res = [];
   213                  res = [];
   212                  var l = this.obsels.length;
   214                  var l = this.obsels.length;
   213                  for (var i = 0; i < l; i++) {
   215                  for (var i = 0; i < l; i++) {
   214                      var o = this.obsels[i];
   216                      var o = this.obsels[i];
   215                      if ((typeof _begin !== 'undefined' && o.begin > _begin) && (typeof _end !== 'undefined' && o.end < _end)) {
   217                      if ((typeof _begin !== 'undefined' && o.begin > _begin) && (typeof _end !== 'undefined' && o.end < _end)) {
   233              return res;
   235              return res;
   234 
   236 
   235          },
   237          },
   236 
   238 
   237          /*
   239          /*
   238           * Return the obsel of this trace identified by the URI, or undefined
   240 * Return the obsel of this trace identified by the URI, or undefined
   239           */
   241 */
   240          get_obsel: function(id) {
   242          get_obsel: function(id) {
   241              for (var i = 0; i < this.obsels.length; i++) {
   243              for (var i = 0; i < this.obsels.length; i++) {
   242                  /* FIXME: should check against variations of id/uri, take this.baseuri into account */
   244                  /* FIXME: should check against variations of id/uri, take this.baseuri into account */
   243                  if (this.obsels[i].uri === id) {
   245                  if (this.obsels[i].uri === id) {
   244                      return this.obsels[i];
   246                      return this.obsels[i];
   246              }
   248              }
   247              return undefined;
   249              return undefined;
   248          },
   250          },
   249 
   251 
   250          set_default_subject: function(subject) {
   252          set_default_subject: function(subject) {
       
   253              // FIXME: if we call this method after the sync_service
       
   254              // init method, then the default_subject will not be
       
   255              // consistent anymore. Maybe we should then call init() again?
   251              this.default_subject = subject;
   256              this.default_subject = subject;
   252          },
   257          },
   253 
   258 
   254          get_default_subject: function() {
   259          get_default_subject: function() {
   255              return this.default_subject;
   260              return this.default_subject;
   289          }
   294          }
   290      };
   295      };
   291 
   296 
   292      var Trace = function(uri, requestmode) {
   297      var Trace = function(uri, requestmode) {
   293          /* FIXME: We could/should use a sorted list such as
   298          /* FIXME: We could/should use a sorted list such as
   294           http://closure-library.googlecode.com/svn/docs/class_goog_structs_AvlTree.html
   299 http://closure-library.googlecode.com/svn/docs/class_goog_structs_AvlTree.html
   295           to speed up queries based on time */
   300 to speed up queries based on time */
   296          this.obsels = [];
   301          this.obsels = [];
   297          /* Trace URI */
   302          /* Trace URI */
   298          if (uri === undefined)
   303          if (uri === undefined)
   299              uri = "";
   304              uri = "";
   300          this.uri = uri;
   305          this.uri = uri;
   314      };
   319      };
   315      Trace.prototype = Trace_prototype;
   320      Trace.prototype = Trace_prototype;
   316 
   321 
   317      var Obsel_prototype = {
   322      var Obsel_prototype = {
   318          /* The following attributes are here for documentation
   323          /* The following attributes are here for documentation
   319           * purposes. They MUST be defined in the constructor
   324 * purposes. They MUST be defined in the constructor
   320           * function. */
   325 * function. */
   321          trace: undefined,
   326          trace: undefined,
   322          type: undefined,
   327          type: undefined,
   323          begin: undefined,
   328          begin: undefined,
   324          end: undefined,
   329          end: undefined,
   325          subject: undefined,
   330          subject: undefined,
   345          },
   350          },
   346 
   351 
   347          list_attribute_types: function() {
   352          list_attribute_types: function() {
   348              var result = [];
   353              var result = [];
   349              for (var prop in this.attributes) {
   354              for (var prop in this.attributes) {
   350                  if (this.hasOwnProperty(prop))
   355                  if (this.attributes.hasOwnProperty(prop))
   351                      result.push(prop);
   356                      result.push(prop);
   352              }
   357              }
   353              /* FIXME: we return URIs here instead of AttributeType elements */
   358              /* FIXME: we return URIs here instead of AttributeType elements */
   354              return result;
   359              return result;
   355          },
   360          },
   366          },
   371          },
   367          list_relating_obsels: function (rt) {
   372          list_relating_obsels: function (rt) {
   368              /* FIXME: not implemented yet */
   373              /* FIXME: not implemented yet */
   369          },
   374          },
   370          /*
   375          /*
   371           * Return the value of the given attribute type for this obsel
   376 * Return the value of the given attribute type for this obsel
   372           */
   377 */
   373          get_attribute_value: function(at) {
   378          get_attribute_value: function(at) {
   374              if (typeof at === "string")
   379              if (typeof at === "string")
   375                  /* It is a URI */
   380                  /* It is a URI */
   376                  return this.attributes[at];
   381                  return this.attributes[at];
   377              else
   382              else
   407          del_related_obsel: function(rt, value) {
   412          del_related_obsel: function(rt, value) {
   408              /* FIXME: not implemented yet */
   413              /* FIXME: not implemented yet */
   409          },
   414          },
   410 
   415 
   411          /*
   416          /*
   412           * Return a JSON representation of the obsel
   417 * Return a JSON representation of the obsel
   413           */
   418 */
   414          toJSON: function() {
   419          toJSON: function() {
   415              var r = {
   420              var r = {
   416                  "@id": this.id,
   421                  "@id": this.id,
   417                  "@type": this.type,
   422                  "@type": this.type,
   418                  "begin": this.begin,
   423                  "begin": this.begin,
   419                  "end": this.end,
   424                  "end": this.end,
   420                  "subject": this.subject
   425                  "subject": this.subject
   421              };
   426              };
   422              for (var prop in this.attributes) {
   427              for (var prop in this.attributes) {
   423                  if (this.hasOwnProperty(prop))
   428                  if (this.attributes.hasOwnProperty(prop))
   424                      r[prop] = this.attributes[prop];
   429                      r[prop] = this.attributes[prop];
   425              }
   430              }
   426              return r;
   431              return r;
   427          },
   432          },
   428 
   433 
   429          /*
   434          /*
   430           * Return a compact JSON representation of the obsel.
   435 * Return a compact JSON representation of the obsel.
   431           * Use predefined + custom shorthands for types/properties
   436 * Use predefined + custom shorthands for types/properties
   432           */
   437 */
   433          toCompactJSON: function() {
   438          toCompactJSON: function() {
   434              var r = {
   439              var r = {
   435                  "@i": this.id,
       
   436                  "@t": (this.trace.shorthands.hasOwnProperty(this.type) ? this.trace.shorthands[this.type] : this.type),
   440                  "@t": (this.trace.shorthands.hasOwnProperty(this.type) ? this.trace.shorthands[this.type] : this.type),
   437                  "@b": this.begin,
   441                  "@b": this.begin,
   438                  "@s": this.subject
       
   439              };
   442              };
       
   443              // Transmit subject only if different from default_subject
       
   444              if (this.subject !== this.trace.default_subject)
       
   445                  r["@s"] = this.subject;
       
   446 
   440              // Store duration (to save some bytes) and only if it is non-null
   447              // Store duration (to save some bytes) and only if it is non-null
   441              if (this.begin !== this.end)
   448              if (this.begin !== this.end)
   442                  r["@d"] = this.end - this.begin;
   449                  r["@d"] = this.end - this.begin;
   443 
   450 
       
   451              // Store id only if != ""
       
   452              if (this.id !== "")
       
   453                  r["@i"] = this.id;
       
   454 
   444              for (var prop in this.attributes) {
   455              for (var prop in this.attributes) {
   445                  if (this.hasOwnProperty(prop))
   456                  if (this.attributes.hasOwnProperty(prop))
   446                  {
   457                  {
   447                      var v = this.attributes[prop];
   458                      var v = this.attributes[prop];
   448                      r[prop] = this.trace.shorthands.hasOwnProperty(v) ? this.trace.shorthands[v] : v;
   459                      r[prop] = this.trace.shorthands.hasOwnProperty(v) ? this.trace.shorthands[v] : v;
   449                  }
   460                  }
   450              }
   461              }
   472      Obsel.prototype = Obsel_prototype;
   483      Obsel.prototype = Obsel_prototype;
   473 
   484 
   474      var TraceManager_prototype = {
   485      var TraceManager_prototype = {
   475          traces: [],
   486          traces: [],
   476          /*
   487          /*
   477           * Return the trace with id name
   488 * Return the trace with id name
   478           * If it was not registered, return undefined.
   489 * If it was not registered, return undefined.
   479           */
   490 */
   480          get_trace: function(name) {
   491          get_trace: function(name) {
   481              return this.traces[name];
   492              return this.traces[name];
   482          },
   493          },
   483 
   494 
   484          /*
   495          /*
   485           * Explicitly create and initialize a new trace with the given name.
   496 * Explicitly create and initialize a new trace with the given name.
   486           * The optional uri parameter allows to initialize the trace URI.
   497 * The optional uri parameter allows to initialize the trace URI.
   487           *
   498 *
   488           * If another existed with the same name before, then it is replaced by a new one.
   499 * If another existed with the same name before, then it is replaced by a new one.
   489           */
   500 */
   490          init_trace: function(name, params)
   501          init_trace: function(name, params)
   491          {
   502          {
   492              if (window.console) window.console.log("init_trace", params);
   503              if (window.console) window.console.log("init_trace", params);
   493              url = params.url ? params.url : "";
   504              url = params.url ? params.url : "";
   494              requestmode = params.requestmode ? params.requestmode : "POST";
   505              requestmode = params.requestmode ? params.requestmode : "POST";
   495              syncmode = params.syncmode ? params.syncmode : "none";
   506              syncmode = params.syncmode ? params.syncmode : "none";
   496              default_subject = params.default_subject ? params.default_subject : "default";
   507              default_subject = params.default_subject ? params.default_subject : "default";
   497              var t = new Trace(url, requestmode);
   508              var t = new Trace(url, requestmode);
       
   509              t.set_default_subject(default_subject);
   498              t.set_sync_mode(syncmode);
   510              t.set_sync_mode(syncmode);
   499              t.set_default_subject(default_subject);
       
   500              this.traces[name] = t;
   511              this.traces[name] = t;
   501              return t;
   512              return t;
   502          }
   513          }
   503      };
   514      };
   504 
   515 
   505      var TraceManager = function() {
   516      var TraceManager = function() {
   506          this.traces = {};
   517          this.traces = {};
   507      };
   518      };
   508      TraceManager.prototype = TraceManager_prototype;
   519      TraceManager.prototype = TraceManager_prototype;
   509 
   520 
   510      var tracemanager  = new TraceManager();
   521      var tracemanager = new TraceManager();
   511      return tracemanager;
   522      return tracemanager;
   512  };
   523  };