| /* |
| * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * - Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * - Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * - Neither the name of Oracle nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /* |
| * This source code is provided to illustrate the usage of a given feature |
| * or technique and has been deliberately simplified. Additional steps |
| * required for a production-quality application, such as security checks, |
| * input validation and proper error handling, might not be present in |
| * this sample code. |
| */ |
| |
| /* |
| * Concurrency utilities for JavaScript. These are based on |
| * java.lang and java.util.concurrent API. The following functions |
| * provide a simpler API for scripts. Instead of directly using java.lang |
| * and java.util.concurrent classes, scripts can use functions and |
| * objects exported from here. |
| */ |
| |
| // shortcut for j.u.c lock classes |
| var Lock = java.util.concurrent.locks.ReentrantLock; |
| var RWLock = java.util.concurrent.locks.ReentrantReadWriteLock; |
| |
| // check if there is a build in sync function, define one if missing |
| if (typeof sync === "undefined") { |
| var sync = function(func, obj) { |
| if (arguments.length < 1 || arguments.length > 2 ) { |
| throw "sync(function [,object]) parameter count mismatch"; |
| } |
| |
| var syncobj = (arguments.length == 2 ? obj : this); |
| |
| if (!syncobj._syncLock) { |
| syncobj._syncLock = new Lock(); |
| } |
| |
| return function() { |
| syncobj._syncLock.lock(); |
| try { |
| func.apply(null, arguments); |
| } finally { |
| syncobj._syncLock.unlock(); |
| } |
| }; |
| }; |
| sync.docString = "synchronize a function, optionally on an object"; |
| } |
| |
| /** |
| * Wrapper for java.lang.Object.wait |
| * |
| * can be called only within a sync method |
| */ |
| function wait(object) { |
| var objClazz = java.lang.Class.forName('java.lang.Object'); |
| var waitMethod = objClazz.getMethod('wait', null); |
| waitMethod.invoke(object, null); |
| } |
| wait.docString = "convenient wrapper for java.lang.Object.wait method"; |
| |
| /** |
| * Wrapper for java.lang.Object.notify |
| * |
| * can be called only within a sync method |
| */ |
| function notify(object) { |
| var objClazz = java.lang.Class.forName('java.lang.Object'); |
| var notifyMethod = objClazz.getMethod('notify', null); |
| notifyMethod.invoke(object, null); |
| } |
| notify.docString = "convenient wrapper for java.lang.Object.notify method"; |
| |
| /** |
| * Wrapper for java.lang.Object.notifyAll |
| * |
| * can be called only within a sync method |
| */ |
| function notifyAll(object) { |
| var objClazz = java.lang.Class.forName('java.lang.Object'); |
| var notifyAllMethod = objClazz.getMethod('notifyAll', null); |
| notifyAllMethod.invoke(object, null); |
| } |
| notifyAll.docString = "convenient wrapper for java.lang.Object.notifyAll method"; |
| |
| /** |
| * Creates a java.lang.Runnable from a given script |
| * function. |
| */ |
| Function.prototype.runnable = function() { |
| var args = arguments; |
| var func = this; |
| return new java.lang.Runnable() { |
| run: function() { |
| func.apply(null, args); |
| } |
| } |
| }; |
| |
| /** |
| * Executes the function on a new Java Thread. |
| */ |
| Function.prototype.thread = function() { |
| var t = new java.lang.Thread(this.runnable.apply(this, arguments)); |
| t.start(); |
| return t; |
| }; |
| |
| /** |
| * Executes the function on a new Java daemon Thread. |
| */ |
| Function.prototype.daemon = function() { |
| var t = new java.lang.Thread(this.runnable.apply(this, arguments)); |
| t.setDaemon(true); |
| t.start(); |
| return t; |
| }; |
| |
| /** |
| * Creates a java.util.concurrent.Callable from a given script |
| * function. |
| */ |
| Function.prototype.callable = function() { |
| var args = arguments; |
| var func = this; |
| return new java.util.concurrent.Callable() { |
| call: function() { return func.apply(null, args); } |
| } |
| }; |
| |
| /** |
| * Registers the script function so that it will be called exit. |
| */ |
| Function.prototype.atexit = function () { |
| var args = arguments; |
| java.lang.Runtime.getRuntime().addShutdownHook( |
| new java.lang.Thread(this.runnable.apply(this, args))); |
| }; |
| |
| /** |
| * Executes the function asynchronously. |
| * |
| * @return a java.util.concurrent.FutureTask |
| */ |
| Function.prototype.future = (function() { |
| // default executor for future |
| var juc = java.util.concurrent; |
| var theExecutor = juc.Executors.newSingleThreadExecutor(); |
| // clean-up the default executor at exit |
| (function() { theExecutor.shutdown(); }).atexit(); |
| return function() { |
| return theExecutor.submit(this.callable.apply(this, arguments)); |
| }; |
| })(); |
| |
| /** |
| * Executes a function after acquiring given lock. On return, |
| * (normal or exceptional), lock is released. |
| * |
| * @param lock lock that is locked and unlocked |
| */ |
| Function.prototype.sync = function (lock) { |
| if (arguments.length == 0) { |
| throw "lock is missing"; |
| } |
| var res = new Array(arguments.length - 1); |
| for (var i = 0; i < res.length; i++) { |
| res[i] = arguments[i + 1]; |
| } |
| lock.lock(); |
| try { |
| this.apply(null, res); |
| } finally { |
| lock.unlock(); |
| } |
| }; |
| |
| /** |
| * Causes current thread to sleep for specified |
| * number of milliseconds |
| * |
| * @param interval in milliseconds |
| */ |
| function sleep(interval) { |
| java.lang.Thread.sleep(interval); |
| } |
| sleep.docString = "wrapper for java.lang.Thread.sleep method"; |
| |
| /** |
| * Schedules a task to be executed once in N milliseconds specified. |
| * |
| * @param callback function or expression to evaluate |
| * @param interval in milliseconds to sleep |
| * @return timeout ID (which is nothing but Thread instance) |
| */ |
| function setTimeout(callback, interval) { |
| if (! (callback instanceof Function)) { |
| callback = new Function(callback); |
| } |
| |
| // start a new thread that sleeps given time |
| // and calls callback in an infinite loop |
| return (function() { |
| try { |
| sleep(interval); |
| } catch (x) { } |
| callback(); |
| }).daemon(); |
| } |
| setTimeout.docString = "calls given callback once after specified interval"; |
| |
| /** |
| * Cancels a timeout set earlier. |
| * @param tid timeout ID returned from setTimeout |
| */ |
| function clearTimeout(tid) { |
| // we just interrupt the timer thread |
| tid.interrupt(); |
| } |
| clearTimeout.docString = "interrupt a setTimeout timer"; |
| |
| /** |
| * Schedules a task to be executed once in |
| * every N milliseconds specified. |
| * |
| * @param callback function or expression to evaluate |
| * @param interval in milliseconds to sleep |
| * @return timeout ID (which is nothing but Thread instance) |
| */ |
| function setInterval(callback, interval) { |
| if (! (callback instanceof Function)) { |
| callback = new Function(callback); |
| } |
| |
| // start a new thread that sleeps given time |
| // and calls callback in an infinite loop |
| return (function() { |
| while (true) { |
| try { |
| sleep(interval); |
| } catch (x) { |
| break; |
| } |
| callback(); |
| } |
| }).daemon(); |
| } |
| setInterval.docString = "calls given callback every specified interval"; |
| |
| /** |
| * Cancels a timeout set earlier. |
| * @param tid timeout ID returned from setTimeout |
| */ |
| function clearInterval(tid) { |
| // we just interrupt the timer thread |
| tid.interrupt(); |
| } |
| clearInterval.docString = "interrupt a setInterval timer"; |
| |
| /** |
| * Simple access to thread local storage. |
| * |
| * Script sample: |
| * |
| * __thread.x = 44; |
| * function f() { |
| * __thread.x = 'hello'; |
| * print(__thread.x); |
| * } |
| * f.thread(); // prints 'hello' |
| * print(__thread.x); // prints 44 in main thread |
| */ |
| var __thread = (function () { |
| var map = new Object(); |
| return new JSAdapter({ |
| __has__: function(name) { |
| return map[name] != undefined; |
| }, |
| __get__: function(name) { |
| if (map[name] != undefined) { |
| return map[name].get(); |
| } else { |
| return undefined; |
| } |
| }, |
| __put__: sync(function(name, value) { |
| if (map[name] == undefined) { |
| var tmp = new java.lang.ThreadLocal(); |
| tmp.set(value); |
| map[name] = tmp; |
| } else { |
| map[name].set(value); |
| } |
| }), |
| __delete__: function(name) { |
| if (map[name] != undefined) { |
| map[name].set(null); |
| } |
| } |
| }); |
| })(); |
| |