Groovy demo

From Trephine

Revision as of 14:11, 13 March 2009 by Jimbojw (Talk | contribs)
(diff) ←Older revision | Current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search

Groovy demo

Interactive demo showing how to execute arbitrary Groovy code through trephine.

You must have JavaScript enabled to run this demo.

// Status and element functions. 
var e = function(tag,index){ return demotab.getElementsByTagName(tag)[index||0]; };
var status = function(msg) {
  if (!msg) return e('p').style.display = 'none';
  e('p').style.display = '';
  e('p').innerHTML = msg;
};
 
// Setup demo 
var setup = function() {
 
  // Test for Groovy (may already be loaded)
  try {
    var result = trephine.exec('groovy', 'True');
  } catch(err) {
    var result = { success: false, error: err.message };
  }
  if (!result.error) {
    var status = 'ready';
  } else {
 
    // Test whether dependencies are ready for loading
    var result = trephine.js( function(){
 
      // Get handle on lib directory or create it if necessary
      var homedir = new java.io.File( java.lang.System.getProperty('user.home') );
      var libdir = new java.io.File( homedir, '.trephine/lib' );
      if (!libdir.exists()) {
        if (!libdir.mkdirs()) throw "Error: Could not create " + libdir.toString();
      }
 
      // Check for Groovy dependencies
      var jars = ['groovy-engine.jar', 'groovy-1.6.0.jar', 'antlr-2.7.7.jar', 'asm-2.2.3.jar'];
      for (var i=0, l=jars.length; i<l; i++) {
        var jarfile = new java.io.File( libdir, jars[i] );
        if (!jarfile.exists()) return 'missing';
      };
      return 'loadable';
 
    } );
 
    if (result.error) return demotab.innerHTML = '<div class="error">' + result.error + '</div>';
    var status = result.result.toString() + '';
 
  }
 
  if (status=='missing') {
    e('div',1).style.display = '';
  } else if (status=='ready') {
    e('form').style.display = '';
  } else if (status=='loadable') {
    var result = trephine.js( function(){
      var jars = ['groovy-engine.jar', 'groovy-1.6.0.jar', 'antlr-2.7.7.jar', 'asm-2.2.3.jar'];
      var homedir = new java.io.File( java.lang.System.getProperty('user.home') );
      var libdir = new java.io.File( homedir, '.trephine/lib' );
      var executor = java.lang.Thread.currentThread();
      for (var i=0, l=jars.length; i<l; i++) {
        var jarfile = new java.io.File(libdir, jars[i]);
        executor.addSystemJar(jarfile);
      }
      executor.addEngineFactory(new Packages.com.sun.script.groovy.GroovyScriptEngineFactory());
      return true;
    } );
    if (result.error) return demotab.innerHTML = '<div class="error">' + result.error.toString() + '</div>';
    e('form').style.display = '';
  } else {
    return demotab.innerHTML = '<div class="error">Unknown status [' + status + '] returned.</div>';
  }
 
  // Setup download link
  e('a').onclick = function(evt) {
    if (!evt) evt = window.event;
    evt.cancelBubble = true;
    if (evt.stopPropagation) evt.stopPropagation();
    var result = trephine.js( function() {
 
      // Shorthand mechanism for creating and starting background threads.
      Function.prototype.run = function() {
        var thread = new java.lang.Thread( new java.lang.Runnable( { run: this } ) );
        thread.start();
        return thread;
      };
 
      // Helper function for downloading a file asynchronously
      function download( fromURL, toFile, options ) {
        options = options || {};
        var onprogress = typeof options.onprogress == "undefined" ? null : options.onprogress;
        var interval = typeof options.interval == "undefined" ? 500 : options.interval;
        var async = typeof options.async == "undefined" ? true : options.async;
        var f = function(){
          var conn = fromURL.openConnection();
          var len = conn.contentLength;
          var bis = new java.io.BufferedInputStream(conn.inputStream);
          var out = new java.io.BufferedOutputStream(new java.io.FileOutputStream(toFile));
          var b, count = 0, n = 0;
          var buf = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 4096);
          if (!onprogress) {
            while ((n = bis.read(buf, 0, buf.length)) != -1) out.write(buf, 0, n);
            out.flush();
            bis.close();
            out.close();
            return;
          }
          var t = (function(){
            while (count < len) {
              onprogress(count, len);
              java.lang.Thread.currentThread().sleep(interval);
            }
          }).run();
          while ((n = bis.read(buf, 0, buf.length)) != -1) {
            count += n;
            out.write(buf, 0, n);
          }
          t.stop();
          out.flush();
          bis.close();
          out.close();
          onprogress(count, len);
        };
        return async ? f.run() : f();
      };
 
      // Download Groovy dependencies, add them to the system classpath and register the engine factory
      var executor = java.lang.Thread.currentThread();
      (function(){
        var jars = ['groovy-engine.jar', 'groovy-1.6.0.jar', 'antlr-2.7.7.jar', 'asm-2.2.3.jar'];
        var jarids = ['groovy-engine', 'groovy', 'antlr', 'asm'];
        var homedir = new java.io.File( java.lang.System.getProperty('user.home') );
        var libdir = new java.io.File( homedir, '.trephine/lib' );
        var base = applet['c'+'lass'].protectionDomain.codeSource.location.toString().replaceFirst('^(.*'+'/).*$', "$1");
        for (var i=0, l=jarids.length; i<l; i++) (function(id, jar){
          var jarfile = new java.io.File( libdir, jar );
          var msg = "<span class=\"spinner\"></span> " + jar + " <span>0</span>% complete."
          window.eval("window.top.document.getElementById('"+id+"').innerHTML = '"+msg+"';");
          download(new java.net.URL(base + jar), jarfile, {
            async: false,
            onprogress: function(count, len) {
              if (count >= len) {
                var msg = "<span class=\"check\"></span> " + jar + " Done!";
                return window.eval([
                  "window.top.document.getElementById('", id, "').innerHTML = '", msg, "';"
                ].join(''));
              }
              window.eval([
                "window.top.document.getElementById('", id, "').getElementsByTagName('span')[1].innerHTML = ",
                "'" + Math.round(100 * count / len) + "';"
              ].join(''));
            }
          });
          executor.addSystemJar(jarfile);
        })(jarids[i], jars[i]);
        executor.addEngineFactory(new Packages.com.sun.script.groovy.GroovyScriptEngineFactory());
 
        // Switch back from download to main demo form
        var code = '(' + function(){
          var e = function(tag,index){ return window.top.document.getElementById('demotab').getElementsByTagName(tag)[index||0]; };
          e('div',1).style.display = 'none';
          e('p').innerHTML = 'Groovy successfully loaded!';
          e('p').style.display = '';
          e('form').style.display = 'block';
          setTimeout(function(){ e('p').style.display='none'; }, 2000);
        } + ')()';
        window.eval( code.replace(new RegExp('\\r?\\n','g'), '') );
      }).run();
 
    } );
    e('p',1).innerHTML = 'Download in progress...';
    return false;
  };
 
  // Setup form
  var submitcount = 0, firstmsg = 'Preparing Groovy engine and executing code (please be patient) ';
  e('form').onsubmit = function(event) {
    try {
      if (!trephine || !trephine.loaded) throw "Error: trephine not loaded.";
      if (!trephine.hasPermission()) throw "Error: elevated permissions have not been granted.";
      e('div').innerHTML = '<p class="notice" style="float:none"><span class="spinner"></span> ' + (submitcount++ ? 'Executing ' : firstmsg ) + '...</p>';
      setTimeout( function(){
        var result = trephine.exec( 'groovy', e('textarea').value );
        var boxtype = result.success.toString() == 'true' ? 'success' : 'error';
        var msg = (boxtype == 'success' ? result.result : result.error);
        try { msg = msg.toString() + ''; } catch(err) {}
        if (boxtype != 'success') msg += "</p><p><strong>Tip</strong>: Enable the Java Console to see full traces.<br />";
        e('div').innerHTML = '<p class="' + boxtype + 'box" style="float:none">' + msg + '</p>';
      }, 10 );
    } catch(err) {
      e('div').innerHTML = '<p class="errorbox" style="float:none">' + err + '</p>';
    }
    return false;
  };
};
 
