HTRACE-75: htraced web UI should query htraced (abe via cmccabe)
diff --git a/htrace-core/src/go/src/org/apache/htrace/htrace/cmd.go b/htrace-core/src/go/src/org/apache/htrace/htrace/cmd.go
index f1e765f..7007343 100644
--- a/htrace-core/src/go/src/org/apache/htrace/htrace/cmd.go
+++ b/htrace-core/src/go/src/org/apache/htrace/htrace/cmd.go
@@ -163,7 +163,7 @@
 			if err == io.EOF {
 				break
 			}
-			fmt.Println("Failed to decode JSON: %s", err.Error())
+			fmt.Printf("Failed to decode JSON: %s\n", err.Error())
 			return EXIT_FAILURE
 		}
 		if *verbose {
diff --git a/htrace-core/src/web/app/models/span.js b/htrace-core/src/web/app/models/span.js
index 2283adb..e292970 100644
--- a/htrace-core/src/web/app/models/span.js
+++ b/htrace-core/src/web/app/models/span.js
@@ -21,8 +21,9 @@
 App.Span = Backbone.Model.extend({
   "defaults": {
     "spanId": null,
-    "parents": null,
+    "traceId": null,
     "processId": null,
+    "parents": null,
     "description": null,
     "beginTime": 0,
     "stopTime": 0
@@ -34,13 +35,15 @@
     "e": "stopTime",
     "d": "description",
     "r": "processId",
-    "p": "parents"
+    "p": "parents",
+    "i": "traceId"
   },
 
   parse: function(response, options) {
     var attrs = {};
+    var $this = this;
     $.each(response, function(key, value) {
-      attrs[(key in this.shorthand) ? this.shorthand[key] : key] = value;
+      attrs[(key in $this.shorthand) ? $this.shorthand[key] : key] = value;
     });
     return attrs;
   },
@@ -51,5 +54,32 @@
 });
 
 App.Spans = Backbone.Collection.extend({
-  model: App.Span
+  model: App.Span,
+  url: "/query",
+
+  initialize: function(models, options) {
+    this.predicates = [];
+    return Backbone.Collection.prototype.initialize.apply(this, arguments);
+  },
+
+  fetch: function(options) {
+    options = options ? _.clone(options) : {};
+    options.data = {
+      "query": {
+        "lim": 100000
+      }
+    };
+
+    if (this.predicates.length > 0) {
+      options.data.query.pred = this.predicates;
+    }
+
+    options.data.query = JSON.stringify(options.data.query);
+
+    return Backbone.Collection.prototype.fetch.apply(this, [options]);
+  },
+
+  setPredicates: function(predicates) {
+    this.predicates = predicates;
+  }
 });
diff --git a/htrace-core/src/web/app/setup.js b/htrace-core/src/web/app/setup.js
index fd27c2f..bb41ad8 100644
--- a/htrace-core/src/web/app/setup.js
+++ b/htrace-core/src/web/app/setup.js
@@ -25,7 +25,9 @@
   },
 
   initialize: function() {
-    this.spansCollection = spans.clone();
+    this.spansCollection = new App.Spans();
+    this.spansCollection.fetch();
+
     this.spanViews = {};
 
     this.listSpansView = new App.ListSpansView({
@@ -49,10 +51,17 @@
 
     // Cache views to avoid leaks
     if (!(span in this.spanViews)) {
+      var model = this.spansCollection.findWhere({
+        "spanId": span
+      });
+
+      if (!model) {
+        urlconf.navigate("/", true);
+        return;
+      }
+
       this.spanViews[span] = new App.SpanView({
-        "model": this.spansCollection.findWhere({
-          "spanId": parseInt(span)
-        }),
+        "model": model,
         "id": "span-details"
       });
     }
diff --git a/htrace-core/src/web/app/views/search.js b/htrace-core/src/web/app/views/search.js
index c948eaa..bcdd980 100644
--- a/htrace-core/src/web/app/views/search.js
+++ b/htrace-core/src/web/app/views/search.js
@@ -28,48 +28,58 @@
     var begin, stop;
 
     var description = $(this.el).find("input[type='search']").val();
-    var startdate = $(this.el).find("#begindate").val();// || now.format("D MMMM, YYYY");
-    var starttime = $(this.el).find("#begintime").val() || now.format("H:mm A");
+    var begindate = $(this.el).find("#begindate").val();// || now.format("D MMMM, YYYY");
+    var begintime = $(this.el).find("#begintime").val() || now.format("H:mm A");
     var enddate = $(this.el).find("#stopdate").val();// || now.format("D MMMM, YYYY");
     var endtime = $(this.el).find("#stoptime").val() || now.format("H:mm A");
     var duration = $(this.el).find("#duration").val();
 
     var newSpans = spans.clone();
 
-    if (startdate) {
-      begin = new moment(startdate + " " + starttime).unix();
+    if (begindate) {
+      begin = new moment(begindate + " " + begintime).unix();
     }
 
     if (enddate) {
       stop = new moment(enddate + " " + endtime).unix();
     }
 
+    var predicates = [];
+
     if (begin) {
-      newSpans = newSpans.filter(function(span) {
-        return span.get("beginTime") > parseInt(begin);
+      predicates.push({
+        "op": "ge",
+        "field": "begin",
+        "val": begin.toString()
       });
     }
 
     if (stop) {
-      newSpans = newSpans.filter(function(span) {
-        return span.get("stopTime") < parseInt(stop);
+      predicates.push({
+        "op": "le",
+        "field": "end",
+        "val": stop.toString()
       });
     }
 
     if (duration) {
-      newSpans = newSpans.filter(function(span) {
-        return span.duration() > parseInt(duration);
+      predicates.push({
+        "op": "ge",
+        "field": "duration",
+        "val": duration.toString()
       });
     }
 
-    newSpans = newSpans.filter(function(span) {
-      return span.get("description").toLowerCase().indexOf(description) != -1;
-    });
+    if (description) {
+      predicates.push({
+        "op": "cn",
+        "field": "description",
+        "val": description
+      });
+    }
 
-    // TODO: this.collection.fetch
-    this.collection.reset(newSpans);
-
-    this.collection.trigger('change');
+    this.collection.setPredicates(predicates);
+    this.collection.fetch();
 
     return false;
   }
diff --git a/htrace-core/src/web/app/views/span.js b/htrace-core/src/web/app/views/span.js
index 121036c..dd50bc6 100644
--- a/htrace-core/src/web/app/views/span.js
+++ b/htrace-core/src/web/app/views/span.js
@@ -51,9 +51,6 @@
   "tagName": "div",
 
   "initialize": function() {
-    _.bindAll(this, "render");
-    this.collection.bind('change', this.render);
-
     this.rendered = false;
 
     this.listSpansView = new Backgrid.Grid({
diff --git a/htrace-core/src/web/index.html b/htrace-core/src/web/index.html
index d8ac906..181762f 100644
--- a/htrace-core/src/web/index.html
+++ b/htrace-core/src/web/index.html
@@ -24,7 +24,7 @@
     
     <!-- TODO: Add Favicon -->
     <link rel="icon" href="//favicon.ico" type="image/x-icon" sizes="16x16">
-    <link href="lib/bootstrap-3.3.1/css/bootstrap.min.css" rel="stylesheet">
+    <link href="lib/bootstrap-3.3.1/css/bootstrap.css" rel="stylesheet">
     <link href="lib/css/backgrid.min.css" rel="stylesheet">
     <link href="lib/pickadate-3.5.2/themes/classic.css" rel="stylesheet">
     <link href="lib/pickadate-3.5.2/themes/classic.date.css" rel="stylesheet">