incubator-blur-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From amccu...@apache.org
Subject [34/51] [partial] Fixed BLUR-126.
Date Thu, 06 Jun 2013 18:58:06 GMT
http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-gui/src/main/webapp/js/thrift.js
----------------------------------------------------------------------
diff --git a/blur-gui/src/main/webapp/js/thrift.js b/blur-gui/src/main/webapp/js/thrift.js
new file mode 100644
index 0000000..e8436b9
--- /dev/null
+++ b/blur-gui/src/main/webapp/js/thrift.js
@@ -0,0 +1,775 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var Thrift = {
+    Version: '0.9.0',
+/*
+    Description: 'JavaScript bindings for the Apache Thrift RPC system',
+    License: 'http://www.apache.org/licenses/LICENSE-2.0',
+    Homepage: 'http://thrift.apache.org',
+    BugReports: 'https://issues.apache.org/jira/browse/THRIFT',
+    Maintainer: 'dev@thrift.apache.org',
+*/
+
+    Type: {
+        'STOP' : 0,
+        'VOID' : 1,
+        'BOOL' : 2,
+        'BYTE' : 3,
+        'I08' : 3,
+        'DOUBLE' : 4,
+        'I16' : 6,
+        'I32' : 8,
+        'I64' : 10,
+        'STRING' : 11,
+        'UTF7' : 11,
+        'STRUCT' : 12,
+        'MAP' : 13,
+        'SET' : 14,
+        'LIST' : 15,
+        'UTF8' : 16,
+        'UTF16' : 17
+    },
+
+    MessageType: {
+        'CALL' : 1,
+        'REPLY' : 2,
+        'EXCEPTION' : 3
+    },
+
+    objectLength: function(obj) {
+        var length = 0;
+        for (var k in obj) {
+            if (obj.hasOwnProperty(k)) {
+                length++;
+            }
+        }
+
+        return length;
+    },
+
+    inherits: function(constructor, superConstructor) {
+      //Prototypal Inheritance http://javascript.crockford.com/prototypal.html
+      function F() {}
+      F.prototype = superConstructor.prototype;
+      constructor.prototype = new F();
+    }
+};
+
+
+
+Thrift.TException = function(message) {
+    this.message = message;
+};
+Thrift.inherits(Thrift.TException, Error);
+Thrift.TException.prototype.name = 'TException';
+
+Thrift.TApplicationExceptionType = {
+    'UNKNOWN' : 0,
+    'UNKNOWN_METHOD' : 1,
+    'INVALID_MESSAGE_TYPE' : 2,
+    'WRONG_METHOD_NAME' : 3,
+    'BAD_SEQUENCE_ID' : 4,
+    'MISSING_RESULT' : 5,
+    'INTERNAL_ERROR' : 6,
+    'PROTOCOL_ERROR' : 7
+};
+
+Thrift.TApplicationException = function(message, code) {
+    this.message = message;
+    this.code = (code === null) ? 0 : code;
+};
+Thrift.inherits(Thrift.TApplicationException, Thrift.TException);
+Thrift.TApplicationException.prototype.name = 'TApplicationException';
+
+Thrift.TApplicationException.prototype.read = function(input) {
+    while (1) {
+        var ret = input.readFieldBegin();
+
+        if (ret.ftype == Thrift.Type.STOP) {
+            break;
+        }
+
+        var fid = ret.fid;
+
+        switch (fid) {
+            case 1:
+                if (ret.ftype == Thrift.Type.STRING) {
+                    ret = input.readString();
+                    this.message = ret.value;
+                } else {
+                    ret = input.skip(ret.ftype);
+                }
+                break;
+            case 2:
+                if (ret.ftype == Thrift.Type.I32) {
+                    ret = input.readI32();
+                    this.code = ret.value;
+                } else {
+                    ret = input.skip(ret.ftype);
+                }
+                break;
+           default:
+                ret = input.skip(ret.ftype);
+                break;
+        }
+
+        input.readFieldEnd();
+    }
+
+    input.readStructEnd();
+};
+
+Thrift.TApplicationException.prototype.write = function(output) {
+    var xfer = 0;
+
+    output.writeStructBegin('TApplicationException');
+
+    if (this.message) {
+        output.writeFieldBegin('message', Thrift.Type.STRING, 1);
+        output.writeString(this.getMessage());
+        output.writeFieldEnd();
+    }
+
+    if (this.code) {
+        output.writeFieldBegin('type', Thrift.Type.I32, 2);
+        output.writeI32(this.code);
+        output.writeFieldEnd();
+    }
+
+    output.writeFieldStop();
+    output.writeStructEnd();
+};
+
+Thrift.TApplicationException.prototype.getCode = function() {
+    return this.code;
+};
+
+Thrift.TApplicationException.prototype.getMessage = function() {
+    return this.message;
+};
+
+/**
+ *If you do not specify a url then you must handle ajax on your own.
+ *This is how to use js bindings in a async fashion.
+ */
+Thrift.Transport = function(url) {
+    this.url = url;
+    this.wpos = 0;
+    this.rpos = 0;
+
+    this.send_buf = '';
+    this.recv_buf = '';
+};
+
+Thrift.Transport.prototype = {
+
+    //Gets the browser specific XmlHttpRequest Object
+    getXmlHttpRequestObject: function() {
+        try { return new XMLHttpRequest(); } catch (e1) { }
+        try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { }
+        try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { }
+
+        throw "Your browser doesn't support the XmlHttpRequest object.";
+    },
+
+    flush: function(async) {
+        //async mode
+        if (async || this.url === undefined || this.url === '') {
+            return this.send_buf;
+        }
+
+        var xreq = this.getXmlHttpRequestObject();
+
+        if (xreq.overrideMimeType) {
+            xreq.overrideMimeType('application/json');
+        }
+
+        xreq.open('POST', this.url, false);
+        xreq.send(this.send_buf);
+
+        if (xreq.readyState != 4) {
+            throw 'encountered an unknown ajax ready state: ' + xreq.readyState;
+        }
+
+        if (xreq.status != 200) {
+            throw 'encountered a unknown request status: ' + xreq.status;
+        }
+
+        this.recv_buf = xreq.responseText;
+        this.recv_buf_sz = this.recv_buf.length;
+        this.wpos = this.recv_buf.length;
+        this.rpos = 0;
+    },
+
+    jqRequest: function(client, postData, args, recv_method) {
+        if (typeof jQuery === 'undefined' ||
+            typeof jQuery.Deferred === 'undefined') {
+            throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests';
+        }
+
+        var thriftTransport = this;
+
+        var jqXHR = jQuery.ajax({
+            url: this.url,
+            data: postData,
+            type: 'POST',
+            cache: false,
+            dataType: 'text thrift',
+            converters: {
+                'text thrift' : function(responseData) {
+                    thriftTransport.setRecvBuffer(responseData);
+                    var value = recv_method.call(client);
+                    return value;
+                }
+            },
+            context: client,
+            success: jQuery.makeArray(args).pop()
+        });
+
+        return jqXHR;
+    },
+
+    setRecvBuffer: function(buf) {
+        this.recv_buf = buf;
+        this.recv_buf_sz = this.recv_buf.length;
+        this.wpos = this.recv_buf.length;
+        this.rpos = 0;
+    },
+
+    isOpen: function() {
+        return true;
+    },
+
+    open: function() {},
+
+    close: function() {},
+
+    read: function(len) {
+        var avail = this.wpos - this.rpos;
+
+        if (avail === 0) {
+            return '';
+        }
+
+        var give = len;
+
+        if (avail < len) {
+            give = avail;
+        }
+
+        var ret = this.read_buf.substr(this.rpos, give);
+        this.rpos += give;
+
+        //clear buf when complete?
+        return ret;
+    },
+
+    readAll: function() {
+        return this.recv_buf;
+    },
+
+    write: function(buf) {
+        this.send_buf = buf;
+    },
+
+    getSendBuffer: function() {
+        return this.send_buf;
+    }
+
+};
+
+
+
+Thrift.Protocol = function(transport) {
+    this.transport = transport;
+};
+
+Thrift.Protocol.Type = {};
+Thrift.Protocol.Type[Thrift.Type.BOOL] = '"tf"';
+Thrift.Protocol.Type[Thrift.Type.BYTE] = '"i8"';
+Thrift.Protocol.Type[Thrift.Type.I16] = '"i16"';
+Thrift.Protocol.Type[Thrift.Type.I32] = '"i32"';
+Thrift.Protocol.Type[Thrift.Type.I64] = '"i64"';
+Thrift.Protocol.Type[Thrift.Type.DOUBLE] = '"dbl"';
+Thrift.Protocol.Type[Thrift.Type.STRUCT] = '"rec"';
+Thrift.Protocol.Type[Thrift.Type.STRING] = '"str"';
+Thrift.Protocol.Type[Thrift.Type.MAP] = '"map"';
+Thrift.Protocol.Type[Thrift.Type.LIST] = '"lst"';
+Thrift.Protocol.Type[Thrift.Type.SET] = '"set"';
+
+
+Thrift.Protocol.RType = {};
+Thrift.Protocol.RType.tf = Thrift.Type.BOOL;
+Thrift.Protocol.RType.i8 = Thrift.Type.BYTE;
+Thrift.Protocol.RType.i16 = Thrift.Type.I16;
+Thrift.Protocol.RType.i32 = Thrift.Type.I32;
+Thrift.Protocol.RType.i64 = Thrift.Type.I64;
+Thrift.Protocol.RType.dbl = Thrift.Type.DOUBLE;
+Thrift.Protocol.RType.rec = Thrift.Type.STRUCT;
+Thrift.Protocol.RType.str = Thrift.Type.STRING;
+Thrift.Protocol.RType.map = Thrift.Type.MAP;
+Thrift.Protocol.RType.lst = Thrift.Type.LIST;
+Thrift.Protocol.RType.set = Thrift.Type.SET;
+
+Thrift.Protocol.Version = 1;
+
+Thrift.Protocol.prototype = {
+
+    getTransport: function() {
+        return this.transport;
+    },
+
+    //Write functions
+    writeMessageBegin: function(name, messageType, seqid) {
+        this.tstack = [];
+        this.tpos = [];
+
+        this.tstack.push([Thrift.Protocol.Version, '"' +
+            name + '"', messageType, seqid]);
+    },
+
+    writeMessageEnd: function() {
+        var obj = this.tstack.pop();
+
+        this.wobj = this.tstack.pop();
+        this.wobj.push(obj);
+
+        this.wbuf = '[' + this.wobj.join(',') + ']';
+
+        this.transport.write(this.wbuf);
+     },
+
+
+    writeStructBegin: function(name) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push({});
+    },
+
+    writeStructEnd: function() {
+
+        var p = this.tpos.pop();
+        var struct = this.tstack[p];
+        var str = '{';
+        var first = true;
+        for (var key in struct) {
+            if (first) {
+                first = false;
+            } else {
+                str += ',';
+            }
+
+            str += key + ':' + struct[key];
+        }
+
+        str += '}';
+        this.tstack[p] = str;
+    },
+
+    writeFieldBegin: function(name, fieldType, fieldId) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push({ 'fieldId': '"' +
+            fieldId + '"', 'fieldType': Thrift.Protocol.Type[fieldType]
+        });
+
+    },
+
+    writeFieldEnd: function() {
+        var value = this.tstack.pop();
+        var fieldInfo = this.tstack.pop();
+
+        this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' +
+            fieldInfo.fieldType + ':' + value + '}';
+        this.tpos.pop();
+    },
+
+    writeFieldStop: function() {
+        //na
+    },
+
+    writeMapBegin: function(keyType, valType, size) {
+        //size is invalid, we'll set it on end.
+        this.tpos.push(this.tstack.length);
+        this.tstack.push([Thrift.Protocol.Type[keyType],
+            Thrift.Protocol.Type[valType], 0]);
+    },
+
+    writeMapEnd: function() {
+        var p = this.tpos.pop();
+
+        if (p == this.tstack.length) {
+            return;
+        }
+
+        if ((this.tstack.length - p - 1) % 2 !== 0) {
+            this.tstack.push('');
+        }
+
+        var size = (this.tstack.length - p - 1) / 2;
+
+        this.tstack[p][this.tstack[p].length - 1] = size;
+
+        var map = '}';
+        var first = true;
+        while (this.tstack.length > p + 1) {
+            var v = this.tstack.pop();
+            var k = this.tstack.pop();
+            if (first) {
+                first = false;
+            } else {
+                map = ',' + map;
+            }
+
+            if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings
+            map = k + ':' + v + map;
+        }
+        map = '{' + map;
+
+        this.tstack[p].push(map);
+        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+    },
+
+    writeListBegin: function(elemType, size) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push([Thrift.Protocol.Type[elemType], size]);
+    },
+
+    writeListEnd: function() {
+        var p = this.tpos.pop();
+
+        while (this.tstack.length > p + 1) {
+            var tmpVal = this.tstack[p + 1];
+            this.tstack.splice(p + 1, 1);
+            this.tstack[p].push(tmpVal);
+        }
+
+        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+    },
+
+    writeSetBegin: function(elemType, size) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push([Thrift.Protocol.Type[elemType], size]);
+    },
+
+    writeSetEnd: function() {
+        var p = this.tpos.pop();
+
+        while (this.tstack.length > p + 1) {
+            var tmpVal = this.tstack[p + 1];
+            this.tstack.splice(p + 1, 1);
+            this.tstack[p].push(tmpVal);
+        }
+
+        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+    },
+
+    writeBool: function(value) {
+        this.tstack.push(value ? 1 : 0);
+    },
+
+    writeByte: function(i8) {
+        this.tstack.push(i8);
+    },
+
+    writeI16: function(i16) {
+        this.tstack.push(i16);
+    },
+
+    writeI32: function(i32) {
+        this.tstack.push(i32);
+    },
+
+    writeI64: function(i64) {
+        this.tstack.push(i64);
+    },
+
+    writeDouble: function(dbl) {
+        this.tstack.push(dbl);
+    },
+
+    writeString: function(str) {
+        // We do not encode uri components for wire transfer:
+        if (str === null) {
+            this.tstack.push(null);
+        } else {
+            // concat may be slower than building a byte buffer
+            var escapedString = '';
+            for (var i = 0; i < str.length; i++) {
+                var ch = str.charAt(i);      // a single double quote: "
+                if (ch === '\"') {
+                    escapedString += '\\\"'; // write out as: \"
+                } else if (ch === '\\') {    // a single backslash: \
+                    escapedString += '\\\\'; // write out as: \\
+                /* Currently escaped forward slashes break TJSONProtocol.
+                 * As it stands, we can simply pass forward slashes into
+                 * our strings across the wire without being escaped.
+                 * I think this is the protocol's bug, not thrift.js
+                 * } else if(ch === '/') {   // a single forward slash: /
+                 *  escapedString += '\\/';  // write out as \/
+                 * }
+                 */
+                } else if (ch === '\b') {    // a single backspace: invisible
+                    escapedString += '\\b';  // write out as: \b"
+                } else if (ch === '\f') {    // a single formfeed: invisible
+                    escapedString += '\\f';  // write out as: \f"
+                } else if (ch === '\n') {    // a single newline: invisible
+                    escapedString += '\\n';  // write out as: \n"
+                } else if (ch === '\r') {    // a single return: invisible
+                    escapedString += '\\r';  // write out as: \r"
+                } else if (ch === '\t') {    // a single tab: invisible
+                    escapedString += '\\t';  // write out as: \t"
+                } else {
+                    escapedString += ch;     // Else it need not be escaped
+                }
+            }
+            this.tstack.push('"' + escapedString + '"');
+        }
+    },
+
+    writeBinary: function(str) {
+        this.writeString(str);
+    },
+
+
+
+    // Reading functions
+    readMessageBegin: function(name, messageType, seqid) {
+        this.rstack = [];
+        this.rpos = [];
+
+        if (typeof jQuery !== 'undefined') {
+            this.robj = jQuery.parseJSON(this.transport.readAll());
+        } else {
+            this.robj = eval(this.transport.readAll());
+        }
+
+        var r = {};
+        var version = this.robj.shift();
+
+        if (version != Thrift.Protocol.Version) {
+            throw 'Wrong thrift protocol version: ' + version;
+        }
+
+        r.fname = this.robj.shift();
+        r.mtype = this.robj.shift();
+        r.rseqid = this.robj.shift();
+
+
+        //get to the main obj
+        this.rstack.push(this.robj.shift());
+
+        return r;
+    },
+
+    readMessageEnd: function() {
+    },
+
+    readStructBegin: function(name) {
+        var r = {};
+        r.fname = '';
+
+        //incase this is an array of structs
+        if (this.rstack[this.rstack.length - 1] instanceof Array) {
+            this.rstack.push(this.rstack[this.rstack.length - 1].shift());
+        }
+
+        return r;
+    },
+
+    readStructEnd: function() {
+        if (this.rstack[this.rstack.length - 2] instanceof Array) {
+            this.rstack.pop();
+        }
+    },
+
+    readFieldBegin: function() {
+        var r = {};
+
+        var fid = -1;
+        var ftype = Thrift.Type.STOP;
+
+        //get a fieldId
+        for (var f in (this.rstack[this.rstack.length - 1])) {
+            if (f === null) {
+              continue;
+            }
+
+            fid = parseInt(f, 10);
+            this.rpos.push(this.rstack.length);
+
+            var field = this.rstack[this.rstack.length - 1][fid];
+
+            //remove so we don't see it again
+            delete this.rstack[this.rstack.length - 1][fid];
+
+            this.rstack.push(field);
+
+            break;
+        }
+
+        if (fid != -1) {
+
+            //should only be 1 of these but this is the only
+            //way to match a key
+            for (var i in (this.rstack[this.rstack.length - 1])) {
+                if (Thrift.Protocol.RType[i] === null) {
+                    continue;
+                }
+
+                ftype = Thrift.Protocol.RType[i];
+                this.rstack[this.rstack.length - 1] =
+                    this.rstack[this.rstack.length - 1][i];
+            }
+        }
+
+        r.fname = '';
+        r.ftype = ftype;
+        r.fid = fid;
+
+        return r;
+    },
+
+    readFieldEnd: function() {
+        var pos = this.rpos.pop();
+
+        //get back to the right place in the stack
+        while (this.rstack.length > pos) {
+            this.rstack.pop();
+        }
+
+    },
+
+    readMapBegin: function(keyType, valType, size) {
+        var map = this.rstack.pop();
+
+        var r = {};
+        r.ktype = Thrift.Protocol.RType[map.shift()];
+        r.vtype = Thrift.Protocol.RType[map.shift()];
+        r.size = map.shift();
+
+
+        this.rpos.push(this.rstack.length);
+        this.rstack.push(map.shift());
+
+        return r;
+    },
+
+    readMapEnd: function() {
+        this.readFieldEnd();
+    },
+
+    readListBegin: function(elemType, size) {
+        var list = this.rstack[this.rstack.length - 1];
+
+        var r = {};
+        r.etype = Thrift.Protocol.RType[list.shift()];
+        r.size = list.shift();
+
+        this.rpos.push(this.rstack.length);
+        this.rstack.push(list);
+
+        return r;
+    },
+
+    readListEnd: function() {
+        this.readFieldEnd();
+    },
+
+    readSetBegin: function(elemType, size) {
+        return this.readListBegin(elemType, size);
+    },
+
+    readSetEnd: function() {
+        return this.readListEnd();
+    },
+
+    readBool: function() {
+        var r = this.readI32();
+
+        if (r !== null && r.value == '1') {
+            r.value = true;
+        } else {
+            r.value = false;
+        }
+
+        return r;
+    },
+
+    readByte: function() {
+        return this.readI32();
+    },
+
+    readI16: function() {
+        return this.readI32();
+    },
+
+    readI32: function(f) {
+        if (f === undefined) {
+            f = this.rstack[this.rstack.length - 1];
+        }
+
+        var r = {};
+
+        if (f instanceof Array) {
+            if (f.length === 0) {
+                r.value = undefined;
+            } else {
+                r.value = f.shift();
+            }
+        } else if (f instanceof Object) {
+           for (var i in f) {
+                if (i === null) {
+                  continue;
+                }
+                this.rstack.push(f[i]);
+                delete f[i];
+
+                r.value = i;
+                break;
+           }
+        } else {
+            r.value = f;
+            this.rstack.pop();
+        }
+
+        return r;
+    },
+
+    readI64: function() {
+        return this.readI32();
+    },
+
+    readDouble: function() {
+        return this.readI32();
+    },
+
+    readString: function() {
+        var r = this.readI32();
+        return r;
+    },
+
+    readBinary: function() {
+        return this.readString();
+    },
+
+
+    //Method to arbitrarily skip over data.
+    skip: function(type) {
+        throw 'skip not supported yet';
+    }
+};

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-gui/src/main/webapp/livemetrics.jsp
----------------------------------------------------------------------
diff --git a/blur-gui/src/main/webapp/livemetrics.jsp b/blur-gui/src/main/webapp/livemetrics.jsp
new file mode 100644
index 0000000..6c5d11e
--- /dev/null
+++ b/blur-gui/src/main/webapp/livemetrics.jsp
@@ -0,0 +1,129 @@
+<%
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file 
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+%>
+<%@page import="java.text.DecimalFormat"%>
+<%@page import="java.text.NumberFormat"%>
+<%@ page contentType="text/html; charset=UTF-8" isThreadSafe="false"
+	import="javax.servlet.*" import="javax.servlet.http.*"
+	import="java.io.*" import="java.util.*" import="java.text.DateFormat"
+	import="java.lang.Math" import="java.net.URLEncoder"
+	import="org.apache.blur.thrift.*"
+	import="org.apache.blur.thrift.generated.*"
+	import="org.apache.blur.thrift.generated.Blur.*"%>
+<%@ include file="functions.jsp"%>
+<%
+	String hostName = request.getServerName() + ":" + System.getProperty("blur.gui.servicing.port");
+%>
+<html>
+<head>
+<title>Metrics</title>
+<link href="style.css" rel="stylesheet" type="text/css" />
+</head>
+<script src="d3.v2.js"></script>
+<body>
+
+<script>
+function draw(uri, id, data, margin, width, height, xLabel, yLabel, labels) {
+  "use strict";
+  var graphSvg = d3.select("#" + id).select("svg");
+  if (graphSvg) {graphSvg.remove();}
+  var graph = d3.select("#" + id).append("svg").attr("width", width).attr("height", height);
+
+  var time_extent = d3.extent(data,function(d){return new Date(d.recordTime)});
+  var time_scale = d3.time.scale().domain(time_extent).range([margin, width]);
+
+  var maxArray = [];
+  for (var index in labels) {
+    var labelObject = labels[index];
+	maxArray.push(d3.max(data,function(d){return d[labelObject.name];}));
+  }
+  var y_scale = d3.scale.linear().range([height-margin,margin]).domain([0, d3.max(maxArray)]);
+
+  //add x axis
+  var x_axis = d3.svg.axis().scale(time_scale);
+  graph.append("g").attr("class","x axis " + id).attr("transform","translate(0,"+(height-margin)+")").call(x_axis);
+  d3.select(".x.axis."+id).append("text").text(xLabel).attr("x", (width / 2) - margin).attr("y", margin / 1.5);
+
+  //add y axis
+  var y_axis = d3.svg.axis().scale(y_scale).orient("left");
+  graph.append("g").attr("class","y axis " + id).attr("transform","translate(" + margin +",0)").call(y_axis);
+  d3.select(".y.axis."+id).append("text").text(yLabel).attr("transform", "rotate (-90, 0, 0) translate(-" + (height/2) + ",-40)");
+
+  //add lines
+  for (var index in labels) {
+    var labelObject = labels[index];
+    var name = labelObject.name;
+    var line = d3.svg.line().x(function(d){return time_scale(new Date(d.recordTime))}).y(function(d){return y_scale(d[name])}).interpolate("basis");
+    var l = graph.append("path").attr("d", line(data)).attr("class", name + "_line");
+    var s = labelObject.style;
+	for (var v in s) {
+      if (s.hasOwnProperty(v)) {
+	    l.style(s,v[s]);
+	  }
+	}
+  }
+}
+
+function drawGraphs(uri, margin, width, height) {
+  d3.json(uri,function(data) {
+	for (var graphId in data) {
+      if (data.hasOwnProperty(graphId)) {
+        draw(uri, graphId, data[graphId].lines.data, margin, width, height, data[graphId].xLabel, data[graphId].yLabel, data[graphId].lines.labels);
+      }
+	}
+  });
+  setTimeout(function() {
+	drawGraphs(uri, margin, width, height);
+  }, 1000);	
+}
+
+var margin = 50, width = 450, height = 220;
+
+drawGraphs("/livemetrics", margin, width, height)
+
+</script>
+<h1>
+	Blur <%=System.getProperty("blur.gui.mode") %> '<%=hostName%>'
+</h1>
+<table>
+	<tr>
+		<td>
+			<h3>Blur Queries / Fetches / Mutates Requests</h3>
+			<div id="blur_calls"></div>
+		</td>
+		<td>
+			<h3>Blur Fetches / Mutates Record Rates</h3>
+			<div id="blur_recordRates"></div>
+		</td>
+	</tr>
+	<tr>
+		<td>
+			<h3>JVM Heap / Committed Heap</h3>
+			<div id="jvm"></div>
+		</td>
+		<td>
+			<h3>System Load</h3>
+			<div id="system"></div>
+		</td>
+	</tr>
+</table>
+
+<%@ include file="footer.jsp" %>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-gui/src/main/webapp/metrics.jsp
----------------------------------------------------------------------
diff --git a/blur-gui/src/main/webapp/metrics.jsp b/blur-gui/src/main/webapp/metrics.jsp
new file mode 100644
index 0000000..515a059
--- /dev/null
+++ b/blur-gui/src/main/webapp/metrics.jsp
@@ -0,0 +1,159 @@
+<%
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file 
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+%>
+
+<%
+	String hostName = request.getServerName() + ":" + System.getProperty("blur.gui.servicing.port");
+%>
+<html>
+  <head>
+    <title>Metrics</title>
+    <link href="style.css" rel="stylesheet" type="text/css" />
+  </head>
+  <script src="js/jquery-1.9.1.min.js"></script>
+  
+  <script type="text/javascript">
+    $(function() {
+        $.getJSON('metrics', function(data) {
+            $("#jvm").append(tree(data["jvm"]));
+            
+            var ignoreColumns = ["Operation", "Buffer Type", "Property"];
+            var thriftCallsInfoColumns = ["Operation", "count", "max", "mean", "median", "min", "p75", "p95", "p98", "p99", "p999", "std_dev"];
+            var thriftCallsTable = constructTable(data["org.apache.blur.Blur.Thrift Calls in �s"], thriftCallsInfoColumns, ignoreColumns);
+            $("#thrift-calls").append(thriftCallsTable);
+            
+            var luceneInternalBuffersColumns = ["Buffer Type", "count", "m1", "m5", "m15", "mean", "type", "unit"];
+            var thriftCallsTable = constructTable(data["org.apache.blur.Lucene.Internal Buffers"], luceneInternalBuffersColumns, ignoreColumns);
+            $("#lucene-internal-buffers").append(thriftCallsTable);
+            
+            var blurDefaultColumns = ["Property", "type", "value"];
+            var blurDefaultTable = constructTable(data["org.apache.blur.Blur.default"], blurDefaultColumns, ignoreColumns);
+            $("#blur-default").append(blurDefaultTable);
+            
+            var blurLuceneTable = constructTable(data["org.apache.blur.Lucene"], blurDefaultColumns, ignoreColumns);
+            $("#blur-lucene").append(blurLuceneTable);
+            
+            var blurColumns = ["Operation", "count", "m1", "m5", "m15", "mean", "type", "unit"];
+            var blurTable = constructTable(data["org.apache.blur.Blur"], blurColumns, ignoreColumns);
+            $("#blur").append(blurTable);
+            
+            $("#blur-fetchtimer").append(tree(data["org.apache.blur.Blur"]["Fetch Timer"]));
+        }); 
+    });
+    
+    /*
+     * Builds and returns a UL/LI tree recirsively from the json data provided
+     */
+    function tree(data) {    
+        if (typeof(data) == 'object') {        
+            var ul = $('<ul>');
+            for (var i in data) {            
+                ul.append($('<li>').text(i).append(tree(data[i])));         
+            }        
+            return ul;
+        } else {       
+            var textNode = document.createTextNode(' : ' + data);
+            return textNode;
+        }
+    }
+
+    function constructTable(data, columns, ignoreColumns) {
+    	var table = $("<table>");
+		table.attr("border", "1px solid black");
+		table.attr("border-collapse", "collapse");
+		var thead = $("<thead>");
+		var tbody = $("<tbody>");
+		table.append(thead),
+        table.append(tbody);
+		
+		var headrow = $("<tr>");
+		for (var i in columns) {
+			headrow.append($("<th>").text(columns[i]).css("text-align", "left").css("border", "1px solid black"));
+		}
+		thead.append(headrow);
+	    
+		$.each(data, function(k, v) {
+			var ignoreKey = false;
+		    var tr = $("<tr>");
+		    tr.append($("<td>").text(camelCaseToNormal(k)).css("border", "1px solid black"));
+		    for (var i in columns) {
+		    	if ($.inArray(columns[i], ignoreColumns) == -1) {
+		    		
+		    		if (v[columns[i]] == undefined) {
+		    			ignoreKey = true;
+		    		} else {
+		    			// fetch the value of the appropriate column
+			    		var td = $("<td>");
+		    		    td.text(v[columns[i]]);
+		    		    td.css("border", "1px solid black");
+		    	        tr.append(td);
+		    		}
+		    	}
+		    }
+		    
+		    if (!ignoreKey) {
+		        tbody.append(tr);
+		    }
+		});
+		
+		return table;
+    }
+    
+    function camelCaseToNormal(text) {
+    	return text.replace(/([A-Z])/g, ' $1').replace(/^./, function(str){ return str.toUpperCase(); })
+    }
+
+  </script>
+  
+  <body style="padding:20px;">
+    <div id="header">
+      <h1>Blur <%=System.getProperty("blur.gui.mode") %> '<%=hostName%>'</h1>
+    </div>
+	
+	<div class="container">
+      <div class="content">
+        <div id="jvm"><h2>JVM Properties</h2></div>
+      </div>
+    
+      <div class="content">
+        <div id="thrift-calls"><h2>Thrift Calls</h2></div>
+      </div>
+    </div>
+    
+    <div class="container" style="clear:both;">
+      <div id="blur" class="content" style="width:1300px;"><h2>Blur</h2></div>
+    </div> 
+    
+    <div class="container" style="clear:both;">
+      <div id="lucene-internal-buffers" class="content" style="width:1300px;"><h2>Lucene Internal Buffers</h2></div>
+    </div>  
+
+    <div class="container" style="clear:both;">
+      <div id="blur-default" class="content" style="width:400px;"><h2>Blur Default</h2></div>
+      <div id="blur-lucene"  class="content" style="width:400px;"><h2>Lucene</h2></div>
+      <div id="blur-fetchtimer" class="content" style="width:300px;"><h2>Blur Fetch Timer</h2></div>
+    </div>  
+    
+      <div id="footer">
+        <%@ include file="footer.jsp" %>
+      </div>
+    
+	
+  </body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-gui/src/main/webapp/shardList.jsp
----------------------------------------------------------------------
diff --git a/blur-gui/src/main/webapp/shardList.jsp b/blur-gui/src/main/webapp/shardList.jsp
new file mode 100644
index 0000000..b709ad5
--- /dev/null
+++ b/blur-gui/src/main/webapp/shardList.jsp
@@ -0,0 +1,79 @@
+<%
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file 
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+%>
+<%@ page contentType="text/html; charset=UTF-8" isThreadSafe="false"
+	import="javax.servlet.*" import="javax.servlet.http.*"
+	import="java.io.*" import="java.util.*" import="java.text.DateFormat"
+	import="java.lang.Math" import="java.net.URLEncoder"
+	import="org.apache.blur.thrift.*"
+	import="org.apache.blur.thrift.generated.*"
+	import="org.apache.blur.thrift.generated.Blur.*"%>
+<%@ include file="functions.jsp"%>
+<%!
+	public String shards(Iface client, String clusterName) throws Exception {
+		String ret = "";
+		List<String> servers = client.shardServerList(clusterName);
+		
+		for(String s : servers) {
+			String[] split = s.split(":");
+			int base = Integer.parseInt(System.getProperty("blur.base.shard.port"));
+			int offset = Integer.parseInt(split[1])-base;
+			int baseShardPort = Integer.parseInt(System.getProperty("baseGuiShardPort"));
+			ret += row("<a href='http://" + split[0] + ":" + (baseShardPort + offset) + "'>" + s + "</a>","","");
+			
+		}
+		return ret;
+	}
+%>
+
+<%
+	//TODO: prop file the port
+	String hostName = request.getServerName() + ":" + System.getProperty("blur.gui.servicing.port");
+
+	Iface client = BlurClient.getClient(hostName);
+
+	String clusterName = request.getParameter("clusterName");
+%>
+
+<html>
+<head>
+<title>Blur Cluster Shard List '<%=hostName%>'
+</title>
+<link href="style.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+	<%
+		if (clusterName == null) {
+	%>
+	No cluster specified, go home.
+	<%
+		} else {
+	%>
+	<h1>
+		Blur Shard List for Cluster '<%=clusterName%>'
+	</h1>
+	<br />
+		<%=table(shards(client, clusterName),"Shard") %>
+
+	<%
+		}
+	%>
+<%@ include file="footer.jsp" %>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-gui/src/main/webapp/style.css
----------------------------------------------------------------------
diff --git a/blur-gui/src/main/webapp/style.css b/blur-gui/src/main/webapp/style.css
new file mode 100644
index 0000000..bfecdf1
--- /dev/null
+++ b/blur-gui/src/main/webapp/style.css
@@ -0,0 +1,89 @@
+body {
+	font-family: sans-serif;
+	font-size: 11px;
+	line-height: 17px;
+}
+
+a {
+    color: #0044FF !important;
+    text-decoration: none !important;
+}
+
+h2 {
+	margin: 5px 5px 0px 0px;
+}
+
+hr {
+	-moz-border-bottom-colors: none;
+	-moz-border-image: none;
+	-moz-border-left-colors: none;
+	-moz-border-right-colors: none;
+	-moz-border-top-colors: none;
+	border-color: -moz-use-text-color #DDDDDD #DDDDDD;
+	border-right: 1px solid #DDDDDD;
+	border-style: none solid solid;
+	border-width: 0 1px 1px;
+}
+
+table {
+	font-size: 12px;
+	
+}
+
+td {
+	align: left;
+	font-size: 12px;
+	padding-left: 10px;
+	padding-right: 10px;
+	font-family: Verdana;
+}
+
+.statTable {
+	width: 500px;
+}
+
+.statTableTitle {
+	color: 55555;
+	align: left;
+	font-weight: bold;
+	font-size:14pt;
+	padding: 10px 5px 0px 5px;
+	font-family: Helvetica;
+	background-color: #DDDDDD;
+}
+
+.axis path {
+  fill:none;
+  stroke: black;
+}
+
+.tick {
+  fill:none;
+  stroke:black;
+} 
+
+.axis {
+  font-family: arial;
+  font-size:0.6em;
+}
+
+path {
+  fill:none;
+  stroke:black;
+  stroke-width:2px;
+}
+
+.container {
+    width:1300px;
+    margin:20px 0;
+    padding: 20px;
+}
+
+.content {
+    float:left;
+    width:600px;
+}
+
+#footer {
+    clear:both;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-gui/src/main/webapp/table.jsp
----------------------------------------------------------------------
diff --git a/blur-gui/src/main/webapp/table.jsp b/blur-gui/src/main/webapp/table.jsp
new file mode 100644
index 0000000..a43f0d8
--- /dev/null
+++ b/blur-gui/src/main/webapp/table.jsp
@@ -0,0 +1,174 @@
+<%
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file 
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+%>
+<%@page import="java.text.DecimalFormat"%>
+<%@page import="java.text.NumberFormat"%>
+<%@ page contentType="text/html; charset=UTF-8" isThreadSafe="false"
+	import="javax.servlet.*" import="javax.servlet.http.*"
+	import="java.io.*" import="java.util.*" import="java.text.DateFormat"
+	import="java.lang.Math" import="java.net.URLEncoder"
+	import="org.apache.blur.thrift.*"
+	import="org.apache.blur.thrift.generated.*"
+	import="org.apache.blur.thrift.generated.Blur.*"%>
+<%@ include file="functions.jsp"%>
+<%!public boolean tableInSafeMode(Iface client, String clusterName) throws Exception {
+		return client.isInSafeMode(clusterName);
+	}
+
+	public String getStats(Iface client, String tableName) throws Exception {
+		DecimalFormat df = new DecimalFormat("#,###,###,###0.00");
+		String ret = "";
+
+		TableStats ts = client.getTableStats(tableName);
+		String size = "";
+		//bytes
+		if(ts.bytes < 1000)
+			size = ts.bytes + " bytes";
+		//kb
+		else if(ts.bytes < 1048576)
+			size = df.format(ts.bytes/1000.0) + " KB";
+		else if(ts.bytes < 1073741824)
+			size = df.format(ts.bytes/1000.0/1000) + " MB";
+		else if(ts.bytes < 137438953472l)
+			size = df.format(ts.bytes/1000.0/1000/1000) + " GB";
+		else if(ts.bytes < 1099511627776l)
+			size = df.format(ts.bytes/1000.0/1000/1000/1000) + " TB";
+		ret += row("size", size);
+		ret += row("Queries", ts.queries + "");
+		ret += row("Rows", ts.rowCount + "");
+		ret += row("Records", ts.recordCount + "");
+		TableDescriptor td = client.describe(tableName);
+		ret += row("Block Caching", td.blockCaching + "");
+		ret += row("Compression Block Size", td.compressionBlockSize + "");
+		ret += row("Compression Class", td.compressionClass);
+		ret += row("Read Only", td.readOnly + "");
+	
+		
+		return ret;
+	}
+
+	public String getSchema(Iface client, String tableName) throws Exception {
+		String ret = "";
+
+		Schema s = client.schema(tableName);
+		for (String fam : s.columnFamilies.keySet()) {
+			String tmp = "";
+			for (String c : s.columnFamilies.get(fam))
+				tmp += c + ", ";
+			if (!"".equals(tmp))
+				tmp = tmp.substring(0, tmp.length() - 2);
+			ret += row(fam, tmp);
+		}
+
+		return ret;
+	}
+
+	public String getAD(Iface client, String tableName) throws Exception {
+		String ret = "";
+		TableDescriptor td = client.describe(tableName);
+		AnalyzerDefinition ad = td.analyzerDefinition;
+		Map<String, ColumnFamilyDefinition> cfds = ad.columnFamilyDefinitions;
+		if (cfds != null) {
+			for (String cf : cfds.keySet()) {
+				ColumnFamilyDefinition cfd = cfds.get(cf);
+				if (cfd.defaultDefinition != null) {
+					ret += row(cf, "default", cfd.defaultDefinition.analyzerClassName);
+				}
+				else {
+					ret += row(cf, "default", "none set");
+				}
+				if (cfd.columnDefinitions != null) {
+					for (String col : cfd.columnDefinitions.keySet()) {
+						ret += row("", col, cfd.columnDefinitions.get(col).analyzerClassName);
+					}
+				}
+			}
+		}
+		return ret;
+	}%>
+<%
+	final String NONE = "none given";
+
+	String hostName = request.getServerName() + ":" + System.getProperty("blur.gui.servicing.port");
+
+	Iface client = BlurClient.getClient(hostName);
+
+	String tableName = request.getParameter("tableName");
+	String clusterName = request.getParameter("clusterName");
+
+	if (tableName == null || tableName.length() < 1) {
+		tableName = NONE;
+	}
+
+	if (clusterName == null || clusterName.length() < 1) {
+		clusterName = NONE;
+	}
+%>
+
+
+<html>
+<head>
+<title>Table '<%=tableName%>'
+</title>
+
+<link href="style.css" rel="stylesheet" type="text/css" />
+
+</head>
+
+<body>
+	<%
+		if (NONE.equals(clusterName) || NONE.equals(tableName)) {
+	%>
+	Dont have a cluster and tableName specified, go home.
+	<%
+		} else {
+	%>
+	<h1>
+		Table '<%=tableName%>'
+	</h1>
+	<%
+		if (tableInSafeMode(client, clusterName)) {
+	%>
+		Cluster
+		<%=clusterName%>
+		is in safe mode, cannot retrieve table information yet.
+	<%
+			} else {
+	%>
+	
+		<h2>Stats</h2>
+		<%=table(getStats(client, tableName), "Stat",
+								"Value")%>
+		<br />
+		<h2>Schema</h2>
+		<%=table(getSchema(client, tableName),
+								"ColumnFamily", "Column")%>
+		<br />
+		<h2>Field Definitions</h2>
+		<%=table(getAD(client, tableName), "ColumnFamily",
+								"Column", "Analyzer")%>
+	
+	<%
+			}
+		}
+	%>
+<%@ include file="footer.jsp" %>
+</body>
+</html>
+

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-gui/src/main/webapp/tableList.html
----------------------------------------------------------------------
diff --git a/blur-gui/src/main/webapp/tableList.html b/blur-gui/src/main/webapp/tableList.html
new file mode 100644
index 0000000..2209e1d
--- /dev/null
+++ b/blur-gui/src/main/webapp/tableList.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Blur</title>
+<meta charset="utf-8">
+<link href="css/bootstrap.min.css" rel="stylesheet">
+</head>
+
+<script src="js/jquery-1.9.1.min.js"></script>
+<script src="js/thrift.js"></script>
+<script src="js/Blur.js"></script>
+<script src="js/Blur_types.js"></script>
+<script>
+function tableList() {
+    var transport = new Thrift.Transport("/blur");
+    var protocol  = new Thrift.Protocol(transport);
+    var client    = new BlurClient(protocol);
+        
+    try {
+      var result = client.tableList();
+      for (var i = 0; i < result.length; i++) {
+	    var tableName = result[i];
+	    var tableDescriptor = client.describe(tableName)
+        $("#blurtables_tbody").append(
+	     "<tr>"+
+	      "<td>"+tableDescriptor.name+"</td>"+
+	      "<td>"+tableDescriptor.readOnly+"</td>"+
+	      "<td>"+tableDescriptor.cluster+"</td>"+
+	      "<td>"+tableDescriptor.isEnabled+"</td>"+
+	      "<td>"+tableDescriptor.shardCount+"</td>"+
+	      "<td>"+tableDescriptor.tableUri+"</td>"+
+	     "</tr>");
+      }
+    } catch(ouch){
+alert (ouch);
+    }
+}
+$(window).bind("load", tableList);
+</script>
+<body>
+
+<table>
+<thead>
+<tr>
+<th>Table Name</th>
+<th>ReadOnly</th>
+<th>Cluster</th>
+<th>Enabled</th>
+<th>Shard Count</th>
+<th>Table Uri</th>
+</tr>
+</thead>
+<tbody id="blurtables_tbody">
+	
+</tbody>
+</table>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-gui/src/main/webapp/test.html
----------------------------------------------------------------------
diff --git a/blur-gui/src/main/webapp/test.html b/blur-gui/src/main/webapp/test.html
new file mode 100644
index 0000000..034ba04
--- /dev/null
+++ b/blur-gui/src/main/webapp/test.html
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<style>
+svg {
+	font: 10px sans-serif;
+}
+
+.line {
+	fill: none;
+	stroke: #000;
+	stroke-width: 1.5px;
+}
+
+.axis path,.axis line {
+	fill: none;
+	stroke: #000;
+	shape-rendering: crispEdges;
+}
+
+div { 
+	background: #CCC;
+}
+
+</style>
+
+</head>
+
+<script src="d3.v2.js"></script>
+<body>
+	<script>
+		//decimal formatter
+		var df = d3.format("4d");
+
+		//basic printout
+		d3.json("metrics", function(json) {
+			//alert(json);
+			arr = [];
+			arr[0] = json;
+			//select obj and bind data
+			d3.select("body").selectAll("ul")
+				.data(arr)
+				.enter().append("ul")
+				.text("Metrics")
+				.selectAll("li")
+				.data(function(d) {
+					var map = [];
+					var i = 0;
+					for(var x in d) {
+						var obj = {};
+						obj.name = x;
+						obj.value = d[x];
+						map[i++] = obj;
+					}
+					return map})
+					.enter()
+					.append("li")
+					.text(function(d) { return d.name + " " + d.value })
+					.style("background-color", function(d,i) { return i % 2 ? "#eee" : "#ddd"; });
+		});
+		
+		
+		
+		//realtime update stuffs
+		
+		//data holder
+		var dummy = [];
+		
+		var total = 10;
+		for(i=0;i<total-1;i++)
+			dummy.push(0);
+		
+		var div = null;
+
+		//not sure why i have to init inside the json method
+		d3.json("metrics", function(json) {
+			dummy.push(d3.round(json.methodCalls.mutate.invokes
+					/ (json.methodCalls.mutate.times / 1000000000.0), 3));
+
+			//select obj and bind data
+			div = d3.select("body")
+						.selectAll("div")
+						.data(dummy)
+						.enter()
+						.append("div")
+						.append("p")
+						.text(function(d) { return d + " mutates/s"});
+			dummy.shift();
+		
+		});
+
+		if(dummy === undefined)
+			alert("no metrics for mutates");
+
+		function tock() {
+			d3.json("metrics", function(json) {
+				dummy.push(d3.round(json.methodCalls.mutate.invokes
+						/ (json.methodCalls.mutate.times / 1000000000.0), 3));
+
+				alert("dummy.length: " + dummy.length + " dummy: " + dummy);
+	
+				div.transition()
+					.duration(1000)
+					.ease("linear")
+					//.text(function(d,i) { alert(d + " " + i);return d + " mutates/s"})
+					.each("end",tock());
+				dummy.shift();
+			});
+		}
+
+		tock();
+		
+		//after data add?
+//		div.enter().append("span").text(function(d) {
+//			return d + "<br/>\n";
+//		})
+
+
+	</script>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-jdbc/jar.sh
----------------------------------------------------------------------
diff --git a/blur-jdbc/jar.sh b/blur-jdbc/jar.sh
new file mode 100755
index 0000000..e2f70ae
--- /dev/null
+++ b/blur-jdbc/jar.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+mvn assembly:assembly -DdescriptorId=jar-with-dependencies

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-jdbc/pom.xml
----------------------------------------------------------------------
diff --git a/blur-jdbc/pom.xml b/blur-jdbc/pom.xml
new file mode 100644
index 0000000..1830533
--- /dev/null
+++ b/blur-jdbc/pom.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor 
+	license agreements. See the NOTICE file distributed with this work for additional 
+	information regarding copyright ownership. The ASF licenses this file to 
+	you under the Apache License, Version 2.0 (the "License"); you may not use 
+	this file except in compliance with the License. You may obtain a copy of 
+	the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required 
+	by applicable law or agreed to in writing, software distributed under the 
+	License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 
+	OF ANY KIND, either express or implied. See the License for the specific 
+	language governing permissions and limitations under the License. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<parent>
+		<groupId>org.apache.blur</groupId>
+		<artifactId>blur</artifactId>
+		<version>0.1.5</version>
+		<relativePath>../pom.xml</relativePath>
+	</parent>
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>org.apache.blur</groupId>
+	<artifactId>blur-jdbc</artifactId>
+	<packaging>jar</packaging>
+	<name>Blur JDBC</name>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.blur</groupId>
+			<artifactId>blur-thrift</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.blur</groupId>
+			<artifactId>blur-util</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>log4j</groupId>
+			<artifactId>log4j</artifactId>
+			<version>${log4j.version}</version>
+			<scope>provided</scope>
+			<exclusions>
+				<exclusion>
+					<groupId>javax.mail</groupId>
+					<artifactId>mail</artifactId>
+				</exclusion>
+				<exclusion>
+					<groupId>javax.jms</groupId>
+					<artifactId>jms</artifactId>
+				</exclusion>
+				<exclusion>
+					<groupId>com.sun.jdmk</groupId>
+					<artifactId>jmxtools</artifactId>
+				</exclusion>
+				<exclusion>
+					<groupId>com.sun.jmx</groupId>
+					<artifactId>jmxri</artifactId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<finalName>blur-jdbc-${project.version}</finalName>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-jdbc/src/assemble/bin.xml
----------------------------------------------------------------------
diff --git a/blur-jdbc/src/assemble/bin.xml b/blur-jdbc/src/assemble/bin.xml
new file mode 100644
index 0000000..463fdbc
--- /dev/null
+++ b/blur-jdbc/src/assemble/bin.xml
@@ -0,0 +1,8 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+  <id>bin</id>
+  <formats>
+    <format>jar</format>
+  </formats>
+</assembly>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurConnection.java
----------------------------------------------------------------------
diff --git a/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurConnection.java b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurConnection.java
new file mode 100644
index 0000000..ea4e145
--- /dev/null
+++ b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurConnection.java
@@ -0,0 +1,117 @@
+package org.apache.blur.jdbc;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.Statement;
+
+import org.apache.blur.jdbc.abstractimpl.AbstractBlurConnection;
+
+public class BlurConnection extends AbstractBlurConnection {
+
+  private boolean closed;
+  private int port;
+  private String host;
+  private String catalog;
+  private String url;
+  private String username;
+
+  public BlurConnection(String url, String username, String host, int port, String catalog) {
+    this.host = host;
+    this.port = port;
+    this.catalog = catalog;
+    this.url = url;
+    this.username = username;
+  }
+
+  @Override
+  public void close() throws SQLException {
+
+  }
+
+  @Override
+  public String getCatalog() throws SQLException {
+    return catalog;
+  }
+
+  @Override
+  public DatabaseMetaData getMetaData() throws SQLException {
+    return new BlurDatabaseMetaData(url, username, host, port);
+  }
+
+  @Override
+  public Statement createStatement() throws SQLException {
+    return new BlurStatement(this);
+  }
+
+  @Override
+  public PreparedStatement prepareStatement(String sql) throws SQLException {
+    return new BlurPreparedStatement(this, sql);
+  }
+
+  @Override
+  public boolean getAutoCommit() throws SQLException {
+    return false;
+  }
+
+  @Override
+  public SQLWarning getWarnings() throws SQLException {
+    return new BlurWarnings();
+  }
+
+  @Override
+  public boolean isClosed() throws SQLException {
+    return closed;
+  }
+
+  @Override
+  public boolean isReadOnly() throws SQLException {
+    return true;
+  }
+
+  @Override
+  public void setAutoCommit(boolean arg0) throws SQLException {
+
+  }
+
+  @Override
+  public void clearWarnings() throws SQLException {
+
+  }
+
+  @Override
+  public void rollback() throws SQLException {
+
+  }
+
+  public int getPort() {
+    return port;
+  }
+
+  public String getHost() {
+    return host;
+  }
+
+  @Override
+  public int getTransactionIsolation() throws SQLException {
+    return TRANSACTION_NONE;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurDatabaseMetaData.java
----------------------------------------------------------------------
diff --git a/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurDatabaseMetaData.java b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurDatabaseMetaData.java
new file mode 100644
index 0000000..fd3098a
--- /dev/null
+++ b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurDatabaseMetaData.java
@@ -0,0 +1,426 @@
+package org.apache.blur.jdbc;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.RowIdLifetime;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.blur.jdbc.abstractimpl.AbstractBlurDatabaseMetaData;
+import org.apache.blur.jdbc.util.EmptyResultSet;
+import org.apache.blur.jdbc.util.SimpleStringResultSet;
+import org.apache.blur.thirdparty.thrift_0_9_0.TException;
+import org.apache.blur.thrift.BlurClientManager;
+import org.apache.blur.thrift.commands.BlurCommand;
+import org.apache.blur.thrift.generated.Blur.Client;
+import org.apache.blur.thrift.generated.BlurException;
+import org.apache.blur.thrift.generated.Schema;
+import org.apache.blur.thrift.generated.TableDescriptor;
+
+
+public class BlurDatabaseMetaData extends AbstractBlurDatabaseMetaData {
+
+  private static final String REF_GENERATION = "REF_GENERATION";
+  private static final String SELF_REFERENCING_COL_NAME = "SELF_REFERENCING_COL_NAME";
+  private static final String TYPE_NAME = "TYPE_NAME";
+  private static final String TYPE_SCHEM = "TYPE_SCHEM";
+  private static final String TYPE_CAT = "TYPE_CAT";
+  private static final String REMARKS = "REMARKS";
+  private static final String TABLE_TYPE = "TABLE_TYPE";
+  private static final String TABLE_NAME = "TABLE_NAME";
+  private static final String TABLE_SCHEM = "TABLE_SCHEM";
+  private static final String TABLE_CAT = "TABLE_CAT";
+  private static final String TABLE_CATALOG = "TABLE_CATALOG";
+
+  private int minorVersion = 1;
+  private int majorVersion = 1;
+  private String url;
+  private String username;
+  private int port;
+  private String host;
+  private List<String> tables;
+  private Map<String, Schema> schemaMap = new TreeMap<String, Schema>();
+
+  public BlurDatabaseMetaData(String url, String username, String host, int port) {
+    this.url = url;
+    this.username = username;
+    this.host = host;
+    this.port = port;
+    try {
+      BlurClientManager.execute(this.host + ":" + this.port, new BlurCommand<Void>() {
+
+        @Override
+        public Void call(Client client) throws BlurException, TException {
+          tables = client.tableList();
+          for (String table : tables) {
+            TableDescriptor descriptor = client.describe(table);
+            if (descriptor.isEnabled) {
+              schemaMap.put(table, client.schema(table));
+            }
+          }
+          return null;
+        }
+      });
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  @Override
+  public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException {
+    return super.getBestRowIdentifier(catalog, schema, table, scope, nullable);
+  }
+
+  @Override
+  public ResultSet getSchemas() throws SQLException {
+    List<Map<String, String>> data = new ArrayList<Map<String, String>>();
+    for (String table : tables) {
+      Map<String, String> row = new HashMap<String, String>();
+      row.put(TABLE_SCHEM, table);
+      data.add(row);
+    }
+    return new SimpleStringResultSet(Arrays.asList(TABLE_SCHEM, TABLE_CATALOG), data);
+  }
+
+  @Override
+  public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException {
+    List<Map<String, String>> data = new ArrayList<Map<String, String>>();
+    for (String table : tables) {
+      if (tableNamePattern != null && !table.equals(tableNamePattern)) {
+        continue;
+      }
+      Schema schema = schemaMap.get(table);
+      Map<String, Set<String>> columnFamilies = schema.columnFamilies;
+      addTableRow(data, table, table);
+      for (String columnFamily : columnFamilies.keySet()) {
+        String tablePlusCf = table + "." + columnFamily;
+        if (tableNamePattern != null && !tablePlusCf.equals(tableNamePattern)) {
+          continue;
+        }
+        addTableRow(data, table, tablePlusCf);
+      }
+    }
+    return new TableDescriptorResultSet(data);
+  }
+
+  @Override
+  public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException {
+    return new EmptyResultSet();
+  }
+
+  private void addTableRow(List<Map<String, String>> data, String schem, String table) {
+    Map<String, String> row = new HashMap<String, String>();
+    row.put(TABLE_SCHEM, schem);
+    row.put(TABLE_NAME, table);
+    row.put(TABLE_TYPE, "TABLE");
+    row.put(REMARKS, "");
+    data.add(row);
+  }
+
+  public static class TableDescriptorResultSet extends SimpleStringResultSet {
+    private static final List<String> COL_NAMES = Arrays.asList(TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS, TYPE_CAT, TYPE_SCHEM, TYPE_NAME,
+        SELF_REFERENCING_COL_NAME, REF_GENERATION);
+
+    public TableDescriptorResultSet(List<Map<String, String>> data) {
+      super(COL_NAMES, data);
+    }
+  }
+
+  @Override
+  public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException {
+    return new EmptyResultSet();
+  }
+
+  @Override
+  public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException {
+    return new EmptyResultSet();
+  }
+
+  @Override
+  public String getSQLKeywords() throws SQLException {
+    return "";
+  }
+
+  public int getDefaultTransactionIsolation() throws SQLException {
+    return Connection.TRANSACTION_NONE;
+  }
+
+  public ResultSet getTableTypes() throws SQLException {
+    return new EmptyResultSet();
+  }
+
+  public String getDatabaseProductName() throws SQLException {
+    return "blur";
+  }
+
+  public String getCatalogSeparator() throws SQLException {
+    return ",";
+  }
+
+  public String getDriverName() throws SQLException {
+    return "blur";
+  }
+
+  public String getDriverVersion() throws SQLException {
+    return "0.1";
+  }
+
+  public String getIdentifierQuoteString() throws SQLException {
+    return "'";
+  }
+
+  @Override
+  public String getDatabaseProductVersion() throws SQLException {
+    return "0.1";
+  }
+
+  @Override
+  public ResultSet getCatalogs() throws SQLException {
+    return new EmptyResultSet();
+  }
+
+  @Override
+  public ResultSet getClientInfoProperties() throws SQLException {
+    return new EmptyResultSet();
+  }
+
+  @Override
+  public RowIdLifetime getRowIdLifetime() throws SQLException {
+    return RowIdLifetime.ROWID_UNSUPPORTED;
+  }
+
+  @Override
+  public int getSQLStateType() throws SQLException {
+    return sqlStateSQL;
+  }
+
+  @Override
+  public int getJDBCMajorVersion() throws SQLException {
+    return majorVersion;
+  }
+
+  @Override
+  public int getJDBCMinorVersion() throws SQLException {
+    return minorVersion;
+  }
+
+  @Override
+  public int getDatabaseMajorVersion() throws SQLException {
+    return majorVersion;
+  }
+
+  @Override
+  public int getDatabaseMinorVersion() throws SQLException {
+    return minorVersion;
+  }
+
+  @Override
+  public int getResultSetHoldability() throws SQLException {
+    return ResultSet.CLOSE_CURSORS_AT_COMMIT;
+  }
+
+  @Override
+  public int getMaxTablesInSelect() throws SQLException {
+    return 1;
+  }
+
+  @Override
+  public int getMaxUserNameLength() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public String getTimeDateFunctions() throws SQLException {
+    return "";
+  }
+
+  @Override
+  public int getMaxStatementLength() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxStatements() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxTableNameLength() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxRowSize() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public String getStringFunctions() throws SQLException {
+    return "";
+  }
+
+  @Override
+  public int getMaxCatalogNameLength() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxProcedureNameLength() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxSchemaNameLength() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public String getCatalogTerm() throws SQLException {
+    return "catalog";
+  }
+
+  @Override
+  public int getDriverMajorVersion() {
+    return majorVersion;
+  }
+
+  @Override
+  public int getDriverMinorVersion() {
+    return minorVersion;
+  }
+
+  @Override
+  public String getExtraNameCharacters() throws SQLException {
+    return ".";
+  }
+
+  @Override
+  public int getMaxBinaryLiteralLength() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxCharLiteralLength() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxColumnNameLength() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxColumnsInGroupBy() throws SQLException {
+    return 0;
+  }
+
+  @Override
+  public int getMaxColumnsInIndex() throws SQLException {
+    return 0;
+  }
+
+  @Override
+  public int getMaxColumnsInOrderBy() throws SQLException {
+    return 0;
+  }
+
+  @Override
+  public int getMaxColumnsInSelect() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxColumnsInTable() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxConnections() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxCursorNameLength() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public int getMaxIndexLength() throws SQLException {
+    return Integer.MAX_VALUE;
+  }
+
+  @Override
+  public String getNumericFunctions() throws SQLException {
+    return "";
+  }
+
+  @Override
+  public String getProcedureTerm() throws SQLException {
+    return "procedure";
+  }
+
+  @Override
+  public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException {
+    return new EmptyResultSet();
+  }
+
+  @Override
+  public String getSchemaTerm() throws SQLException {
+    return "schema";
+  }
+
+  @Override
+  public String getSearchStringEscape() throws SQLException {
+    return "\\";
+  }
+
+  @Override
+  public ResultSet getTypeInfo() throws SQLException {
+    return new EmptyResultSet();
+  }
+
+  @Override
+  public String getURL() throws SQLException {
+    return url;
+  }
+
+  @Override
+  public String getUserName() throws SQLException {
+    return username;
+  }
+
+  @Override
+  public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException {
+    return new EmptyResultSet();
+  }
+
+  @Override
+  public String getSystemFunctions() throws SQLException {
+    return "";
+  }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurJdbc.java
----------------------------------------------------------------------
diff --git a/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurJdbc.java b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurJdbc.java
new file mode 100644
index 0000000..861fe45
--- /dev/null
+++ b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurJdbc.java
@@ -0,0 +1,94 @@
+package org.apache.blur.jdbc;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverPropertyInfo;
+import java.sql.SQLException;
+import java.util.Properties;
+
+public class BlurJdbc implements Driver {
+
+  static {
+    try {
+      java.sql.DriverManager.registerDriver(new BlurJdbc());
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  @Override
+  public boolean acceptsURL(String url) throws SQLException {
+    // jdbc:blur:host:port
+    String[] split = url.split(":");
+    if (split.length != 4) {
+      return false;
+    }
+    if ("jdbc".equals(split[0])) {
+      if ("blur".equals(split[1])) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Connection connect(String url, Properties info) throws SQLException {
+    // jdbc:blur:host:port
+    String username = "";
+    String[] split = url.split(":");
+    if (split.length != 4) {
+      throw new SQLException("Invalid url [" + url + "]");
+    }
+    if ("jdbc".equals(split[0])) {
+      if ("blur".equals(split[1])) {
+        String host = split[2];
+        int port = Integer.parseInt(split[3]);
+        return new BlurConnection(url, username, host, port, host);
+      }
+    }
+    throw new SQLException("Invalid url [" + url + "]");
+  }
+
+  @Override
+  public int getMajorVersion() {
+    return 1;
+  }
+
+  @Override
+  public int getMinorVersion() {
+    return 0;
+  }
+
+  @Override
+  public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
+    return null;
+  }
+
+  @Override
+  public boolean jdbcCompliant() {
+    return false;
+  }
+  
+  //java 7
+
+//  public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+//    throw new SQLFeatureNotSupportedException();
+//  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurPreparedStatement.java
----------------------------------------------------------------------
diff --git a/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurPreparedStatement.java b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurPreparedStatement.java
new file mode 100644
index 0000000..1e796db
--- /dev/null
+++ b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurPreparedStatement.java
@@ -0,0 +1,45 @@
+package org.apache.blur.jdbc;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.blur.jdbc.abstractimpl.AbstractBlurPreparedStatement;
+
+
+public class BlurPreparedStatement extends AbstractBlurPreparedStatement {
+
+  private BlurStatement blurStatement;
+  private String sql;
+
+  public BlurPreparedStatement(BlurConnection connection, String sql) {
+    this.sql = sql;
+    blurStatement = new BlurStatement(connection);
+  }
+
+  @Override
+  public boolean execute() throws SQLException {
+    return blurStatement.execute(sql);
+  }
+
+  @Override
+  public ResultSet getResultSet() throws SQLException {
+    return blurStatement.getResultSet();
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurResultSetMetaData.java
----------------------------------------------------------------------
diff --git a/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurResultSetMetaData.java b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurResultSetMetaData.java
new file mode 100644
index 0000000..f1b9c8d
--- /dev/null
+++ b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurResultSetMetaData.java
@@ -0,0 +1,228 @@
+package org.apache.blur.jdbc;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.blur.jdbc.abstractimpl.AbstractBlurResultSetMetaData;
+
+
+public class BlurResultSetMetaData extends AbstractBlurResultSetMetaData {
+
+  public static final String RECORDID = "recordid";
+  public static final String FAMILY = "family";
+  public static final String LOCATIONID = "locationid";
+  public static final String SCORE = "score";
+  public static final String ROWID = "rowid";
+
+  public enum QUERY_COLUMN_TYPE {
+    ALL_COLUMNS, ALL_COLUMNS_IN_CF, ONE_COLUMN_IN_CF, ONE_COLUMN_IN_SYSTEM
+  }
+
+  public static Collection<String> systemCols;
+  private List<String> sqlColumnNames;
+  private String tableName;
+  private Map<String, Set<String>> columnFamilies;
+
+  static {
+    systemCols = new HashSet<String>();
+    systemCols.add(ROWID);
+    systemCols.add(SCORE);
+    systemCols.add(LOCATIONID);
+    systemCols.add(FAMILY);
+    systemCols.add(RECORDID);
+  }
+
+  public BlurResultSetMetaData(List<String> queryColumnNames, Map<String, Set<String>> columnFamilies) {
+    this.columnFamilies = columnFamilies;
+    this.sqlColumnNames = new ArrayList<String>();
+    this.sqlColumnNames.add(null);
+    for (String queryColumnName : queryColumnNames) {
+      addReturnColumns(queryColumnName);
+    }
+  }
+
+  private void addReturnColumns(String queryColumnName) {
+    String col = queryColumnName.trim();
+    if ("*".equals(col)) {
+      addAllColumns();
+      return;
+    }
+    int index = col.indexOf('.');
+    if (index < 0) {
+      addSystemColumn(col);
+      return;
+    }
+    String columnFamily = col.substring(0, index);
+    String columnName = col.substring(index + 1);
+    if ("*".equals(columnName)) {
+      addColumnFamily(columnFamily);
+      return;
+    }
+    addColumn(columnFamily, columnName);
+  }
+
+  private void addColumn(String columnFamily, String columnName) {
+    sqlColumnNames.add(columnFamily + "." + columnName);
+  }
+
+  private void addColumnFamily(String columnFamily) {
+    Set<String> columns = columnFamilies.get(columnFamily);
+    if (columns == null) {
+      throw new RuntimeException("Column family [" + columnFamily + "] not found.");
+    }
+    for (String columnName : columns) {
+      addColumn(columnFamily, columnName);
+    }
+  }
+
+  private void addSystemColumn(String col) {
+    String lcCol = col.toLowerCase();
+    if (systemCols.contains(lcCol)) {
+      sqlColumnNames.add(lcCol);
+      return;
+    }
+    throw new RuntimeException("System column [" + col + "] not found.");
+  }
+
+  private void addAllColumns() {
+    sqlColumnNames.add(ROWID);
+    sqlColumnNames.add(FAMILY);
+    sqlColumnNames.add(RECORDID);
+    Map<String, Set<String>> columnFamilies = new TreeMap<String, Set<String>>(this.columnFamilies);
+    for (String family : columnFamilies.keySet()) {
+      Set<String> columnNames = columnFamilies.get(family);
+      for (String columnName : columnNames) {
+        sqlColumnNames.add(family + "." + columnName);
+      }
+    }
+  }
+
+  @Override
+  public String getColumnClassName(int column) throws SQLException {
+    return "java.lang.String";
+  }
+
+  @Override
+  public int getColumnType(int column) throws SQLException {
+    return Types.VARCHAR;
+  }
+
+  @Override
+  public int getColumnCount() throws SQLException {
+    return sqlColumnNames.size() - 1;
+  }
+
+  @Override
+  public String getColumnName(int column) throws SQLException {
+    return sqlColumnNames.get(column);
+  }
+
+  @Override
+  public String getColumnTypeName(int column) throws SQLException {
+    return "string";
+  }
+
+  @Override
+  public int getPrecision(int column) throws SQLException {
+    return 4000;
+  }
+
+  @Override
+  public int getScale(int column) throws SQLException {
+    return 0;
+  }
+
+  @Override
+  public String getCatalogName(int column) throws SQLException {
+    return "";
+  }
+
+  @Override
+  public String getSchemaName(int column) throws SQLException {
+    return "";
+  }
+
+  @Override
+  public String getTableName(int column) throws SQLException {
+    return tableName;
+  }
+
+  @Override
+  public int isNullable(int column) throws SQLException {
+    return ResultSetMetaData.columnNullable;
+  }
+
+  @Override
+  public int getColumnDisplaySize(int column) throws SQLException {
+    return 100;
+  }
+
+  @Override
+  public String getColumnLabel(int column) throws SQLException {
+    return getColumnName(column);
+  }
+
+  @Override
+  public boolean isAutoIncrement(int column) throws SQLException {
+    return false;
+  }
+
+  @Override
+  public boolean isCaseSensitive(int column) throws SQLException {
+    return true;
+  }
+
+  @Override
+  public boolean isCurrency(int column) throws SQLException {
+    return false;
+  }
+
+  @Override
+  public boolean isDefinitelyWritable(int column) throws SQLException {
+    return false;
+  }
+
+  @Override
+  public boolean isReadOnly(int column) throws SQLException {
+    return true;
+  }
+
+  @Override
+  public boolean isSearchable(int column) throws SQLException {
+    return true;
+  }
+
+  @Override
+  public boolean isSigned(int column) throws SQLException {
+    return false;
+  }
+
+  @Override
+  public boolean isWritable(int column) throws SQLException {
+    return false;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/b0e26648/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurResultSetRecords.java
----------------------------------------------------------------------
diff --git a/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurResultSetRecords.java b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurResultSetRecords.java
new file mode 100644
index 0000000..c86e574
--- /dev/null
+++ b/blur-jdbc/src/main/java/org/apache/blur/jdbc/BlurResultSetRecords.java
@@ -0,0 +1,247 @@
+package org.apache.blur.jdbc;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import static org.apache.blur.jdbc.BlurResultSetMetaData.FAMILY;
+import static org.apache.blur.jdbc.BlurResultSetMetaData.LOCATIONID;
+import static org.apache.blur.jdbc.BlurResultSetMetaData.RECORDID;
+import static org.apache.blur.jdbc.BlurResultSetMetaData.ROWID;
+import static org.apache.blur.jdbc.BlurResultSetMetaData.SCORE;
+
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+import org.apache.blur.jdbc.abstractimpl.AbstractBlurResultSet;
+import org.apache.blur.jdbc.parser.Parser;
+import org.apache.blur.thirdparty.thrift_0_9_0.TException;
+import org.apache.blur.thrift.generated.Blur.Iface;
+import org.apache.blur.thrift.generated.BlurException;
+import org.apache.blur.thrift.generated.BlurQuery;
+import org.apache.blur.thrift.generated.BlurResult;
+import org.apache.blur.thrift.generated.BlurResults;
+import org.apache.blur.thrift.generated.Column;
+import org.apache.blur.thrift.generated.FetchResult;
+import org.apache.blur.thrift.generated.Record;
+import org.apache.blur.thrift.generated.Schema;
+import org.apache.blur.thrift.generated.Selector;
+import org.apache.blur.thrift.generated.SimpleQuery;
+
+
+public class BlurResultSetRecords extends AbstractBlurResultSet {
+
+  private Selector selector;
+  private BlurResults results;
+  private int resultPosition = -1;
+  private int size;
+  private String tableName;
+  private FetchResult fetchResult;
+  private BlurResultSetMetaData blurResultSetMetaData;
+  private String lastValue;
+  private List<List<String>> displayRows = new ArrayList<List<String>>();
+  private int displayRowsPosition;
+  private Schema schema;
+  private final Iface client;
+  private long totalResults;
+  private int overallRowPosition;
+  private int currentFetch;
+  private int currentStart;
+  private Parser parser;
+  private List<String> columnNames;
+  private String columnFamily;
+
+  public BlurResultSetRecords(Iface client, Parser parser) throws SQLException {
+    this.client = client;
+    this.parser = parser;
+    String tName = parser.getTableName();
+    int lastIndexOf = tName.lastIndexOf('.');
+    tableName = tName.substring(0, lastIndexOf);
+    columnFamily = tName.substring(lastIndexOf + 1);
+    columnNames = parser.getColumnNames();
+    runSearch(0, 100);
+  }
+
+  private void runSearch(int start, int fetch) throws SQLException {
+    currentStart = start;
+    currentFetch = fetch;
+    BlurQuery blurQuery = new BlurQuery();
+    blurQuery.minimumNumberOfResults = Long.MAX_VALUE;
+    blurQuery.maxQueryTime = Long.MAX_VALUE;
+    blurQuery.uuid = new Random().nextLong();
+    blurQuery.fetch = fetch;
+    blurQuery.start = start;
+    blurQuery.simpleQuery = new SimpleQuery();
+    blurQuery.simpleQuery.queryStr = parser.getWhere();
+    blurQuery.simpleQuery.superQueryOn = false;
+
+    try {
+      schema = client.schema(tableName);
+    } catch (BlurException e) {
+      e.printStackTrace();
+      throw new SQLException(e);
+    } catch (TException e) {
+      e.printStackTrace();
+      throw new SQLException(e);
+    }
+
+    selector = new Selector();
+    setupSelector(selector, schema, columnNames);
+    selector.recordOnly = !blurQuery.simpleQuery.superQueryOn;
+    Map<String, Set<String>> columnFamilies = schema.columnFamilies;
+    Set<String> cfSet = columnFamilies.get(columnFamily);
+    columnFamilies.clear();
+    columnFamilies.put(columnFamily, cfSet);
+    blurResultSetMetaData = new BlurResultSetMetaData(columnNames, columnFamilies);
+    try {
+      results = client.query(tableName, blurQuery);
+    } catch (BlurException e) {
+      e.printStackTrace();
+      throw new SQLException(e);
+    } catch (TException e) {
+      e.printStackTrace();
+      throw new SQLException(e);
+    }
+    if (results.totalResults > 0) {
+      size = results.results.size();
+    }
+    totalResults = results.totalResults;
+  }
+
+  private void setupSelector(Selector selector, Schema schema, List<String> columnNames) {
+
+  }
+
+  @Override
+  public ResultSetMetaData getMetaData() throws SQLException {
+    return blurResultSetMetaData;
+  }
+
+  @Override
+  public boolean next() throws SQLException {
+    if (displayRows != null && displayRowsPosition + 1 < displayRows.size()) {
+      overallRowPosition++;
+      displayRowsPosition++;
+      return true;
+    } else if (resultPosition + 1 < size) {
+      INNER: while (resultPosition + 1 < size) {
+        displayRows.clear();
+        resultPosition++;
+        displayRowsPosition = 0;
+        overallRowPosition++;
+
+        final BlurResult result = results.results.get(resultPosition);
+        try {
+          selector.setLocationId(result.getLocationId());
+          fetchResult = client.fetchRow(tableName, selector);
+          Record record = fetchResult.recordResult.record;
+          if (!record.family.equals(columnFamily)) {
+            continue INNER;
+          }
+          String rowId = fetchResult.recordResult.rowid;
+          displayRows.add(addColumns(result.getScore(), result.getLocationId(), rowId, record.family, record));
+          return true;
+
+        } catch (Exception e) {
+          e.printStackTrace();
+          throw new SQLException(e);
+        }
+      }
+      return next();
+    } else if (overallRowPosition < totalResults) {
+      currentStart += currentFetch;
+      runSearch(currentStart, currentFetch);
+      displayRowsPosition = 0;
+      resultPosition = -1;
+      return next();
+    }
+    return false;
+  }
+
+  private List<String> addColumns(double score, String locationId, String rowId, String family, Record record) throws SQLException {
+    int columnCount = blurResultSetMetaData.getColumnCount();
+    List<String> result = new ArrayList<String>(columnCount + 1);
+    for (int i = 0; i < columnCount + 1; i++) {
+      result.add(null);
+    }
+    for (int i = 1; i <= columnCount; i++) {
+      String columnName = blurResultSetMetaData.getColumnName(i);
+      if (columnName.equals(ROWID)) {
+        result.set(i, rowId);
+      } else if (columnName.equals(SCORE)) {
+        result.set(i, Double.toString(score));
+      } else if (columnName.equals(LOCATIONID)) {
+        result.set(i, locationId);
+      } else if (columnName.equals(FAMILY)) {
+        result.set(i, family);
+      } else if (columnName.equals(RECORDID)) {
+        result.set(i, record.recordId);
+      } else {
+        String value = getValue(record, columnName, family);
+        result.set(i, value);
+      }
+    }
+    return result;
+  }
+
+  private String getValue(Record record, String columnNameWithFamilyName, String family) {
+    int index = columnNameWithFamilyName.indexOf('.');
+    if (family.equals(columnNameWithFamilyName.substring(0, index))) {
+      String columnName = columnNameWithFamilyName.substring(index + 1);
+      List<String> values = new ArrayList<String>();
+      for (Column col : record.columns) {
+        if (columnName.equals(col.getName())) {
+          values.add(col.getValue());
+        }
+      }
+      if (values.size() == 1) {
+        return values.get(0);
+      } else {
+        return values.toString();
+      }
+    } else {
+      return null;
+    }
+  }
+
+  @Override
+  public String getString(int columnIndex) throws SQLException {
+    return lastValue = displayRows.get(displayRowsPosition).get(columnIndex);
+  }
+
+  @Override
+  public boolean wasNull() throws SQLException {
+    if (lastValue == null) {
+      return true;
+    }
+    return false;
+  }
+
+  @Override
+  public void close() throws SQLException {
+
+  }
+
+  @Override
+  public SQLWarning getWarnings() throws SQLException {
+    return new BlurWarnings();
+  }
+}


Mime
View raw message