Home | History | Annotate | Download | only in resources
      1 /*
      2  * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  *   - Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  *
     11  *   - Redistributions in binary form must reproduce the above copyright
     12  *     notice, this list of conditions and the following disclaimer in the
     13  *     documentation and/or other materials provided with the distribution.
     14  *
     15  *   - Neither the name of Oracle nor the names of its
     16  *     contributors may be used to endorse or promote products derived
     17  *     from this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * This source code is provided to illustrate the usage of a given feature
     34  * or technique and has been deliberately simplified. Additional steps
     35  * required for a production-quality application, such as security checks,
     36  * input validation and proper error handling, might not be present in
     37  * this sample code.
     38  */
     39 
     40 /*
     41  * Concurrency utilities for JavaScript. These are based on
     42  * java.lang and java.util.concurrent API. The following functions
     43  * provide a simpler API for scripts. Instead of directly using java.lang
     44  * and java.util.concurrent classes, scripts can use functions and
     45  * objects exported from here.
     46  */
     47 
     48 // shortcut for j.u.c lock classes
     49 var Lock = java.util.concurrent.locks.ReentrantLock;
     50 var RWLock = java.util.concurrent.locks.ReentrantReadWriteLock;
     51 
     52 // check if there is a build in sync function, define one if missing
     53 if (typeof sync === "undefined") {
     54     var sync = function(func, obj) {
     55         if (arguments.length < 1 || arguments.length > 2 ) {
     56             throw "sync(function [,object]) parameter count mismatch";
     57         }
     58 
     59         var syncobj = (arguments.length == 2 ? obj : this);
     60 
     61         if (!syncobj._syncLock) {
     62             syncobj._syncLock = new Lock();
     63         }
     64 
     65         return function() {
     66             syncobj._syncLock.lock();
     67             try {
     68                 func.apply(null, arguments);
     69             } finally {
     70                 syncobj._syncLock.unlock();
     71             }
     72         };
     73     };
     74     sync.docString = "synchronize a function, optionally on an object";
     75 }
     76 
     77 /**
     78  * Wrapper for java.lang.Object.wait
     79  *
     80  * can be called only within a sync method
     81  */
     82 function wait(object) {
     83     var objClazz = java.lang.Class.forName('java.lang.Object');
     84     var waitMethod = objClazz.getMethod('wait', null);
     85     waitMethod.invoke(object, null);
     86 }
     87 wait.docString = "convenient wrapper for java.lang.Object.wait method";
     88 
     89 /**
     90  * Wrapper for java.lang.Object.notify
     91  *
     92  * can be called only within a sync method
     93  */
     94 function notify(object) {
     95     var objClazz = java.lang.Class.forName('java.lang.Object');
     96     var notifyMethod = objClazz.getMethod('notify', null);
     97     notifyMethod.invoke(object, null);
     98 }
     99 notify.docString = "convenient wrapper for java.lang.Object.notify method";
    100 
    101 /**
    102  * Wrapper for java.lang.Object.notifyAll
    103  *
    104  * can be called only within a sync method
    105  */
    106 function notifyAll(object)  {
    107     var objClazz = java.lang.Class.forName('java.lang.Object');
    108     var notifyAllMethod = objClazz.getMethod('notifyAll', null);
    109     notifyAllMethod.invoke(object, null);
    110 }
    111 notifyAll.docString = "convenient wrapper for java.lang.Object.notifyAll method";
    112 
    113 /**
    114  * Creates a java.lang.Runnable from a given script
    115  * function.
    116  */
    117 Function.prototype.runnable = function() {
    118     var args = arguments;
    119     var func = this;
    120     return new java.lang.Runnable() {
    121         run: function() {
    122             func.apply(null, args);
    123         }
    124     }
    125 };
    126 
    127 /**
    128  * Executes the function on a new Java Thread.
    129  */
    130 Function.prototype.thread = function() {
    131     var t = new java.lang.Thread(this.runnable.apply(this, arguments));
    132     t.start();
    133     return t;
    134 };
    135 
    136 /**
    137  * Executes the function on a new Java daemon Thread.
    138  */
    139 Function.prototype.daemon = function() {
    140     var t = new java.lang.Thread(this.runnable.apply(this, arguments));
    141     t.setDaemon(true);
    142     t.start();
    143     return t;
    144 };
    145 
    146 /**
    147  * Creates a java.util.concurrent.Callable from a given script
    148  * function.
    149  */
    150 Function.prototype.callable = function() {
    151     var args = arguments;
    152     var func = this;
    153     return new java.util.concurrent.Callable() {
    154           call: function() { return func.apply(null, args); }
    155     }
    156 };
    157 
    158 /**
    159  * Registers the script function so that it will be called exit.
    160  */
    161 Function.prototype.atexit = function () {
    162     var args = arguments;
    163     java.lang.Runtime.getRuntime().addShutdownHook(
    164          new java.lang.Thread(this.runnable.apply(this, args)));
    165 };
    166 
    167 /**
    168  * Executes the function asynchronously.
    169  *
    170  * @return a java.util.concurrent.FutureTask
    171  */
    172 Function.prototype.future = (function() {
    173     // default executor for future
    174     var juc = java.util.concurrent;
    175     var theExecutor = juc.Executors.newSingleThreadExecutor();
    176     // clean-up the default executor at exit
    177     (function() { theExecutor.shutdown(); }).atexit();
    178     return function() {
    179         return theExecutor.submit(this.callable.apply(this, arguments));
    180     };
    181 })();
    182 
    183 /**
    184  * Executes a function after acquiring given lock. On return,
    185  * (normal or exceptional), lock is released.
    186  *
    187  * @param lock lock that is locked and unlocked
    188  */
    189 Function.prototype.sync = function (lock) {
    190     if (arguments.length == 0) {
    191         throw "lock is missing";
    192     }
    193     var res = new Array(arguments.length - 1);
    194     for (var i = 0; i < res.length; i++) {
    195         res[i] = arguments[i + 1];
    196     }
    197     lock.lock();
    198     try {
    199         this.apply(null, res);
    200     } finally {
    201         lock.unlock();
    202     }
    203 };
    204 
    205 /**
    206  * Causes current thread to sleep for specified
    207  * number of milliseconds
    208  *
    209  * @param interval in milliseconds
    210  */
    211 function sleep(interval) {
    212     java.lang.Thread.sleep(interval);
    213 }
    214 sleep.docString = "wrapper for java.lang.Thread.sleep method";
    215 
    216 /**
    217  * Schedules a task to be executed once in N milliseconds specified.
    218  *
    219  * @param callback function or expression to evaluate
    220  * @param interval in milliseconds to sleep
    221  * @return timeout ID (which is nothing but Thread instance)
    222  */
    223 function setTimeout(callback, interval) {
    224     if (! (callback instanceof Function)) {
    225         callback = new Function(callback);
    226     }
    227 
    228     // start a new thread that sleeps given time
    229     // and calls callback in an infinite loop
    230     return (function() {
    231          try {
    232              sleep(interval);
    233          } catch (x) { }
    234          callback();
    235     }).daemon();
    236 }
    237 setTimeout.docString = "calls given callback once after specified interval";
    238 
    239 /**
    240  * Cancels a timeout set earlier.
    241  * @param tid timeout ID returned from setTimeout
    242  */
    243 function clearTimeout(tid) {
    244     // we just interrupt the timer thread
    245     tid.interrupt();
    246 }
    247 clearTimeout.docString = "interrupt a setTimeout timer";
    248 
    249 /**
    250  * Schedules a task to be executed once in
    251  * every N milliseconds specified.
    252  *
    253  * @param callback function or expression to evaluate
    254  * @param interval in milliseconds to sleep
    255  * @return timeout ID (which is nothing but Thread instance)
    256  */
    257 function setInterval(callback, interval) {
    258     if (! (callback instanceof Function)) {
    259         callback = new Function(callback);
    260     }
    261 
    262     // start a new thread that sleeps given time
    263     // and calls callback in an infinite loop
    264     return (function() {
    265          while (true) {
    266              try {
    267                  sleep(interval);
    268              } catch (x) {
    269                  break;
    270              }
    271              callback();
    272          }
    273     }).daemon();
    274 }
    275 setInterval.docString = "calls given callback every specified interval";
    276 
    277 /**
    278  * Cancels a timeout set earlier.
    279  * @param tid timeout ID returned from setTimeout
    280  */
    281 function clearInterval(tid) {
    282     // we just interrupt the timer thread
    283     tid.interrupt();
    284 }
    285 clearInterval.docString = "interrupt a setInterval timer";
    286 
    287 /**
    288  * Simple access to thread local storage.
    289  *
    290  * Script sample:
    291  *
    292  *  __thread.x = 44;
    293  *  function f() {
    294  *      __thread.x = 'hello';
    295  *      print(__thread.x);
    296  *  }
    297  *  f.thread();       // prints 'hello'
    298  * print(__thread.x); // prints 44 in main thread
    299  */
    300 var __thread = (function () {
    301     var map = new Object();
    302     return new JSAdapter({
    303         __has__: function(name) {
    304             return map[name] != undefined;
    305         },
    306         __get__: function(name) {
    307             if (map[name] != undefined) {
    308                 return map[name].get();
    309             } else {
    310                 return undefined;
    311             }
    312         },
    313         __put__: sync(function(name, value) {
    314             if (map[name] == undefined) {
    315                 var tmp = new java.lang.ThreadLocal();
    316                 tmp.set(value);
    317                 map[name] = tmp;
    318             } else {
    319                 map[name].set(value);
    320             }
    321         }),
    322         __delete__: function(name) {
    323             if (map[name] != undefined) {
    324                 map[name].set(null);
    325             }
    326         }
    327     });
    328 })();
    329 
    330