// Load trephine 
status('<span class="spinner"></span> Loading trephine...');
trephine.load({
  debug: true, // Enables debug logging to the Java Console
  engines: ['js', 'groovy'], // Initialize the JavaScript and Groovy engines as soon as possible
  onload: function() { // Immediately prompt for permissions
    status('<span class="spinner"></span> Asking for elevated permissions...');
    trephine.askPermission( function(response) {
      if (!response) { // Short-circuit if permission request was denied
        return demotab.innerHTML = '<div class="error">Sorry, you must grant trephine privileges to enjoy this demo.</div>';
      }
      setup();
      status('Permission request granted.');
      setTimeout( function(){ status(); }, 2000 );
    } );
  } 
});
<p class="notice"></p>
<form style="display:none">
  <input class="button" type="submit" value="execute"/>
  <h4>Groovy Code:</h4>
  <textarea>
// Rules I live by
if (Calendar.getInstance().get(Calendar.AM_PM) == Calendar.AM) {
  advise = "Have another cup of coffee."
} else {
  advise = "Switch to decaf (just kidding - fire up the espresso machine!)."
}
  </textarea>
  <h4>Result:</h4>
  <div style="overflow:auto"></div>
</form>
<div style="display:none">
  <p class="notice">
    This demo requires the following Groovy support jars.
    <strong><a href="" title="begin download">Click here to begin download</a></strong>
  </p>
  <ul>
    <li id="groovy-engine">groovy-engine.jar (13 KB)</li>
    <li id="groovy">groovy.jar (3.8 MB)</li>
    <li id="antlr">antlr-2.7.7.jar (445 KB)</li>
    <li id="asm">asm-2.2.3.jar (34 KB)</li>
  </ul>
</div>
.demotab input {
  float: right;
}
.demotab textarea {
  width: 600px;
  height: 100px;
  background: #fffff0;
  margin-bottom: 18px;
}
.demotab h4 {
  font-weight: bold;
}
.demotab .spinner {
  padding: 10px 10px;
  background: url("skins/common/images/spinner.gif");
  background-position: center center;
  background-repeat: no-repeat;
}
.demotab .check {
  padding: 8px 10px;
  background: url("skins/trephine/accept.gif");
  background-position: center center;
  background-repeat: no-repeat;
}
.demotab form div p {
  overflow: auto;
}

Activation

  1. Activate the demo by clicking the specified link.
  2. You may see a Java Security dialog, if so, click "Run" or "Trust" to indicate your acceptance
  3. In the "Trephine permission request" dialog, answer the math challenge and click "OK" to grant scripts on this page elevated privileges.
  4. If this is your first time running the demo, you will be prompted to download the Groovy dependencies, click the link to do so.
  5. Once all the dependency jars have been downloaded, the demo will be ready to accept instructions.

Usage

  1. Enter desired Groovy code into the code box provided.
  2. Click the execute button in the upper-right corner to trigger trephine's exec() function.
  3. Repeat as many times as you like.
Note
  • For return value, the script engine sends back the result of the last successfully executed command or expression, or an exception if one was thrown.

Examples

The Groovy website has some great sample code, like the Mailer User Interface example.

Personal tools