diff options
Diffstat (limited to '')
-rw-r--r-- | infrastructure/framework-src/modules/atomfeed.js (renamed from trunk/infrastructure/framework-src/modules/atomfeed.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/blob.js (renamed from trunk/infrastructure/framework-src/modules/blob.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/cache_utils.js (renamed from trunk/infrastructure/framework-src/modules/cache_utils.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/comet.js (renamed from trunk/infrastructure/framework-src/modules/comet.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/dateutils.js (renamed from trunk/infrastructure/framework-src/modules/dateutils.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/dispatch.js (renamed from trunk/infrastructure/framework-src/modules/dispatch.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/ejs.js | 477 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/email.js (renamed from trunk/infrastructure/framework-src/modules/email.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/exceptionutils.js (renamed from trunk/infrastructure/framework-src/modules/exceptionutils.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/execution.js | 61 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/fastJSON.js (renamed from trunk/infrastructure/framework-src/modules/fastJSON.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/faststatic.js | 342 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/fileutils.js (renamed from trunk/infrastructure/framework-src/modules/fileutils.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/funhtml.js (renamed from trunk/infrastructure/framework-src/modules/funhtml.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/global/appjet.js (renamed from trunk/infrastructure/framework-src/modules/global/appjet.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/global/request.js (renamed from trunk/infrastructure/framework-src/modules/global/request.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/global/response.js (renamed from trunk/infrastructure/framework-src/modules/global/response.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/image.js (renamed from trunk/infrastructure/framework-src/modules/image.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/jsutils.js (renamed from trunk/infrastructure/framework-src/modules/jsutils.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/netutils.js (renamed from trunk/infrastructure/framework-src/modules/netutils.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/process.js | 91 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/profiler.js (renamed from trunk/infrastructure/framework-src/modules/profiler.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/sessions.js (renamed from trunk/infrastructure/framework-src/modules/sessions.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/sqlbase/persistent_vars.js (renamed from trunk/infrastructure/framework-src/modules/sqlbase/persistent_vars.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/sqlbase/sqlbase.js (renamed from trunk/infrastructure/framework-src/modules/sqlbase/sqlbase.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/sqlbase/sqlcommon.js (renamed from trunk/infrastructure/framework-src/modules/sqlbase/sqlcommon.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/sqlbase/sqlobj.js | 551 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/stringutils.js (renamed from trunk/infrastructure/framework-src/modules/stringutils.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/sync.js (renamed from trunk/infrastructure/framework-src/modules/sync.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/timer.js (renamed from trunk/infrastructure/framework-src/modules/timer.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/varz.js (renamed from trunk/infrastructure/framework-src/modules/varz.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/modules/yuicompressor.js (renamed from trunk/infrastructure/framework-src/modules/yuicompressor.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/oncomet.js (renamed from trunk/infrastructure/framework-src/oncomet.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/onerror.js (renamed from trunk/infrastructure/framework-src/onerror.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/onprint.js (renamed from trunk/infrastructure/framework-src/onprint.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/onrequest.js (renamed from trunk/infrastructure/framework-src/onrequest.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/onreset.js (renamed from trunk/infrastructure/framework-src/onreset.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/onsars.js (renamed from trunk/infrastructure/framework-src/onsars.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/onscheduledtask.js (renamed from trunk/infrastructure/framework-src/onscheduledtask.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/onshutdown.js (renamed from trunk/infrastructure/framework-src/onshutdown.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/onstartup.js (renamed from trunk/infrastructure/framework-src/onstartup.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/onsyntaxerror.js (renamed from trunk/infrastructure/framework-src/onsyntaxerror.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/postamble.js (renamed from trunk/infrastructure/framework-src/postamble.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/preamble.js (renamed from trunk/infrastructure/framework-src/preamble.js) | 0 | ||||
-rw-r--r-- | infrastructure/framework-src/syntaxerror.js (renamed from trunk/infrastructure/framework-src/syntaxerror.js) | 0 |
45 files changed, 1522 insertions, 0 deletions
diff --git a/trunk/infrastructure/framework-src/modules/atomfeed.js b/infrastructure/framework-src/modules/atomfeed.js index 4b86eeb..4b86eeb 100644 --- a/trunk/infrastructure/framework-src/modules/atomfeed.js +++ b/infrastructure/framework-src/modules/atomfeed.js diff --git a/trunk/infrastructure/framework-src/modules/blob.js b/infrastructure/framework-src/modules/blob.js index af788a0..af788a0 100644 --- a/trunk/infrastructure/framework-src/modules/blob.js +++ b/infrastructure/framework-src/modules/blob.js diff --git a/trunk/infrastructure/framework-src/modules/cache_utils.js b/infrastructure/framework-src/modules/cache_utils.js index f2a360c..f2a360c 100644 --- a/trunk/infrastructure/framework-src/modules/cache_utils.js +++ b/infrastructure/framework-src/modules/cache_utils.js diff --git a/trunk/infrastructure/framework-src/modules/comet.js b/infrastructure/framework-src/modules/comet.js index 2331f8b..2331f8b 100644 --- a/trunk/infrastructure/framework-src/modules/comet.js +++ b/infrastructure/framework-src/modules/comet.js diff --git a/trunk/infrastructure/framework-src/modules/dateutils.js b/infrastructure/framework-src/modules/dateutils.js index 72e87c8..72e87c8 100644 --- a/trunk/infrastructure/framework-src/modules/dateutils.js +++ b/infrastructure/framework-src/modules/dateutils.js diff --git a/trunk/infrastructure/framework-src/modules/dispatch.js b/infrastructure/framework-src/modules/dispatch.js index e7e3ef0..e7e3ef0 100644 --- a/trunk/infrastructure/framework-src/modules/dispatch.js +++ b/infrastructure/framework-src/modules/dispatch.js diff --git a/infrastructure/framework-src/modules/ejs.js b/infrastructure/framework-src/modules/ejs.js new file mode 100644 index 0000000..58c67bc --- /dev/null +++ b/infrastructure/framework-src/modules/ejs.js @@ -0,0 +1,477 @@ +/*-------------------------------------------------------------------------- + * EJS - Embedded JavaScript, version 0.1.0 + * Copyright (c) 2007 Edward Benson + * http://www.edwardbenson.com/projects/ejs + * ------------------------------------------------------------------------ + * + * EJS is freely distributable under the terms of an MIT-style license. + * + * EJS is a client-side preprocessing engine written in and for JavaScript. + * If you have used PHP, ASP, JSP, or ERB then you get the idea: code embedded + * in <% // Code here %> tags will be executed, and code embedded in <%= .. %> + * tags will be evaluated and appended to the output. + * + * This is essentially a direct JavaScript port of Masatoshi Seki's erb.rb + * from the Ruby Core, though it contains a subset of ERB's functionality. + * + * Requirements: + * prototype.js + * + * Usage: + * // source should be either a string or a DOM node whose innerHTML + * // contains EJB source. + * var source = "<% var ejb="EJB"; %><h1>Hello, <%= ejb %>!</h1>"; + * var compiler = new EjsCompiler(source); + * compiler.compile(); + * var output = eval(compiler.out); + * alert(output); // -> "<h1>Hello, EJB!</h1>" + * + * For a demo: see demo.html + * For the license: see license.txt + * + *--------------------------------------------------------------------------*/ + +import("jsutils.*"); +import("funhtml"); +import("etherpad.log"); + +jimport("java.lang.System.out.println"); +jimport("net.appjet.ajstdlib.execution.executeCodeInNewScope"); + +/* Make a split function like Ruby's: "abc".split(/b/) -> ['a', 'b', 'c'] */ +function rsplit(x, regex) { + var item = x; + var result = regex.exec(item); + var retArr = new Array(); + while (result != null) + { + var first_idx = result.index; + var last_idx = regex.lastIndex; + if ((first_idx) != 0) + { + var first_bit = item.substring(0,first_idx); + retArr.push(item.substring(0,first_idx)); + item = item.slice(first_idx); + } + retArr.push(result[0]); + item = item.slice(result[0].length); + result = regex.exec(item); + } + if (! item == '') + { + retArr.push(item); + } + return retArr; +}; + +/* Chop is nice to have too */ +function chop(x) { + return x.substr(0, x.length - 1); +} + +/* Adaptation from the Scanner of erb.rb */ +var EjsScanner = function(source, left, right) { + this.left_delimiter = left +'%'; //<% + this.right_delimiter = '%'+right; //> + this.double_left = left+'%%'; + this.double_right = '%%'+right; + this.left_equal = left+'%='; + this.left_colon = left+'%:'; + this.left_comment = left+'%#'; + if(left=='[') { + this.SplitRegexp = /(\[%%)|(%%\])|(\[%:)|(\[%=)|(\[%#)|(\[%)|(%\]\n)|(%\])|(\n)/; + } + else { + this.SplitRegexp = new RegExp('('+this.double_left+')|(%%'+this.double_right+')|('+this.left_equal+')|('+this.left_colon+')|('+this.left_equal+')|('+this.left_comment+')|('+this.left_delimiter+')|('+this.right_delimiter+'\n)|('+this.right_delimiter+')|(\n)') + } + + this.source = source; + this.stag = null; + this.lines = 0; +}; +EjsView = function(data) { + this.data = data; +}; +EjsView.prototype.partial = function(options, data){ + if(!data) data = this.data; + return new EJS(options).render(data); +}; + +EjsScanner.to_text = function(input){ + if(input == null || input === undefined) + return ''; + if(input instanceof Date) + return input.toDateString(); + if(input.toString) + return input.toString(); + return ''; +} + +EjsScanner.prototype = { + + /* For each line, scan! */ + scan: function(block) { + scanline = this.scanline; + regex = this.SplitRegexp; + if (! this.source == '') + { + var source_split = rsplit(this.source, /\n/); + for(var i=0; i<source_split.length; i++) { + var item = source_split[i]; + this.scanline(item, regex, block); + } + } + }, + + /* For each token, block! */ + scanline: function(line, regex, block) { + this.lines++; + var line_split = rsplit(line, regex); + for(var i=0; i<line_split.length; i++) { + var token = line_split[i]; + if (token != null) { + try{ + block(token, this); + }catch(e){ + throw {type: 'EjsScanner', line: this.lines}; + } + } + } + } +}; + +/* Adaptation from the Buffer of erb.rb */ +var EjsBuffer = function(pre_cmd, post_cmd) { + this.line = new Array(); + this.script = ""; + this.pre_cmd = pre_cmd; + this.post_cmd = post_cmd; + + for (var i=0; i<this.pre_cmd.length; i++) + { + this.push(pre_cmd[i]); + } +} +EjsBuffer.prototype = { + + push: function(cmd) { + this.line.push(cmd); + }, + + cr: function() { + this.script = this.script + this.line.join('; '); + this.line = new Array(); + this.script = this.script + "\n"; + }, + + close: function() { + if (this.line.length > 0) + { + for (var i=0; i<this.post_cmd.length; i++) + { + this.push(pre_cmd[i]); + } + this.script = this.script + this.line.join('; '); + line = null; + } + } + +}; + +/* Adaptation from the Compiler of erb.rb */ +EjsCompiler = function(source, left) { + this.pre_cmd = ['var ejs_data = "";']; + this.post_cmd = new Array(); + this.source = ' '; + if (source != null) + { + if (typeof source == 'string') + { + source = source.replace(/\r\n/g, "\n"); + source = source.replace(/\r/g, "\n"); + this.source = source; + } + else if (source.innerHTML) + { + this.source = source.innerHTML; + } + if (typeof this.source != 'string') + { + this.source = ""; + } + } + left = left || '<' + var right = '>' + switch(left) { + case '[': + right = ']' + break; + case '<': + break; + default: + throw left+' is not a supported deliminator' + break; + } + this.scanner = new EjsScanner(this.source, left, right); + this.out = ''; +} +EjsCompiler.prototype = { + compile: function(options) { + options = options || {}; + this.out = ''; + var put_cmd = "ejs_data += "; + var insert_cmd = put_cmd; + var buff = new EjsBuffer(this.pre_cmd, this.post_cmd); + var content = ''; + var clean = function(content) + { + content = content.replace(/\\/g, '\\\\'); + content = content.replace(/\n/g, '\\n'); + content = content.replace(/\"/g, '\\"'); + return content; + }; + this.scanner.scan(function(token, scanner) { + if (scanner.stag == null) + { + //alert(token+'|'+(token == "\n")) + switch(token) { + case '\n': + content = content + "\n"; + buff.push(put_cmd + '"' + clean(content) + '";'); + buff.cr(); + content = ''; + break; + case scanner.left_delimiter: + case scanner.left_equal: + case scanner.left_colon: + case scanner.left_comment: + scanner.stag = token; + if (content.length > 0) + { + // Chould be content.dump in Ruby + + buff.push(put_cmd + '"' + clean(content) + '"'); + } + content = ''; + break; + case scanner.double_left: + content = content + scanner.left_delimiter; + break; + default: + content = content + token; + break; + } + } + else { + switch(token) { + case scanner.right_delimiter: + switch(scanner.stag) { + case scanner.left_delimiter: + if (content[content.length - 1] == '\n') + { + content = chop(content); + buff.push(content); + buff.cr(); + } + else { + buff.push(content); + } + break; + case scanner.left_equal: + buff.push(insert_cmd + "(EjsScanner.to_text(" + content + "))"); + break; + case scanner.left_colon: + buff.push(insert_cmd + content); + break; + } + scanner.stag = null; + content = ''; + break; + case scanner.double_right: + content = content + scanner.right_delimiter; + break; + default: + content = content + token; + break; + } + } + }); + if (content.length > 0) + { + // Chould be content.dump in Ruby + buff.push(put_cmd + '"' + clean(content) + '"'); + } + buff.close(); + this.out = buff.script + ";"; + var to_be_evaled = [ + 'var process = function(_CONTEXT,_VIEW) {', + ' with(_VIEW) {', + ' with (_CONTEXT) {', + this.out, + ' return ejs_data;', + ' }', + ' }', + '};' + ].join(''); + // make funhtml.* available in parent scope. + var parentScope = {}; + parentScope.EjsScanner = EjsScanner; + keys(funhtml).forEach(function(k) { + parentScope[k] = funhtml[k]; + }); + var ret = executeCodeInNewScope( + parentScope, + to_be_evaled, + (options.name || "template"), + 1 + ); + this.process = ret.process; + } +} + + +//type, cache, folder +EJS = function( options ){ + this.set_options(options); + + if(options.url){ + var template = EJS.get(options.url, this.cache); + if (template) return template; + if (template == EJS.INVALID_PATH) return null; + this.text = EJS.request(options.url); + if(this.text == null){ + //EJS.update(options.url, this.INVALID_PATH); + throw 'There is no template at '+options.url; + } + this.name = options.url; + }else if(options.element) + { + if(typeof options.element == 'string'){ + var name = options.element; + options.element = document.getElementById( options.element ); + if(options.element == null) throw name+'does not exist!'; + } + if(options.element.value){ + this.text = options.element.value; + }else{ + this.text = options.element.innerHTML; + } + this.name = options.element.id; + this.type = '['; + } + var template = new EjsCompiler(this.text, this.type); + + template.compile(options); + + + EJS.update(this.name, this); + this.template = template; +}; +EJS.config = function(options){ + EJS.cache = options.cache != null ? options.cache : EJS.cache; + EJS.type = options.type != null ? options.type : EJS.type; + var templates_directory = {}; //nice and private container + + EJS.get = function(path, cache){ + if(cache == false) return null; + if(templates_directory[path]) return templates_directory[path]; + return null; + }; + + EJS.update = function(path, template) { + if(path == null) return; + templates_directory[path] = template; + }; + + EJS.INVALID_PATH = -1; + + +}; +EJS.config( {cache: true, type: '<' } ); + +EJS.prototype = { + render : function(object){ + var v = new EjsView(object); + return this.template.process.call(v, object, v); + }, + out : function(){ + return this.template.out; + }, + set_options : function(options){ + this.type = options.type != null ? options.type : EJS.type; + this.cache = options.cache != null ? options.cache : EJS.cache; + this.text = options.text != null ? options.text : null; + this.name = options.name != null ? options.name : null; + }, + // called without options, returns a function that takes the object + // called with options being a string, uses that as a url + // called with options as an object + update : function(element, options){ + if(typeof element == 'string'){ + element = document.getElementById(element); + } + if(options == null){ + _template = this; + return function(object){ + EJS.prototype.update.call(_template, element, object); + }; + } + if(typeof options == 'string'){ + params = {}; + params.url = options; + _template = this; + params.onComplete = function(request){ + var object = eval( request.responseText ); + EJS.prototype.update.call(_template, element, object); + }; + EJS.ajax_request(params); + }else + { + element.innerHTML = this.render(options); + } + } +}; + + EJS.newRequest = function(){ + var factories = [function() { return new ActiveXObject("Msxml2.XMLHTTP"); },function() { return new XMLHttpRequest(); },function() { return new ActiveXObject("Microsoft.XMLHTTP"); }]; + for(var i = 0; i < factories.length; i++) { + try { + var request = factories[i](); + if (request != null) return request; + } + catch(e) { continue;} + } + }; + + EJS.request = function(path){ + var request = new EJS.newRequest(); + request.open("GET", path, false); + + try{request.send(null);} + catch(e){return null;} + + if ( request.status == 404 || request.status == 2 ||(request.status == 0 && request.responseText == '') ) return null; + + return request.responseText + }; + EJS.ajax_request = function(params){ + params.method = ( params.method ? params.method : 'GET'); + + var request = new EJS.newRequest(); + request.onreadystatechange = function(){ + if(request.readyState == 4){ + if(request.status == 200){ + params.onComplete(request); + }else + { + params.onComplete(request); + } + } + }; + request.open(params.method, params.url); + request.send(null); + }; + +//} + + diff --git a/trunk/infrastructure/framework-src/modules/email.js b/infrastructure/framework-src/modules/email.js index 2d81dc3..2d81dc3 100644 --- a/trunk/infrastructure/framework-src/modules/email.js +++ b/infrastructure/framework-src/modules/email.js diff --git a/trunk/infrastructure/framework-src/modules/exceptionutils.js b/infrastructure/framework-src/modules/exceptionutils.js index b572a3a..b572a3a 100644 --- a/trunk/infrastructure/framework-src/modules/exceptionutils.js +++ b/infrastructure/framework-src/modules/exceptionutils.js diff --git a/infrastructure/framework-src/modules/execution.js b/infrastructure/framework-src/modules/execution.js new file mode 100644 index 0000000..2f9d933 --- /dev/null +++ b/infrastructure/framework-src/modules/execution.js @@ -0,0 +1,61 @@ +/** + * Copyright 2009 Google Inc. + * + * Licensed 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("jsutils.{scalaF0,scalaF1}"); + +/** + * Asynchronously call a function as soon as the current request completes. + **/ +function async(f) { + Packages.net.appjet.ajstdlib.execution.runAsync(appjet.context, f); +} + +function initTaskThreadPool(name, poolSize) { + Packages.net.appjet.ajstdlib.execution.createNamedTaskThreadPool(name, poolSize); +} + +function scheduleTask(poolName, taskName, delayMillis, args) { + return Packages.net.appjet.ajstdlib.execution.scheduleTaskInPool(poolName, taskName, delayMillis, args); +} + +function shutdownAndWaitOnTaskThreadPool(poolName, timeoutMillis) { + return Packages.net.appjet.ajstdlib.execution.shutdownAndWaitOnTaskThreadPool(poolName, timeoutMillis); +} + +function fancyAssEval(initCode, mainCode) { + function init(runner) { + Packages.net.appjet.bodylock.BodyLock.evaluateString( + runner.globalScope(), + initCode, + "eval'd code imports", + 1); + } + var runner = Packages.net.appjet.oui.ScopeReuseManager.getEmpty(scalaF1(init)); + var requestWrapper = null; + if (request.underlying !== undefined) + requestWrapper = new Packages.net.appjet.oui.RequestWrapper(request.underlying); + var ec = new Packages.net.appjet.oui.ExecutionContext( + requestWrapper, + null, runner); + return Packages.net.appjet.oui.ExecutionContextUtils.withContext(ec, + scalaF0(function() { + return Packages.net.appjet.bodylock.BodyLock.evaluateString( + runner.globalScope(), + mainCode, + "eval'd code main", + 1); + })); +}
\ No newline at end of file diff --git a/trunk/infrastructure/framework-src/modules/fastJSON.js b/infrastructure/framework-src/modules/fastJSON.js index 3198b96..3198b96 100644 --- a/trunk/infrastructure/framework-src/modules/fastJSON.js +++ b/infrastructure/framework-src/modules/fastJSON.js diff --git a/infrastructure/framework-src/modules/faststatic.js b/infrastructure/framework-src/modules/faststatic.js new file mode 100644 index 0000000..920be8c --- /dev/null +++ b/infrastructure/framework-src/modules/faststatic.js @@ -0,0 +1,342 @@ +/** + * Copyright 2009 Google Inc. + * + * Licensed 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. + */ + +/** + * @fileOverview serving static files, including js and css, and cacheing + * and minifying. + * + * Terminology Note: + * "path" is confusing because paths can be part of URLs and part + * of filesystem paths, and static files have both types of paths + * associated with them. Therefore, in this module: + * + * LOCALDIR or LOCALFILE refers to directories or files on the filesystem. + * + * HREF is used to describe things that go in a URL. + */ + +import("fileutils.{readFile,readFileBytes}"); +import("yuicompressor"); +import("stringutils"); +import("varz"); +import("ejs.EJS"); + +jimport("java.lang.System.out.println"); + +//---------------------------------------------------------------- +// Content Type Guessing +//---------------------------------------------------------------- + +var _contentTypes = { + 'gif': 'image/gif', + 'png': 'image/png', + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'css': 'text/css', + 'js': 'application/x-javascript', + 'txt': 'text/plain', + 'html': 'text/html; charset=utf-8', + 'ico': 'image/x-icon', + 'swf': 'application/x-shockwave-flash', + 'zip': 'application/zip', + 'xml': 'application/xml' +}; + +var _gzipableTypes = { + 'text/css': true, + 'application/x-javascript': true, + 'text/html; charset=utf-8': true +}; + +function _guessContentType(path) { + var ext = path.split('.').pop().toLowerCase(); + return _contentTypes[ext] || 'text/plain'; +} + +//---------------------------------------------------------------- + +function _getCache(name) { + var m = 'faststatic'; + if (!appjet.cache[m]) { + appjet.cache[m] = {}; + } + var c = appjet.cache[m]; + if (!c[name]) { + c[name] = {}; + } + return c[name]; +} + +var _mtimeCheckInterval = 5000; // 5 seconds + +function _getMTime(f) { + var mcache = _getCache('mtimes'); + var now = +(new Date); + if (appjet.config.devMode || + !(mcache[f] && (now - mcache[f].lastCheck < _mtimeCheckInterval))) { + var jfile = new net.appjet.oui.JarVirtualFile(f); + if (jfile.exists() && !jfile.isDirectory()) { + mcache[f] = { + lastCheck: now, + mtime: jfile.lastModified() + }; + } else { + mcache[f] = null; + } + } + if (mcache[f]) { + return +mcache[f].mtime; + } else { + return null; + } +} + +function manglePluginPath(localFile, fileType) { + var prefix = '/static/' + fileType + '/plugins/'; + if (localFile.substring(0, prefix.length) != prefix) + return localFile; + var suffix = localFile.substring(prefix.length); + var plugin = suffix.split('/', 1)[0]; + suffix = suffix.substring(plugin.length + 1); + return '/plugins/' + plugin + '/static/' + fileType + '/' + suffix; +} + +function manglePluginPaths(localFile) { + return manglePluginPath( + manglePluginPath( + manglePluginPath( + manglePluginPath( + manglePluginPath( + localFile, + 'js'), + 'css'), + 'swf'), + 'html'), + 'zip'); +} + +function _wrapFile(localFile) { + return { + getPath: function() { return localFile; }, + getMTime: function() { return _getMTime(localFile); }, + getContents: function() { return _readFileAndProcess(manglePluginPaths(localFile), 'string'); } + }; +} + +function _readFileAndProcess(fileName, type) { + if (fileName.slice(-8) == "_ejs.css") { + // run CSS through EJS + var template = readFile(fileName); + var ejs = new EJS({text:template, name:fileName}); + var resultString = ejs.render({}); + if (type == 'bytes') { + return new java.lang.String(resultString).getBytes("UTF-8"); + } + else { + return resultString; + } + } + else if (type == 'string') { + return readFile(fileName); + } + else if (type == 'bytes') { + return readFileBytes(fileName); + } +} + +function _cachedFileBytes(f) { + var mtime = _getMTime(f); + if (!mtime) { return null; } + var fcache = _getCache('file-bytes-cache'); + if (!(fcache[f] && (fcache[f].mtime == mtime))) { + varz.incrementInt("faststatic-file-bytes-cache-miss"); + var bytes = _readFileAndProcess(f, 'bytes'); + if (bytes) { + fcache[f] = {mtime: mtime, bytes: bytes}; + }; + } + if (fcache[f] && fcache[f].bytes) { + return fcache[f].bytes; + } else { + return null; + } +} + +function _shouldGzip(contentType) { + var userAgent = request.headers["User-Agent"]; + if (! userAgent) return false; + if (! (/Firefox/.test(userAgent) || /webkit/i.test(userAgent))) return false; + if (! _gzipableTypes[contentType]) return false; + + return request.acceptsGzip; +} + +function _getCachedGzip(original, key) { + var c = _getCache("gzipped"); + if (! c[key] || ! java.util.Arrays.equals(c[key].original, original)) { + c[key] = {original: original, + gzip: stringutils.gzip(original)}; + } + return c[key].gzip; +} + +function _setGzipHeader() { + response.setHeader("Content-Encoding", "gzip"); +} + +//---------------------------------------------------------------- + +/** + * Function for serving a single static file. + */ +function singleFileServer(localPath, opts) { + var contentType = _guessContentType(localPath); + + return function() { + (opts.cache ? response.alwaysCache() : response.neverCache()); + response.setContentType(contentType); + var bytes = _cachedFileBytes(localPath); + if (bytes) { + if (_shouldGzip(contentType)) { + bytes = _getCachedGzip(bytes, "file:"+localPath); + _setGzipHeader(); + } + response.writeBytes(bytes); + return true; + } else { + return false; + } + }; +} + +/** + * valid opts: + * alwaysCache: default false + */ +function directoryServer(localDir, opts) { + if (stringutils.endsWith(localDir, "/")) { + localDir = localDir.substr(0, localDir.length-1); + } + return function(relpath) { + if (stringutils.startsWith(relpath, "/")) { + relpath = relpath.substr(1); + } + if (relpath.indexOf('..') != -1) { + response.forbid(); + } + (opts.cache ? response.alwaysCache() : response.neverCache()); + var contentType = _guessContentType(relpath); + response.setContentType(contentType); + var fullPath = localDir + "/" + relpath; + var bytes = _cachedFileBytes(fullPath); + + if (bytes) { + if (_shouldGzip(contentType)) { + bytes = _getCachedGzip(bytes, "file:"+fullPath); + _setGzipHeader(); + } + response.writeBytes(bytes); + return true; + } else { + return false; + } + }; +} + +/** + * Serves cat files, which are concatenated versions of many files. + */ +function compressedFileServer(opts) { + var cfcache = _getCache('compressed-files'); + return function() { + var key = request.path.split('/').slice(-1)[0]; + var contentType = _guessContentType(request.path); + response.setContentType(contentType); + response.alwaysCache(); + var data = cfcache[key]; + if (data) { + if (_shouldGzip(contentType)) { + data = _getCachedGzip((new java.lang.String(data)).getBytes(response.getCharacterEncoding()), "comp:"+key); + _setGzipHeader(); + response.writeBytes(data); + } else { + response.write(data); + } + return true; + } else { + return false; + } + }; +} + +function getCompressedFilesKey(type, baseLocalDir, localFileList) { + if (stringutils.endsWith(baseLocalDir, '/')) { + baseLocalDir = baseLocalDir.substr(0, baseLocalDir.length-1); + } + + var fileList = []; + // convert passed-in file list into list of our file objects + localFileList.forEach(function(f) { + if (typeof(f) == 'string') { + fileList.push(_wrapFile(baseLocalDir+'/'+f)); + } else { + fileList.push(f); + } + }); + + // have we seen this exact fileset before? + var fsId = fileList.map(function(f) { return f.getPath(); }).join('|'); + var fsMTime = Math.max.apply(this, + fileList.map(function(f) { return f.getMTime(); })); + + var kdcache = _getCache('fileset-keydata-cache'); + if (!(kdcache[fsId] && (kdcache[fsId].mtime == fsMTime))) { + //println("cache miss for fileset: "+fsId); + //println("compressing fileset..."); + kdcache[fsId] = { + mtime: fsMTime, + keyString: _compressFilesAndMakeKey(type, fileList) + }; + } + return kdcache[fsId].keyString; +} + +function _compressFilesAndMakeKey(type, fileList) { + function _compress(s) { + if (type == 'css') { + varz.incrementInt("faststatic-yuicompressor-compressCSS"); + return yuicompressor.compressCSS(s); + } else if (type == 'js') { + varz.incrementInt("faststatic-yuicompressor-compressJS"); + return yuicompressor.compressJS(s); + } else { + throw Error('Dont know how to compress this filetype: '+type); + } + } + + var fullstr = ""; + fileList.forEach(function(f) { + fullstr += _compress(f.getContents()); + }); + + fullstr = _compress(fullstr); + + var key = stringutils.md5(fullstr) + '.' + type; + var cfcache = _getCache('compressed-files'); + cfcache[key] = fullstr; + return key; +} + diff --git a/trunk/infrastructure/framework-src/modules/fileutils.js b/infrastructure/framework-src/modules/fileutils.js index aaf12e2..aaf12e2 100644 --- a/trunk/infrastructure/framework-src/modules/fileutils.js +++ b/infrastructure/framework-src/modules/fileutils.js diff --git a/trunk/infrastructure/framework-src/modules/funhtml.js b/infrastructure/framework-src/modules/funhtml.js index c27b667..c27b667 100644 --- a/trunk/infrastructure/framework-src/modules/funhtml.js +++ b/infrastructure/framework-src/modules/funhtml.js diff --git a/trunk/infrastructure/framework-src/modules/global/appjet.js b/infrastructure/framework-src/modules/global/appjet.js index 135ac44..135ac44 100644 --- a/trunk/infrastructure/framework-src/modules/global/appjet.js +++ b/infrastructure/framework-src/modules/global/appjet.js diff --git a/trunk/infrastructure/framework-src/modules/global/request.js b/infrastructure/framework-src/modules/global/request.js index a4327f9..a4327f9 100644 --- a/trunk/infrastructure/framework-src/modules/global/request.js +++ b/infrastructure/framework-src/modules/global/request.js diff --git a/trunk/infrastructure/framework-src/modules/global/response.js b/infrastructure/framework-src/modules/global/response.js index 7236920..7236920 100644 --- a/trunk/infrastructure/framework-src/modules/global/response.js +++ b/infrastructure/framework-src/modules/global/response.js diff --git a/trunk/infrastructure/framework-src/modules/image.js b/infrastructure/framework-src/modules/image.js index 8aec74b..8aec74b 100644 --- a/trunk/infrastructure/framework-src/modules/image.js +++ b/infrastructure/framework-src/modules/image.js diff --git a/trunk/infrastructure/framework-src/modules/jsutils.js b/infrastructure/framework-src/modules/jsutils.js index 02f81a2..02f81a2 100644 --- a/trunk/infrastructure/framework-src/modules/jsutils.js +++ b/infrastructure/framework-src/modules/jsutils.js diff --git a/trunk/infrastructure/framework-src/modules/netutils.js b/infrastructure/framework-src/modules/netutils.js index 6616b76..6616b76 100644 --- a/trunk/infrastructure/framework-src/modules/netutils.js +++ b/infrastructure/framework-src/modules/netutils.js diff --git a/infrastructure/framework-src/modules/process.js b/infrastructure/framework-src/modules/process.js new file mode 100644 index 0000000..48ab62e --- /dev/null +++ b/infrastructure/framework-src/modules/process.js @@ -0,0 +1,91 @@ +/** + * Simple way to execute external commands through javascript + * + * @example + cmd = exec("cat"); + System.out.println("First: " +cmd.write("this is a loop.").read(Process.READ_AVAILABLE)); // prints "this is a loop." + System.out.println("Second: " +cmd.writeAndClose(" hi there").result()); // prints "this is a loop. hi there" + * + */ + +jimport("java.lang.Runtime"); +jimport("java.io.BufferedInputStream"); +jimport("java.io.BufferedOutputStream"); +jimport("java.lang.System"); + +/* returns a process */ +function exec(process) { + return new Process(process); +}; + +function Process(cmd) { + this.cmd = cmd; + this.proc = Runtime.getRuntime().exec(cmd); + this.resultText = ""; + this.inputStream = new BufferedInputStream(this.proc.getInputStream()); + this.errorStream = new BufferedInputStream(this.proc.getErrorStream()); + this.outputStream = new BufferedOutputStream(this.proc.getOutputStream()); +} + +Process.CHUNK_SIZE = 1024; +Process.READ_ALL = -1; +Process.READ_AVAILABLE = -2; + +Process.prototype.write = function(stdinText) { + this.outputStream.write(new java.lang.String(stdinText).getBytes()); + this.outputStream.flush(); + return this; +}; + +Process.prototype.writeAndClose = function(stdinText) { + this.write(stdinText); + this.outputStream.close(); + return this; +}; + +/* Python file-like behavior: read specified number of bytes, else until EOF*/ +Process.prototype.read = function(nbytesToRead, stream) { + var inputStream = stream || this.inputStream; + var availBytes = inputStream.available(); + if (!availBytes) return null; + + var result = ""; + var nbytes = nbytesToRead || Process.READ_ALL; + var readAll = (nbytes == Process.READ_ALL); + var readAvailable = (nbytes == Process.READ_AVAILABLE); + while (nbytes > 0 || readAll || readAvailable) { + var chunkSize = readAll ? Process.CHUNK_SIZE : + readAvailable ? Process.CHUNK_SIZE : nbytes; + + // allocate a java byte array + var bytes = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, chunkSize); + + var len = inputStream.read(bytes, 0, chunkSize); + + // at end of stream, or when we run out of data, stop reading in chunks. + if (len == -1) break; + if (nbytes > 0) nbytes -= len; + + result += new java.lang.String(bytes); + + if (readAvailable && inputStream.available() == 0) break; + } + + this.resultText += new String(result); + return new String(result); +}; + +Process.prototype.result = function() { + this.outputStream.close(); + this.proc.waitFor(); + this.read(Process.READ_ALL, this.inputStream); + return new String(this.resultText); +}; + +Process.prototype.resultOrError = function() { + this.proc.waitFor(); + this.read(Process.READ_ALL, this.inputStream); + var result = this.resultText; + if(!result || result == "") result = this.read(Process.READ_ALL, this.errorStream); + return result || ""; +}; diff --git a/trunk/infrastructure/framework-src/modules/profiler.js b/infrastructure/framework-src/modules/profiler.js index 223c197..223c197 100644 --- a/trunk/infrastructure/framework-src/modules/profiler.js +++ b/infrastructure/framework-src/modules/profiler.js diff --git a/trunk/infrastructure/framework-src/modules/sessions.js b/infrastructure/framework-src/modules/sessions.js index 3d0041b..3d0041b 100644 --- a/trunk/infrastructure/framework-src/modules/sessions.js +++ b/infrastructure/framework-src/modules/sessions.js diff --git a/trunk/infrastructure/framework-src/modules/sqlbase/persistent_vars.js b/infrastructure/framework-src/modules/sqlbase/persistent_vars.js index 1c4cc95..1c4cc95 100644 --- a/trunk/infrastructure/framework-src/modules/sqlbase/persistent_vars.js +++ b/infrastructure/framework-src/modules/sqlbase/persistent_vars.js diff --git a/trunk/infrastructure/framework-src/modules/sqlbase/sqlbase.js b/infrastructure/framework-src/modules/sqlbase/sqlbase.js index 3df1a0f..3df1a0f 100644 --- a/trunk/infrastructure/framework-src/modules/sqlbase/sqlbase.js +++ b/infrastructure/framework-src/modules/sqlbase/sqlbase.js diff --git a/trunk/infrastructure/framework-src/modules/sqlbase/sqlcommon.js b/infrastructure/framework-src/modules/sqlbase/sqlcommon.js index 360f5e2..360f5e2 100644 --- a/trunk/infrastructure/framework-src/modules/sqlbase/sqlcommon.js +++ b/infrastructure/framework-src/modules/sqlbase/sqlcommon.js diff --git a/infrastructure/framework-src/modules/sqlbase/sqlobj.js b/infrastructure/framework-src/modules/sqlbase/sqlobj.js new file mode 100644 index 0000000..e599c92 --- /dev/null +++ b/infrastructure/framework-src/modules/sqlbase/sqlobj.js @@ -0,0 +1,551 @@ +/** + * Copyright 2009 Google Inc. + * + * Licensed 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("cache_utils.syncedWithCache"); +import("sqlbase.sqlcommon.*"); +import("jsutils.*"); +import("etherpad.log"); + +jimport("java.lang.System.out.println"); +jimport("java.sql.Statement"); + +function _withCache(name, fn) { + return syncedWithCache('sqlobj.'+name, fn); +} + +function getIdColspec() { + return ('INT NOT NULL '+autoIncrementClause()+' PRIMARY KEY'); +} + +function getLongtextColspec(extra) { + var spec = getSqlBase().longTextType(); + if (extra) { + spec = (spec + " " + extra); + } + return spec; +} + +function getBoolColspec(extra) { + var spec; + if (isMysql()) { + spec = 'TINYINT(1)'; + } else { + spec = 'SMALLINT'; + } + if (extra) { + spec = (spec + " " + extra); + } + return spec; +} + +function getDateColspec(extra) { + var spec; + if (isMysql()) { + spec = 'DATETIME'; + } else { + spec = 'TIMESTAMP'; + } + if (extra) { + spec = (spec + " " + extra); + } + return spec; +} + +function _bq(x) { return btquote(x); } + +/* + * for debugging queries + */ +function _qdebug(q) { + if (appjet.config.debugSQL) { + println(q); + } +} + +/** executeFn is either "execute" or "executeUpdate" "executeQuery" */ +function _execute(stmnt, executeFn) { + if (!executeFn) { + executeFn = 'execute'; + } + return withConnection(function(conn) { + var pstmnt = conn.prepareStatement(stmnt); + return closing(pstmnt, function() { + _qdebug(stmnt); + return pstmnt[executeFn](); + }); + }); +} + +function _executeUpdate(stmnt) { + return _execute(stmnt, 'executeUpdate'); +} + +function _executeQuery(stmnt) { + return _execute(stmnt, 'executeQuery'); +} + +/* + * Not all SQL/JS types supported. + */ +function _getJsValFromResultSet(rs, type, colName) { + var r; + if (type == java.sql.Types.VARCHAR || + type == java.sql.Types.LONGVARCHAR || + type == java.sql.Types.CHAR) { + r = String(rs.getString(colName)); + } else if (type == java.sql.Types.TIMESTAMP) { + var t = rs.getTimestamp(colName); + if (t) { + r = new Date(t.getTime()); + } else { + r = null; + } + } else if (type == java.sql.Types.BIGINT || + type == java.sql.Types.INTEGER || + type == java.sql.Types.SMALLINT || + type == java.sql.Types.TINYINT) { + r = rs.getInt(colName); + } else if (type == java.sql.Types.DECIMAL) { + r = rs.getFloat(colName); + } else if (type == java.sql.Types.BIT) { + r = rs.getBoolean(colName); + } else { + throw Error("Cannot fetch sql type ID "+type+" (columnName = "+colName+")"); + } + + if (rs.wasNull()) { + r = null; + } + return r; +} + +function _lookupColumnType(tableName, columnName) { + return withConnection(function(conn) { + var metadata = conn.getMetaData(); + var rs = metadata.getColumns(null, null, tableName, columnName); + if (!rs) { + throw Error("Table '"+tableName+"' does not appear to have colum '"+columnName+"'."); + } + var rsmd = rs.getMetaData(); + var colCount = rsmd.getColumnCount(); +// rs.first(); + rs.next(); + var type = rs.getInt("DATA_TYPE"); + return type; + }); +} + +/* cached, on misses calls _lookuParameterType */ +function _getParameterType(tableName, columnName) { + var key = [tableName, columnName].join("."); + return _withCache('column-types', function(cache) { + if (!cache[key]) { + cache[key] = _lookupColumnType(tableName, columnName); + } + return cache[key]; + }); +} + +/* + * Not all SQL/JS types supported. + */ +function _setPreparedValues(tableName, pstmnt, keyList, obj, indexOffset) { + if (!indexOffset) { indexOffset = 0; } + + for (var i = 1; i <= keyList.length; i++) { + var k = keyList[i-1]; + var v = obj[k]; + var j = i + indexOffset; + + if (v === undefined) { + throw Error("value is undefined for key "+k); + } + + if (v === null) { + var type = _getParameterType(tableName, k); + pstmnt.setNull(j, type); + } else if (typeof(v) == 'string') { + pstmnt.setString(j, v); + } else if (typeof(v) == 'number') { + pstmnt.setInt(j, v); + } else if (typeof(v) == 'boolean') { + pstmnt.setBoolean(j, v); + } else if (v.valueOf && v.getDate && v.getHours) { + pstmnt.setTimestamp(j, new java.sql.Timestamp(+v)); + } else { + throw Error("Cannot insert this type of javascript object: "+typeof(v)+" (key="+k+", value = "+v+")"); + } + } +} + +function _resultRowToJsObj(resultSet) { + var resultObj = {}; + + var metaData = resultSet.getMetaData(); + var colCount = metaData.getColumnCount(); + + for (var i = 1; i <= colCount; i++) { + var colName = metaData.getColumnLabel(i); + var type = metaData.getColumnType(i); + resultObj[colName] = _getJsValFromResultSet(resultSet, type, colName); + } + + return resultObj; +} + +/* + * Inserts the object into the given table, and returns auto-incremented ID if any. + */ +function insert(tableName, obj) { + var keyList = keys(obj); + + var stmnt = "INSERT INTO "+_bq(tableName)+" ("; + stmnt += keyList.map(function(k) { return _bq(k); }).join(', '); + stmnt += ") VALUES ("; + stmnt += keyList.map(function(k) { return '?'; }).join(', '); + stmnt += ")"; + + return withConnection(function(conn) { + var pstmnt = conn.prepareStatement(stmnt, Statement.RETURN_GENERATED_KEYS); + return closing(pstmnt, function() { + _setPreparedValues(tableName, pstmnt, keyList, obj, 0); + _qdebug(stmnt); + pstmnt.executeUpdate(); + var rs = pstmnt.getGeneratedKeys(); + if (rs != null) { + return closing(rs, function() { + if (rs.next()) { + return rs.getInt(1); + } + }); + } + }); + }); +}; + +/* + * Selects a single object given the constraintMap. If there are more + * than 1 objects that match, it will return a single one of them + * (unspecified which one). If no objects match, returns null. + * + * constraints is a javascript object of column names to values. + * Currently only supports string equality of constraints. + */ +function selectSingle(tableName, constraints) { + var keyList = keys(constraints); + + var stmnt = "SELECT * FROM "+_bq(tableName)+" WHERE ("; + stmnt += keyList.map(function(k) { return '('+_bq(k)+' = '+'?)'; }).join(' AND '); + stmnt += ')'; + if (isMysql()) { + stmnt += ' LIMIT 1'; + } + + return withConnection(function(conn) { + var pstmnt = conn.prepareStatement(stmnt); + return closing(pstmnt, function() { + _setPreparedValues(tableName, pstmnt, keyList, constraints, 0); + _qdebug(stmnt); + var resultSet = pstmnt.executeQuery(); + return closing(resultSet, function() { + if (!resultSet.next()) { + return null; + } + return _resultRowToJsObj(resultSet); + }); + }); + }); +} + +function _makeConstraintString(key, value) { + if (typeof(value) != 'object' || ! (value instanceof Array)) { + return '('+_bq(key)+' = ?)'; + } else { + var comparator = value[0]; + return '('+_bq(key)+' '+comparator+' ?)'; + } +} + +function _preparedValuesConstraints(constraints) { + var c = {}; + eachProperty(constraints, function(k, v) { + c[k] = (typeof(v) != 'object' || ! (v instanceof Array) ? v : v[1]); + }); + return c; +} + +function selectMulti(tableName, constraints, options) { + if (!options) { + options = {}; + } + + var constraintKeys = keys(constraints); + + var stmnt = "SELECT * FROM "+_bq(tableName)+" "; + + if (constraintKeys.length > 0) { + stmnt += "WHERE ("; + stmnt += constraintKeys.map(function(key) { + return _makeConstraintString(key, constraints[key]); + }).join(' AND '); + stmnt += ')'; + } + + if (options.orderBy) { + var orderEntries = []; + options.orderBy.split(",").forEach(function(orderBy) { + var asc = "ASC"; + if (orderBy.charAt(0) == '-') { + orderBy = orderBy.substr(1); + asc = "DESC"; + } + orderEntries.push(_bq(orderBy)+" "+asc); + }); + stmnt += " ORDER BY "+orderEntries.join(", "); + } + + if (options.limit) { + stmnt += " LIMIT "+options.limit; + } + + return withConnection(function(conn) { + var pstmnt = conn.prepareStatement(stmnt); + return closing(pstmnt, function() { + _setPreparedValues( + tableName, pstmnt, constraintKeys, + _preparedValuesConstraints(constraints), 0); + + _qdebug(stmnt); + var resultSet = pstmnt.executeQuery(); + var resultArray = []; + + return closing(resultSet, function() { + while (resultSet.next()) { + resultArray.push(_resultRowToJsObj(resultSet)); + } + + return resultArray; + }); + }); + }); +} + +function executeRaw(stmnt, params) { + return withConnection(function(conn) { + var pstmnt = conn.prepareStatement(stmnt); + return closing(pstmnt, function() { + for (var i = 0; i < params.length; i++) { + var v = params[i]; + + if (v === undefined) { + throw Error("value is undefined for key "+i); + } + + if (typeof(v) == 'object' && v.isnull) { + pstmnt.setNull(i+1, v.type); + } else if (typeof(v) == 'string') { + pstmnt.setString(i+1, v); + } else if (typeof(v) == 'number') { + pstmnt.setInt(i+1, v); + } else if (typeof(v) == 'boolean') { + pstmnt.setBoolean(i+1, v); + } else if (v.valueOf && v.getDate && v.getHours) { + pstmnt.setTimestamp(i+1, new java.sql.Timestamp(+v)); + } else { + throw Error("Cannot insert this type of javascript object: "+typeof(v)+" (key="+i+", value = "+v+")"); + } + } + + _qdebug(stmnt); + var resultSet = pstmnt.executeQuery(); + var resultArray = []; + + return closing(resultSet, function() { + while (resultSet.next()) { + resultArray.push(_resultRowToJsObj(resultSet)); + } + + return resultArray; + }); + }); + }); +} + +/* returns number of rows updated */ +function update(tableName, constraints, obj) { + var objKeys = keys(obj); + var constraintKeys = keys(constraints); + + var stmnt = "UPDATE "+_bq(tableName)+" SET "; + stmnt += objKeys.map(function(k) { return ''+_bq(k)+' = ?'; }).join(', '); + stmnt += " WHERE ("; + stmnt += constraintKeys.map(function(k) { return '('+_bq(k)+' = ?)'; }).join(' AND '); + stmnt += ')'; + + return withConnection(function(conn) { + var pstmnt = conn.prepareStatement(stmnt); + return closing(pstmnt, function() { + _setPreparedValues(tableName, pstmnt, objKeys, obj, 0); + _setPreparedValues(tableName, pstmnt, constraintKeys, constraints, objKeys.length); + _qdebug(stmnt); + return pstmnt.executeUpdate(); + }); + }); +} + +function updateSingle(tableName, constraints, obj) { + var count = update(tableName, constraints, obj); + if (count != 1) { + throw Error("save count != 1. instead, count = "+count); + } +} + +function deleteRows(tableName, constraints) { + var constraintKeys = keys(constraints); + var stmnt = "DELETE FROM "+_bq(tableName)+" WHERE ("; + stmnt += constraintKeys.map(function(k) { return '('+_bq(k)+' = ?)'; }).join(' AND '); + stmnt += ')'; + withConnection(function(conn) { + var pstmnt = conn.prepareStatement(stmnt); + closing(pstmnt, function() { + _setPreparedValues(tableName, pstmnt, constraintKeys, constraints); + _qdebug(stmnt); + pstmnt.executeUpdate(); + }); + }) +} + +//---------------------------------------------------------------- +// table management +//---------------------------------------------------------------- + +/* + * Create a SQL table, specifying column names and types with a + * javascript object. + */ +function createTable(tableName, colspec, indices) { + if (doesTableExist(tableName)) { + return; + } + + var stmnt = "CREATE TABLE "+_bq(tableName)+ " ("; + stmnt += keys(colspec).map(function(k) { return (_bq(k) + ' ' + colspec[k]); }).join(', '); + if (indices) { + stmnt += ', ' + keys(indices).map(function(k) { return 'INDEX (' + _bq(k) + ')'; }).join(', '); + } + stmnt += ')'+createTableOptions(); + _execute(stmnt); +} + +function dropTable(tableName) { + _execute("DROP TABLE "+_bq(tableName)); +} + +function dropAndCreateTable(tableName, colspec, indices) { + if (doesTableExist(tableName)) { + dropTable(tableName); + } + + return createTable(tableName, colspec, indices); +} + +function renameTable(oldName, newName) { + _executeUpdate("RENAME TABLE "+_bq(oldName)+" TO "+_bq(newName)); +} + +function modifyColumn(tableName, columnName, newSpec) { + _executeUpdate("ALTER TABLE "+_bq(tableName)+" MODIFY "+_bq(columnName)+" "+newSpec); +} + +function alterColumn(tableName, columnName, alteration) { + var q = "ALTER TABLE "+_bq(tableName)+" ALTER COLUMN "+_bq(columnName)+" "+alteration; + _executeUpdate(q); +} + +function changeColumn(tableName, columnName, newSpec) { + var q = ("ALTER TABLE "+_bq(tableName)+" CHANGE COLUMN "+_bq(columnName) + +" "+newSpec); + _executeUpdate(q); +} + +function addColumns(tableName, colspec) { + inTransaction(function(conn) { + eachProperty(colspec, function(name, definition) { + var stmnt = "ALTER TABLE "+_bq(tableName)+" ADD COLUMN "+_bq(name)+" "+definition; + _executeUpdate(stmnt); + }); + }); +} + +function dropColumn(tableName, columnName) { + var stmnt = "ALTER TABLE "+_bq(tableName)+" DROP COLUMN "+_bq(columnName); + _executeUpdate(stmnt); +} + +function listTables() { + return withConnection(function(conn) { + var metadata = conn.getMetaData(); + var resultSet = metadata.getTables(null, null, null, null); + var resultArray = []; + + return closing(resultSet, function() { + while (resultSet.next()) { + resultArray.push(resultSet.getString("TABLE_NAME")); + } + return resultArray; + }); + }); +} + +function setTableEngine(tableName, engineName) { + var stmnt = "ALTER TABLE "+_bq(tableName)+" ENGINE="+_bq(engineName); + _executeUpdate(stmnt); +} + +function getTableEngine(tableName) { + if (!isMysql()) { + throw Error("getTableEngine() only supported by MySQL database type."); + } + + var tableEngines = {}; + + withConnection(function(conn) { + var stmnt = "show table status"; + var pstmnt = conn.prepareStatement(stmnt); + closing(pstmnt, function() { + _qdebug(stmnt); + var resultSet = pstmnt.executeQuery(); + closing(resultSet, function() { + while (resultSet.next()) { + var n = resultSet.getString("Name"); + var eng = resultSet.getString("Engine"); + tableEngines[n] = eng; + } + }); + }); + }); + + return tableEngines[tableName]; +} + +function createIndex(tableName, columns) { + var indexName = "idx_"+(columns.join("_")); + var stmnt = "CREATE INDEX "+_bq(indexName)+" on "+_bq(tableName)+" ("; + stmnt += columns.map(_bq).join(", "); + stmnt += ")"; + _executeUpdate(stmnt); +} + diff --git a/trunk/infrastructure/framework-src/modules/stringutils.js b/infrastructure/framework-src/modules/stringutils.js index 3fe5611..3fe5611 100644 --- a/trunk/infrastructure/framework-src/modules/stringutils.js +++ b/infrastructure/framework-src/modules/stringutils.js diff --git a/trunk/infrastructure/framework-src/modules/sync.js b/infrastructure/framework-src/modules/sync.js index a222ea0..a222ea0 100644 --- a/trunk/infrastructure/framework-src/modules/sync.js +++ b/infrastructure/framework-src/modules/sync.js diff --git a/trunk/infrastructure/framework-src/modules/timer.js b/infrastructure/framework-src/modules/timer.js index 01be175..01be175 100644 --- a/trunk/infrastructure/framework-src/modules/timer.js +++ b/infrastructure/framework-src/modules/timer.js diff --git a/trunk/infrastructure/framework-src/modules/varz.js b/infrastructure/framework-src/modules/varz.js index 0e55d20..0e55d20 100644 --- a/trunk/infrastructure/framework-src/modules/varz.js +++ b/infrastructure/framework-src/modules/varz.js diff --git a/trunk/infrastructure/framework-src/modules/yuicompressor.js b/infrastructure/framework-src/modules/yuicompressor.js index 572cc0d..572cc0d 100644 --- a/trunk/infrastructure/framework-src/modules/yuicompressor.js +++ b/infrastructure/framework-src/modules/yuicompressor.js diff --git a/trunk/infrastructure/framework-src/oncomet.js b/infrastructure/framework-src/oncomet.js index b6aeda5..b6aeda5 100644 --- a/trunk/infrastructure/framework-src/oncomet.js +++ b/infrastructure/framework-src/oncomet.js diff --git a/trunk/infrastructure/framework-src/onerror.js b/infrastructure/framework-src/onerror.js index f19a85f..f19a85f 100644 --- a/trunk/infrastructure/framework-src/onerror.js +++ b/infrastructure/framework-src/onerror.js diff --git a/trunk/infrastructure/framework-src/onprint.js b/infrastructure/framework-src/onprint.js index 8e334fe..8e334fe 100644 --- a/trunk/infrastructure/framework-src/onprint.js +++ b/infrastructure/framework-src/onprint.js diff --git a/trunk/infrastructure/framework-src/onrequest.js b/infrastructure/framework-src/onrequest.js index d76c8db..d76c8db 100644 --- a/trunk/infrastructure/framework-src/onrequest.js +++ b/infrastructure/framework-src/onrequest.js diff --git a/trunk/infrastructure/framework-src/onreset.js b/infrastructure/framework-src/onreset.js index 24b000a..24b000a 100644 --- a/trunk/infrastructure/framework-src/onreset.js +++ b/infrastructure/framework-src/onreset.js diff --git a/trunk/infrastructure/framework-src/onsars.js b/infrastructure/framework-src/onsars.js index 31dc8ca..31dc8ca 100644 --- a/trunk/infrastructure/framework-src/onsars.js +++ b/infrastructure/framework-src/onsars.js diff --git a/trunk/infrastructure/framework-src/onscheduledtask.js b/infrastructure/framework-src/onscheduledtask.js index 810c3b5..810c3b5 100644 --- a/trunk/infrastructure/framework-src/onscheduledtask.js +++ b/infrastructure/framework-src/onscheduledtask.js diff --git a/trunk/infrastructure/framework-src/onshutdown.js b/infrastructure/framework-src/onshutdown.js index 0243bf6..0243bf6 100644 --- a/trunk/infrastructure/framework-src/onshutdown.js +++ b/infrastructure/framework-src/onshutdown.js diff --git a/trunk/infrastructure/framework-src/onstartup.js b/infrastructure/framework-src/onstartup.js index 61feff7..61feff7 100644 --- a/trunk/infrastructure/framework-src/onstartup.js +++ b/infrastructure/framework-src/onstartup.js diff --git a/trunk/infrastructure/framework-src/onsyntaxerror.js b/infrastructure/framework-src/onsyntaxerror.js index 7129a16..7129a16 100644 --- a/trunk/infrastructure/framework-src/onsyntaxerror.js +++ b/infrastructure/framework-src/onsyntaxerror.js diff --git a/trunk/infrastructure/framework-src/postamble.js b/infrastructure/framework-src/postamble.js index 76fa766..76fa766 100644 --- a/trunk/infrastructure/framework-src/postamble.js +++ b/infrastructure/framework-src/postamble.js diff --git a/trunk/infrastructure/framework-src/preamble.js b/infrastructure/framework-src/preamble.js index 40f6845..40f6845 100644 --- a/trunk/infrastructure/framework-src/preamble.js +++ b/infrastructure/framework-src/preamble.js diff --git a/trunk/infrastructure/framework-src/syntaxerror.js b/infrastructure/framework-src/syntaxerror.js index 801066b..801066b 100644 --- a/trunk/infrastructure/framework-src/syntaxerror.js +++ b/infrastructure/framework-src/syntaxerror.js |