Subversion Repositories pub

Compare Revisions

No changes between revisions

Ignore whitespace Rev 61 → Rev 62

/pluggablejs/trunk/Makefile
1,26 → 1,32
# $Id$
 
prefix:=/usr/local
DESTDIR:=
JAR=dist/pluggablejs.jar
 
buildnum=$(shell grep 'build.number' build.num | cut -d'=' -f2)
version=$(shell grep '<property name="version"' build.xml | sed -r 's/.*value="([^"]*)".*/\1/')
jarbasename=pluggablejs-$(version)-build$(buildnum).jar
 
bindir=$(DESTDIR)/$(prefix)/bin
 
all:
ant compile.downstream
 
$(JAR):
dist/$(jarbasename):
ant dist.downstream
 
clean:
ant clean
 
install: $(JAR)
install: dist/$(jarbasename)
test 0 -eq `id -u` # Must be root (or use fakeroot)
mkdir -p $(DESTDIR)/$(prefix)/share/java $(bindir)/
install -m644 -o0 -g0 $(JAR) $(DESTDIR)/$(prefix)/share/java/
install -m644 -o0 -g0 dist/$(jarbasename) $(DESTDIR)/$(prefix)/share/java/
cd $(DESTDIR)/$(prefix)/share/java && ln -s $(jarbasename) pluggablejs.jar
cat pjsh.sh | sed 's\^prefix=.*$$\prefix=$(prefix)\g' > $(bindir)/pjsh
chmod 755 $(bindir)/pjsh
-chown root.root $(bindir)/pjsh
 
uninstall:
$(RM) $(DESTDIR)/$(prefix)/share/java/`basename "$(JAR)"`
$(RM) $(DESTDIR)/$(prefix)/share/java/$(jarbasename)
-rmdir -p $(DESTDIR)/$(prefix)/share/java
Property changes:
Added: svn:keywords
+Rev Id Date
\ No newline at end of property
/pluggablejs/trunk/build.num
1,3 → 1,3
#Build Number for ANT. Do not edit!
#Sun Jun 29 04:30:52 CEST 2008
build.number=29
#Mon Jun 30 20:53:31 CEST 2008
build.number=33
/pluggablejs/trunk/build.xml
9,7 → 9,8
<property name="release" location="release"/>
<property name="depends" location="lib"/>
 
<property name="version" value="1.0"/>
<property name="version" value="1.1.0"/>
<property name="jarbasename" value="pluggablejs-${version}-build" /><!-- followed by build.number, can't resolve yet -->
 
<target name="init">
<!-- Create timestamp, sets TODAY (full, human), DSTAMP (yyyymmdd) and
41,7 → 42,7
<target name="dist.real" description="Generate the distribution">
<mkdir dir="${dist}/"/>
 
<jar jarfile="${dist}/pluggablejs.jar" basedir="${build}">
<jar jarfile="${dist}/${jarbasename}${build.number}.jar" basedir="${build}">
<!-- <classpath refid="${third.party.libs}" /> -->
<manifest>
<attribute name="X-COMMENT" value="Standard build" />
54,7 → 55,7
-->
</manifest>
</jar>
<jar destfile="${dist}/pluggablejs-src.jar" basedir="${src}"/>
<jar destfile="${dist}/${jarbasename}${build.number}-src.jar" basedir="${src}"/>
</target>
 
<target name="dist.downstream" depends="compile.downstream, dist.real" />
/pluggablejs/trunk/debian/README.Debian
1,6 → 1,7
libpluggablejs-java for Debian
------------------------------
 
<possible notes regarding this package - if none, delete this file>
This is debian package created from the upstream source, it might
not follow the Debian policy correctly.
 
-- Toni Corvera <outlyer@gmail.com> Thu, 26 Jun 2008 02:54:11 +0200
/pluggablejs/trunk/debian/changelog
1,3 → 1,9
pluggablejs (1.1.0build33-upstream.0) experimental; urgency=low
 
* New release.
 
-- Toni Corvera <outlyer@gmail.com> Tue, 01 Jul 2008 02:20:32 +0200
 
pluggablejs (1.0build29-upstream.0) experimental; urgency=low
 
* Initial public release.
/pluggablejs/trunk/debian/docs
0,0 → 1,2
pjsh.cmd
 
/pluggablejs/trunk/debian/rules
67,7 → 67,7
binary-arch: build install
dh_testdir
dh_testroot
dh_installchangelogs
dh_installchangelogs ChangeLog
dh_installdocs
dh_installexamples
# dh_install
/pluggablejs/trunk/samples/langext.js
0,0 → 1,31
 
println("Language extensions samples");
 
println("|> Inclusion of langext-included.js, composition of ");
println("|> an object from different files");
 
function method1_implementation() {
println("This method is defined in langext.js");
}
 
var method2_implementation = null;
 
// If method2 was defined this way it will fail, it needs to be
// defined as with method3
var obj = {
method1: method1_implementation,
method2: method2_implementation,
method3: function() {
method3_implementation();
}
};
 
lang.include("langext-included.js");
 
// ... instead, it can be defined now though
obj.method2 = method2_implementation;
 
println("|> calling of methods defined elsewhere:");
obj.method1();
obj.method2();
obj.method3();
/pluggablejs/trunk/samples/interactive-call.js
0,0 → 1,2
 
net.outlyer.plugins.Shell.interactive($net.outlyer.runtime.pluginEnvironment);
/pluggablejs/trunk/samples/langext-included.js
0,0 → 1,9
 
println("|< langext-included.js loaded");
 
method2_implementation = function() {
println("This method is defined in langext-included.js");
}
 
method3_implementation = method2_implementation;
 
/pluggablejs/trunk/src/net/outlyer/plugins/Shell.java
27,34 → 27,95
// $Id$
 
import java.io.File;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import net.outlyer.plugins.utils.*;
 
/**
* Sample shell for tests, files passed as arguments will be loaded and
* executed.
* Sample shell for tests, or scripts.
* Files passed as arguments will be loaded and executed.
*/
public final class Shell {
public static void interactive(final PluginEnvironment pe) {
try {
final Sandbox sandbox = pe.createSandbox(null);
final ScriptEngine rhino = ((SandboxImpl) sandbox).executeAndGetEngine();
 
final Input in = new Input();
final Output out = new Output();
System.err.printf("pluggablejsShell v%d.%d.%d\n",API.VERSION,API.MIN_SUPPORTED_VERSION,API.REVISION);
final boolean isWin = System.getProperty("os.name").toLowerCase().startsWith("windows");
// apparently windows doesn't get EOF until enter is pressed
System.err.printf(" use EOF (%s) or break (CTRL+C) to exit\n", (isWin)?"CTRL+Z,Enter":"CTRL+D");
 
try {
// undocumented feature: when
// $net.outlyer.runtime.internal.shell is true an extra println() is
// issued after each eval
rhino.eval("$net.outlyer.runtime.internal.shell = { autoEOL: false, };");
}
catch (final ScriptException e) {
e.printStackTrace();
}
while (true) {
out.print("pjsh% : ");
final String line = in.readline();
if (null == line) {
break;
}
try {
rhino.eval(line);
final boolean eol = (Boolean) rhino.eval("$net.outlyer.runtime.internal.shell.autoEOL");
if (eol) {
out.println();
}
}
catch (final ScriptException e) {
System.err.println("//[E] Error: " + e.getMessage());
}
}
// EOF
System.exit(0);
}
catch (final PluginException e) {
System.err.printf("Exception while running on-the-fly " +
"interpreted script", e.getLocalizedMessage());
System.exit(5);
}
}
public static void main(String...args) {
if (args.length == 0) {
System.err.printf("Usage: java [...] %s [file1.js [file2.js [...]]]\n",
System.err.printf("Usage: \n" +
" java [...] %s <file1.js [file2.js [...]]>\n"+
" or\n"+
" java [...] %1$s <-i|--interactive>\n",
Shell.class.getName());
System.exit(1);
}
 
final PluginEnvironment pe = new PluginEnvironment();
pe.exportGlobalObject("input", new Input());
pe.exportGlobalObject("out", new Output());
pe.exportGlobalObject("err", new Output(System.err));
pe.exportGlobalObject("hooks", new Hooks());
pe.exportObject("input", new Input());
pe.exportObject("out", new Output());
pe.exportObject("err", new Output(System.err));
pe.exportObject("hooks", new Hooks());
// Generally either UI or GUI should be used but not both
// since GUI falls-back to UI if appropriate (so the ui object
// will use the "best" implementation)
pe.exportGlobalObject("ui", new GUI());
pe.exportGlobalObject("gui", new GUI());
pe.exportGlobalObject("cui", new UI()); // cui stands for Console UI
pe.exportObject("ui", new GUI());
pe.exportObject("gui", new GUI());
pe.exportObject("cui", new UI()); // cui stands for Console UI
pe.exportObject("lang", new LanguageExtensions());
final PluginObject po = new PluginObject();
pe.setPluginObject(po);
if (args.length == 1 && (args[0].equals("-i") || args[0].equals("--interactive"))) {
interactive(pe);
assert false;
}
// Non-interactive mode
for (final String path : args) {
try {
final Sandbox sandbox = pe.createSandbox(new File(path).toURI());
/pluggablejs/trunk/src/net/outlyer/plugins/API.java
27,34 → 27,51
// $Id$
 
/**
* API versioning
* API versioning.
*
* Versioning is inspired by libtool's rules
* {@link http://www.gnu.org/software/libtool/manual.html#Versioning}, i.e.
* <pre>
* API version = "current"
* API revvision = "revision"
* API min_supported_revision = "current" - "age"
* </pre>
*
* Release numbers are meaningful and composed like:
* <code>Version.MinSupported.Revision.build#</code>,
* so, e.g. release 2.3.0 won't valid since MinSupported can't be
* greater than version.
*/
public final class API {
// Release will be REVISION.(IMPLEMENTATION-1) i.e.
// for REVISION=1 and IMPLEMENTATION=1, release would be 1.0
 
/**
* API Revision.
* Newer revisions might break backwards compatibility (see
* {@link #MIN_SUPPORTED_REVISION}).
* API Version.
* Newer versions might break backwards compatibility.
*/
public static final int REVISION = 1;
public static final int VERSION = 1;
 
/**
* Implementation of the API revision.
* Different implementations of an API are guaranteed to maintain
* the API unchanged.
* @see #REVISION
* Revision of the API Version.
* A newer revision might add features but not change the meaning of
* existing ones neither remove any of them.
* @see #VERSION
*/
public static final int IMPLEMENTATION = 1;
public static final int REVISION = 0;
 
/**
* Minimum API revision supported by this implementation.
* Number of previous Versions supported.
* For future use.
* {@see #VERSION}
* {@see #MIN_SUPPORTED_VERSION}
*/
public static final int AGE = 0;
/**
* Minimum API version supported by this implementation.
* For future use.
* In principle a new API should provide support for previous revisions,
* in case it doesn't, this constant will hold the lower supported API.
* @see #REVISION
* @pre MIN_SUPPORTED_REVISION &lt;= REVISION
* @see #VERSION
* @pre MIN_SUPPORTED_VERSION &lt;= VERSION
*/
public static final int MIN_SUPPORTED_REVISION = 1;
public static final int MIN_SUPPORTED_VERSION = VERSION - AGE;
}
/pluggablejs/trunk/src/net/outlyer/plugins/SandboxProperties.java
29,10 → 29,10
import java.net.URI;
 
/**
* Provides access to some properties of a sandbox
* Provides access to properties of a sandbox
* @see Sandbox
*/
public interface SandboxProperties {
interface SandboxProperties {
/**
* Obtains the number of this execution (each time the script is executed
/pluggablejs/trunk/src/net/outlyer/plugins/PluginProperties.java
30,9 → 30,32
* Common properties of the plugin object. All of them
* take sane defaults.
*/
public class PluginProperties extends SandboxAccessorImpl {
class PluginProperties extends SandboxAccessorImpl {
/**
* pluggablejs Api Version against which this plugin was written.
* Default: 1
* @see API#VERSION
*/
public int apiVersion = 1;
 
/**
* Type of this plugin, application-specific.
* Default: "" (no type)
* @see PluginLocator#getAll()
* @see PluginLocator#getFirst()
*/
public String type;
 
/**
* Name of this plugin.
* Default: same as filename (including extension but not path)
* @see PluginLocator#getAll()
* @see PluginLocator#getFirst()
*/
public String name;
 
/**
* @deprecated The use of this field is yet to be defined
*/
public Object properties; // FIXME: To be defined
}
/pluggablejs/trunk/src/net/outlyer/plugins/utils/LanguageExtensions.java
0,0 → 1,75
package net.outlyer.plugins.utils;
 
/*
* Copyright (c) 2008, Toni Corvera. 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.
*
* THIS SOFTWARE IS PROVIDED "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.
*/
 
// $Id$
 
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import javax.script.ScriptException;
import net.outlyer.plugins.SandboxAccessorImpl;
 
/**
* Extra facilities found in other languages or more complete
* versions of available facilities.
* Recommended name: lang
*/
public class LanguageExtensions extends SandboxAccessorImpl {
/**
* ScriptEngine's eval.
* The built-in eval() appears to be less-powerful, in general they're
* equivalent, but if the eval'ed string is obtainer from input
* <code>eval()</code> appears to ignore it, while
* <code>LanguageExtensions.eval()</code> does eval it.
* @param code Code to evaluate
* @return Eval's result
*/
public Object eval(final String code) {
try {
return getSandbox().getCurrentEngine().eval(code);
}
catch (final ScriptException e) {
// FIXME: Handle better
System.err.println("Exception: " + e.getMessage());
}
return null;
}
 
public Object include(final String fileName) { // TODO: Support jar URIs
try {
return getSandbox().getCurrentEngine().eval(new FileReader(new File(fileName)));
}
catch (final FileNotFoundException e) {
// FIXME: Handle better
System.err.println("Failed to read "+fileName);
}
catch (final ScriptException e) {
// FIXME: Handle better
System.err.println("Exception: " + e.getMessage());
}
return null;
}
}
Property changes:
Added: svn:keywords
+Rev Id Date
\ No newline at end of property
/pluggablejs/trunk/src/net/outlyer/plugins/utils/package-info.java
1,7 → 1,7
/**
* This package provides some common functionality that might often be
* wanted to be exported as global objects.
* {@see net.outlyer.plugins.sandboxing.PluginEnvironment#exportGlobalObject}.
* {@see net.outlyer.plugins.PluginEnvironment#exportObject}.
*/
 
// $Id$
/pluggablejs/trunk/src/net/outlyer/plugins/utils/Output.java
42,6 → 42,9
public Output(final PrintStream ps) {
this.ps = ps;
}
 
// Note rhino already provides print() and println() in the global
// namespace
public void println() {
ps.println();
61,6 → 64,10
}
public void printf(final String s) {
ps.printf("%s", s);
print(s);
}
 
public void print(final String s) {
ps.print(s);
}
}
/pluggablejs/trunk/src/net/outlyer/plugins/SandboxImpl.java
26,6 → 26,9
 
// $Id$
 
// Related reference:
// http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/
 
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
50,11 → 53,24
private final String boilerPlate;
private int execution = 0;
private final PluginProperties properties;
private transient ScriptEngine currentEngine = null;
private static final String END_KEY = "e";
private static final boolean debug;
private final PluginEnvironment pE;
private static final String END_KEY = "e";
private static class ExecResult {
final ScriptEngine rhino;
final Object evalResult;
ExecResult(final ScriptEngine rhino_, final Object evalResult_) {
rhino = rhino_;
evalResult = evalResult_;
}
}
 
static {
nextUniqueVarNum = (int) (1193 * (1+Math.random()));
debug = System.getProperty("debug", "0").equals("1");
}
{
62,16 → 78,19
hooks.put(END_KEY, new LinkedList<Runnable>());
}
protected SandboxImpl(final URI plugin, final Bindings bs, final PluginProperties pp) {
this(plugin, bs, pp, null);
protected SandboxImpl(final PluginEnvironment pe, final URI plugin,
final Bindings bs, final PluginProperties pp) {
this(pe, plugin, bs, pp, null);
}
protected SandboxImpl(final URI plugin, final Bindings bs,
protected SandboxImpl(final PluginEnvironment pe, final URI plugin,
final Bindings bs,
final PluginProperties pp, final String boilerPlate) {
bindings = bs;
pluginUri = plugin;
pluginUri = plugin; // if null => sandbox without file
this.boilerPlate = boilerPlate;
properties = pp;
pE = pe;
}
public void addEndHook(Runnable r) {
82,7 → 101,7
* Namespace for variables used by the enviroment
*/
private static String namespace() {
return "$net.outlyer.runtime";
return "$net.outlyer.runtime.internal";
}
 
/**
101,44 → 120,34
return new StringBuilder(namespace()).append(".")
.append(uniqueVarName()).toString();
}
 
/**
* Gets an engine.
* If the system property "debug" is set to "1" the returned engine
* will dump extra information to the console
* @return New engine
*/
private static ScriptEngine getEngine() {
return new ScriptEngineManager().getEngineByName("rhino");
final ScriptEngine se = new ScriptEngineManager().getEngineByName("rhino");
if (debug) {
return new EngineSink(se);
}
return se;
}
private ScriptEngine execute(final String prependText,
 
private ExecResult execute(final String prependText,
final String appendText,
final Map<String,Object> extraBindings)
throws PluginExecutionException {
final ScriptEngine rhino = getEngine();
currentEngine = rhino;
// First, export in the global namespace the reference to this
// sandbox. This variable isn't meant to be used directly, it's only
// set to refer to it from the boilerplate code (AFAIK there's no
// way to add a binding with a FQ name).
// TODO: Can a fully qualified name be bound directly?
final String globalSanboxVarName = uniqueVarName();
bindings.put(globalSanboxVarName, this);
if (null != extraBindings) {
for (final String key : extraBindings.keySet()) {
bindings.put(key, extraBindings.get(key));
}
bindings.putAll(extraBindings);
}
 
Object result = null;
// Will contain some biolerplate code used to provide access
// to the runtime wrapped-environment
final StringBuilder runtime = new StringBuilder();
// $net.outlyer.runtime.sandbox Contains a reference to this object
// Implementation note: PluginEnvironment.EXPORTED_SANDBOX_VARIABLE should have the same name
// TODO: ? $net.outlyer.runtime.pluginEnvironment
runtime.append("var $net = {\n")
.append(" outlyer : {\n")
.append(" runtime : {\n")
.append(" sandbox : ").append(globalSanboxVarName).append("\n")
.append(" }\n")
.append(" }\n")
.append("};\n");
 
try {
rhino.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
 
147,15 → 156,27
if (null != boilerPlate) {
rhino.eval(boilerPlate);
}
// Create the $net.outlyer.runtime pseudo-namespace...
rhino.eval(runtime.toString());
 
// $net.outlyer.runtime.sandbox Contains a reference to this object
// Implementation note: PluginEnvironment.EXPORTED_SANDBOX_VARIABLE
// should have the same name
final NamespaceContainer.$Net $net = new NamespaceContainer.$Net(pE, this);
assert this == $net.outlyer.runtime.sandbox;
rhino.put("$net", $net);
// ....internal can be used to store random internal data, it's
// a dynamic object so that fields can be created as needed
rhino.eval("$net.outlyer.runtime.internal={};");
 
if (null != prependText) {
rhino.eval(prependText);
}
rhino.eval(new PluginReader(pluginUri));
if (null != pluginUri) {
result = rhino.eval(new PluginReader(pluginUri));
}
else {
result = null;
}
if (null != appendText) {
rhino.eval(appendText);
172,24 → 193,42
catch (final ScriptException e) {
throw new PluginExecutionException("Script exception: " + e.getMessage(), e);
}
finally {
currentEngine = null;
}
return rhino;
return new ExecResult(rhino, result);
}
public void execute() throws PluginExecutionException {
execute(null, null, null);
}
ScriptEngine executeAndGetEngine() throws PluginExecutionException {
return execute(null, null, null).rhino;
}
 
public <T> T createDelayedImplementation(final Class<T> c,
final String objectName)
throws PluginExecutionException {
final String varImpl = uniqueVarName();
 
if (null == c) {
throw new IllegalArgumentException("Can't instantiate null");
}
if (!c.isInterface()) {
throw new IllegalArgumentException("Can only create delayed " +
"implementations for interfaces");
}
if (null == objectName) {
throw new IllegalArgumentException("Implementor's name can't be null");
}
final StringBuilder preCode = new StringBuilder();
 
if (debug) {
preCode.append("// Forward declaration for delayed implementation:\n");
}
preCode.append("var ").append(objectName).append(" = {\n");
for (final Method method : c.getMethods()) {
if (method.getDeclaringClass() != c) {
if (method.getDeclaringClass() == Object.class) { // Implement everything, including hierarchies
continue;
}
preCode.append(method.getName()).append(": null,\n");
196,104 → 235,104
}
preCode.append("};\n");
 
// Could be safely instantiated before actually being assigned IF
// plugins were required to define their methods with
// objectName.methodName = function() {} ...
// but would file with
// objectName = { methodName: function() {}, ... }
// Creating the instance as postCode does the job for both
final StringBuilder postCode = new StringBuilder();
postCode.append(varImpl).append(" = new ")
final ScriptEngine rhino = execute(preCode.toString(), null, null).rhino;
try {
final StringBuilder retriever = new StringBuilder();
retriever.append("new ")
.append(c.getCanonicalName()).append("(").append(objectName).append(");");
if (debug) {
retriever.append("// <== Actual delayed implementation creation");
}
 
final ScriptEngine rhino = execute(preCode.toString(), postCode.toString(), null);
// Could be safely instantiated before actually being assigned IF
// plugins were required to define their methods with
// objectName.methodName = function() {} ...
// but would file with
// objectName = { methodName: function() {}, ... }
// Creating the instance as postCode does the job for both
 
assert (c.isInstance(rhino.get(varImpl)));
return (T) rhino.get(varImpl);
try {
currentEngine = rhino;
// eval() returns the value of the last evaluated line/command
assert (c.isInstance(rhino.eval(retriever.toString())));
return (T) rhino.eval(retriever.toString());
}
finally {
currentEngine = null;
}
}
catch (final ScriptException e) {
throw new PluginExecutionException("Failed to create the delayed " +
"implementation instance: " + e.getMessage(), e);
}
}
 
public <T> T createDelayedImplementation(final Class<T> c)
/**
* {@inheritDoc}
*/
public <T> T createDelayedImplementation(final Class<T> c,
final Map<Method, String> map)
throws PluginExecutionException {
return createDelayedImplementation(c, false);
}
 
public <T> T createDelayedImplementation(final Class<T> c, boolean allowPartial)
throws PluginExecutionException {
return createDelayedImplementation(c, null, allowPartial);
}
 
public <T> T createDelayedImplementation(final Class<T> interfaceClass,
final T fallbackObject)
throws PluginExecutionException {
if (null == fallbackObject) {
throw new IllegalArgumentException("Can't use a null fallback object");
if (null == c) {
throw new IllegalArgumentException("Can't instantiate null");
}
return createDelayedImplementation(interfaceClass, fallbackObject, true);
}
if (!c.isInterface()) {
throw new IllegalArgumentException("Can only create delayed " +
"implementations for interfaces");
}
if (null == map || map.isEmpty()) {
throw new IllegalArgumentException("No mappings; creating a delayed " +
"implementation with no mappings " +
"is equivalent to creating" +
"the object from Java");
}
 
private <T> T createDelayedImplementation(final Class<T> c,
final T fallback,
boolean allowPartial)
throws PluginExecutionException {
final StringBuilder hack = new StringBuilder();
 
final StringBuffer preCode = new StringBuffer();
final String var = uniqueFQVarName();
// Apparently only global namespace objects can be retrieved with get()
// so to simplify retrieval a global variable is used
final String varImpl = uniqueVarName();
 
hack.append(var).append("={\n");
 
final StringBuilder script = new StringBuilder();
 
final String varFallback = uniqueVarName();
 
for (final Method m : c.getMethods()) {
if (m.getDeclaringClass() != c) {
continue;
}
 
final String implFuncName = c.getSimpleName()+"_"+m.getName();
if (allowPartial) {
// This makes undefined functions to be mapped to undefined
// variables (otherwise the interface instantation would fail)
// Apparently defining a var with the same name as a function
// produces no error, while checking for an undefined
// variable/method does fail.
// FIXME: Might be cleaner by handling "undefined"
script.append("var ").append(implFuncName).append(";\n");
if (null != fallback) {
script.append("if (!").append(implFuncName).append(")\n\t")
.append(implFuncName).append("=")
.append(varFallback).append(".").append(m.getName())
.append("\n");
}
// script.append("if (!").append(implFuncName).append(") ")
// .append(implFuncName).append("=null;\n");
}
hack.append("\t").append(m.getName()).append(" : ").append(implFuncName).append(",\n");
preCode.append(var).append(" = {\n");
for (final Method method : map.keySet()) {
preCode.append(method.getName()).append(": ")
.append(map.get(method))
.append("\n,\n");
}
hack.append("};\nvar ")
.append(varImpl).append("=new ")
.append(c.getCanonicalName()).append("(").append(var).append(");");
preCode.append("};\n");
script.append(hack.toString());
final ScriptEngine rhino = execute(preCode.toString(), null, null).rhino;
final HashMap<String, Object> bn = new HashMap();
bn.put(varFallback, fallback);
try {
final StringBuilder retriever = new StringBuilder();
retriever.append("new ")
.append(c.getCanonicalName()).append("(").append(var).append(");");
if (debug) {
retriever.append("// <== Actual delayed implementation creation");
}
 
if (null != fallback) {
script.append("\n// " + bn.get(varFallback).getClass());
// Could be safely instantiated before actually being assigned IF
// plugins were required to define their methods with
// objectName.methodName = function() {} ...
// but would file with
// objectName = { methodName: function() {}, ... }
// Creating the instance as postCode does the job for both
 
try {
currentEngine = rhino;
// eval() returns the value of the last evaluated line/command
assert (c.isInstance(rhino.eval(retriever.toString())));
return (T) rhino.eval(retriever.toString());
}
finally {
currentEngine = null;
}
}
//System.err.println(script.toString());
 
final ScriptEngine rhino = execute(null, script.toString(), bn);
assert (c.isInstance(rhino.get(varImpl)));
return (T) rhino.get(varImpl);
catch (final ScriptException e) {
throw new PluginExecutionException("Failed to create the delayed " +
"implementation instance: " + e.getMessage(), e);
}
}
 
public BasePluginObject getPluginObject() throws PluginExecutionException {
323,6 → 362,8
public URI loadedFrom() {
return pluginUri.normalize(); // FIXME: Return a copy
}
 
public ScriptEngine getCurrentEngine() {
return currentEngine;
}
}
/pluggablejs/trunk/src/net/outlyer/plugins/SandboxAccessor.java
32,12 → 32,28
* it enables exported objects to retrieve the sandbox object in which they're
* being executed.
*
* Implementors must contain a field exactly:
* Implementors must contain a field like
* <pre>
* public Object sandboxGetter = null;
* </pre>
*
* public Callable<Sandbox> _getSandbox = null;
*
* sandboxGetter MUST be public, it can be of class Object or
* Callable&lt;Sandbox&gt;, but shouldn't be used directly, instead, if required,
* use SandboxAccessorImpl#getSandbox(SandboxAccessor) to retrieve it's
* value, or inherit from SandboxAccessorImpl to be able to use
* SandboxAccessorImpl#getSandbox().
* <br />
* Implementation notes: It will be dynamically initialised, no user
* initialisation is required.
*
* The convenience default implementation, {@link SandboxAccessorImpl} can
* be used as a base class if that's possible, to hide such requirement.
*/
public interface SandboxAccessor {
/**
* Obtains the associated sanbdox.
* Implementors can use {@link SandboxAccessor#getSandbox(SandboxAccessor)}.
* @return The sandbox
*/
public Sandbox getSandbox();
}
/pluggablejs/trunk/src/net/outlyer/plugins/PluginEnvironment.java
60,7 → 60,7
private BasePluginObject pluginObject;
private StringBuilder boilerPlate;
private List<String> acceptedTypes = null;
private int maxApi=API.REVISION;
private int maxApi=API.VERSION;
// Since these lines are evaluated they'll be executed twice
// so the lower the number the better to reduce unexpected side effects
private static int linesToCheckForSupport = 1;
71,6 → 71,11
exportedObjects = new HashMap();
pluginObject = null;
boilerPlate = new StringBuilder();
 
// plugin is guaranteed to be a SandboxAccessor, regardless of which
// exact object it ends up mapping to, see enableSandboxAccess()
boilerPlate.append("plugin.sandboxGetter = new java.util.concurrent.Callable(function() {")
.append(" return $net.outlyer.runtime.sandbox; });\n");
}
 
////////////////////////////////////////////////////////
86,7 → 91,17
public Sandbox createSandbox(final URI forUri) throws PluginException {
final ScriptEngine rhino = new ScriptEngineManager().getEngineByName("rhino");
final PluginProperties pp = checkForSupport(forUri);
PluginProperties pp;
if (null != forUri) {
pp = checkForSupport(forUri);
}
else {
pp = new PluginProperties();
pp.apiVersion = API.VERSION;
pp.name = "none";
pp.type = "";
}
 
if (null == pluginObject) {
pluginObject = new PluginObject();
101,9 → 116,9
bindings.put(objectName, exportedObjects.get(objectName));
}
bindings.put("plugin", po);
enableSandboxAccess("plugin", po);
//enableSandboxAccess("plugin", po);
 
return new SandboxImpl(forUri, bindings, pp, boilerPlate.toString());
return new SandboxImpl(this, forUri, bindings, pp, boilerPlate.toString());
}
catch (final CloneNotSupportedException e) {
assert false;
117,12 → 132,17
* the exporting it.
* @param name Name with which to access the object
* @param object Object to export
* @throws IllegalArgumentException If name is <code>null</code>
* @throws IllegalArgumentException If name is "<code>plugin</code>" (use
* {@link #setPluginObject()} instead).
*/
public void exportGlobalObject(final String name, final Object object) {
public void exportObject(final String name, final Object object) {
if (null == name) {
throw new IllegalArgumentException("Can't export an object with" +
"a null name");
}
// Since the plugin object rules' are special (it will be cloned)
// being nice could (?) lead to confusion
if (name.equals("plugin")) {
throw new IllegalArgumentException("Can't export an object named " +
"plugin, use setPluginObject() instead");
133,8 → 153,39
enableSandboxAccess(name, (SandboxAccessor)object);
}
}
 
/**
* Makes a package's contents available in the global namespace.
* (<em>Imports</em> it into JavaScript).
* @param pkg Package to export
* @see #exportPackage(String)
*/
public void exportPackage(final Package pkg) {
if (null == pkg) {
throw new IllegalArgumentException("Can't export a null package");
}
 
boilerPlate.append("importPackage("+pkg.getName()+")");
}
 
/**
* Makes a package's contents available in the global namespace.
* Like {@see #exportPackage(Package)} but exporting by name.
* @param packageName
* @see #exportPackage(Package)
*/
public void exportPackage(final String packageName) {
if (null == packageName) {
throw new IllegalArgumentException("Can't export a null-named package");
}
final Package pkg = Package.getPackage(packageName);
if (null == pkg) {
throw new IllegalArgumentException("Failed to find package "+packageName);
}
exportPackage(pkg);
}
 
/**
* Defines the object to be exported as <code>plugin</code>.
* The <code>plugin</code> object is the only one exported by default.
* If none is set, a default one will be provided.
169,9 → 220,24
// Non-public interface
////////////////////////////////////////////////////////
 
/**
* Makes a {@link SanboxAccessor}'s field <code>getSandbox</code>
* be evaluable as a <code>Callable&lt;Sandbox&gt;</code>, i.e.,
* from Java it will be possible to use:<br />
* <pre>
* Sandbox sb = ( (Callable&lt;Sandbox&gt;) object.getSandbox ).call()
* </pre>
* to retrieve the sandbox, while from JavaScript it will be enough
* with:
* <pre>
* var sb = object.getSandbox()
* </pre>
* @param name Exported object's name
* @param sa Exported object
*/
private void enableSandboxAccess(final String name, final SandboxAccessor sa) {
try {
Field f = sa.getClass().getField("_getSandbox");
Field f = sa.getClass().getField("sandboxGetter");
}
catch (final NoSuchFieldException e) {
throw new IllegalArgumentException("object " + name + " must comply " +
178,12 → 244,9
"with the contract of SandboxAccessor");
}
 
final String callback = name + "._getSandbox";
 
boilerPlate.append(callback).append("=function() {")
.append(" return ")
.append(EXPORTED_SANDBOX_VARIABLE).append(";\n};");
 
boilerPlate.append(name).append(".sandboxGetter=new java.util.concurrent.Callable(function() {")
.append(" return ")
.append(EXPORTED_SANDBOX_VARIABLE).append("; });\n");
}
PluginProperties checkForSupport(final URI uri) throws PluginException {
/pluggablejs/trunk/src/net/outlyer/plugins/package-info.java
0,0 → 1,32
/**
* This package contains the classes used to load JavaScript-based plugins.
* See {@link http://p.outlyer.net./pluggablejs/}
*/
 
// $Id$
 
package net.outlyer.plugins;
 
/*
* Copyright (c) 2008, Toni Corvera. 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.
*
* THIS SOFTWARE IS PROVIDED "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.
*/
Property changes:
Added: svn:keywords
+Rev Id Date
\ No newline at end of property
/pluggablejs/trunk/src/net/outlyer/plugins/PluginObject.java
26,8 → 26,8
 
// $Id$
 
import java.util.LinkedList;
import java.util.List;
import java.util.HashSet;
import java.util.Set;
 
/**
* Default plugin object, adds a "features" field intended to describe
35,22 → 35,33
* the script has been executed.
*/
public class PluginObject extends BasePluginObject {
public List features;
/**
* Plugins can describe which features they provide by adding
* elements to this field. Possible values are application-specific.
* Default: empty
* @see #properties
*/
public Set<String> features;
 
{
features = new LinkedList();
features = new HashSet<String>();
}
 
/**
* Obtains the number of the current execution
* @return Current execution number
* @see Sandbox#getExecution()
*/
public int execution() {
return getSandbox().getExecution();
}
 
/**
* {@inheritDoc}
*/
@Override public Object clone() throws CloneNotSupportedException {
PluginObject po = (PluginObject) super.clone();
po.features = new LinkedList();
po.features.addAll(this.features);
final PluginObject po = (PluginObject) super.clone();
po.features = new HashSet<String>(this.features);
return po;
}
/pluggablejs/trunk/src/net/outlyer/plugins/RuntimeHooks.java
27,9 → 27,9
// $Id$
 
/**
* Provides hooks to the execution
* Provides hooks to some points in the execution process.
*/
public interface RuntimeHooks {
interface RuntimeHooks {
/**
* Adds a callback to be executed after the script is finished
*/
/pluggablejs/trunk/src/net/outlyer/plugins/EngineSink.java
0,0 → 1,118
package net.outlyer.plugins;
 
/*
* Copyright (c) 2008, Toni Corvera. 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.
*
* THIS SOFTWARE IS PROVIDED "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.
*/
 
// $Id$
 
import java.io.PrintStream;
import java.io.Reader;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
 
/**
* Intercepts ScriptEngine's methods and dumps their information to console.
* @see SandboxImpl#getEngine
*/
class EngineSink implements ScriptEngine {
private final ScriptEngine e;
private final PrintStream s;
{
s = System.err;
}
public EngineSink(final ScriptEngine actualEngine) {
e = actualEngine;
}
 
public Object eval(String script, ScriptContext context) throws ScriptException {
return e.eval(script, context);
}
 
public Object eval(Reader reader, ScriptContext context) throws ScriptException {
return e.eval(reader, context);
}
 
public Object eval(String script) throws ScriptException {
s.printf("//[D] eval(String):\n%s//[EOS]\n", script);
return e.eval(script);
}
 
public Object eval(Reader reader) throws ScriptException {
return e.eval(reader);
}
 
public Object eval(String script, Bindings n) throws ScriptException {
return e.eval(script, n);
}
 
public Object eval(Reader reader, Bindings n) throws ScriptException {
return e.eval(reader, n);
}
 
public void put(String key, Object value) {
s.printf("//[D] put('%s', %s)\n", key, value);
e.put(key, value);
}
 
public Object get(String key) {
return e.get(key);
}
 
public Bindings getBindings(int scope) {
return e.getBindings(scope);
}
 
public void setBindings(Bindings bindings, int scope) {
s.printf("//[D] setBindings() scope=%s:\n",
(scope==ScriptContext.ENGINE_SCOPE) ? "ENGINE_SCOPE" : "GLOBAL_SCOPE");
for (final String key : bindings.keySet()) {
s.printf(" %s=%s\n", key, bindings.get(key));
}
s.println("//[EOL]");
e.setBindings(bindings, scope);
}
 
public Bindings createBindings() {
return e.createBindings();
}
 
public ScriptContext getContext() {
return e.getContext();
}
 
public void setContext(ScriptContext context) {
e.setContext(context);
}
 
public ScriptEngineFactory getFactory() {
throw new UnsupportedOperationException("Not supported yet.");
}
 
}
Property changes:
Added: svn:keywords
+Rev Id Date
\ No newline at end of property
/pluggablejs/trunk/src/net/outlyer/plugins/Sandbox.java
26,59 → 26,69
 
// $Id$
 
import java.lang.reflect.Method;
import java.util.Map;
import javax.script.ScriptEngine;
 
/**
* Public methods provided by the sandbox.
* Note that all methods in this interface imply a call to {@link #execute}.
*/
// Note that all methods defined directly in this interface imply a call to {@link #execute}.
public interface Sandbox extends RuntimeHooks, SandboxProperties {
 
/**
* @see #createDelayedImplementation(Class, boolean)
* @deprecated (TEMPORARILY) Until the API stabilizes,
* {@link #createDelayedImplementation(Class, String)} is the only
* secure variant.
*/
<T> T createDelayedImplementation(final Class<T> interfaceClass) throws PluginExecutionException;
 
/**
* Creates an implementation of an interface from JS code
* @param interfaceClass Class of the interface to implement
* @param allowPartialImplementation If true, the implementation would be used
* even if incomplete (note that calling an unimplemented method will produce
* an exception)
* @return The implementation
* @throws net.outlyer.plugins.sandboxing.PluginExecutionException
* @deprecated (TEMPORARILY) Until the API stabilizes,
* {@link #createDelayedImplementation(Class, String)} is the only
* secure variant.
*/
<T> T createDelayedImplementation(final Class<T> interfaceClass,
boolean allowPartialImplementation)
throws PluginExecutionException;
 
/**
* @see #createDelayedImplementation(Class, boolean)
* @param fallbackObject If not null incomplete implementations are allowed and
* calls to undefined methods will be passed to this object
* @deprecated (TEMPORARILY) Until the API stabilizes,
* {@link #createDelayedImplementation(Class, String)} is the only
* secure variant.
*/
<T> T createDelayedImplementation(final Class<T> interfaceClass,
final T fallbackObject)
throws PluginExecutionException;
 
/**
* Creates an implementation of an interface from a JS object
* containing the interface's methods.
* <br />
* <b>Note</b>: Implies a call to {@link #execute()}.
* @param interfaceClass Interface to implement
* @param objectName Name of the JS object implementing the interface
* @return The implementation
* @throws net.outlyer.plugins.PluginExecutionException
* @see #createDelayedImplementation(Class,Map)
* @see #execute()
*/
<T> T createDelayedImplementation(final Class<T> interfaceClass, final String objectName) throws PluginExecutionException;
 
/**
* Creates an implementation of an interface from inline JS code.
* This variant allows more flexibility (e.g. the implementation might
* be split among objects, map to global functions or fallback to other
* object if unimplemented).
* Note the mapped code should be evaluable as a JS function AND
* it shouldn't end in a semicolon, e.g.:
* <br />
* Valid:
* <pre>
* function() { return SomeValue; }
* </pre>
* <pre>
* // myFunc() is a function defined somewhere in the code
* myFunc
* </pre>
* <br />
* Not valid:
* <pre>
* function() { return SomeValue; };
* </pre>
* <pre>
* SomeValue
* </pre>
* <br />
* Where possible {@link #createDelayedImplementation(Class,String)} is
* a much cleaner option.
* <br />
* <b>Note</b>: Implies a call to {@link #execute()}.
* @param interfaceClass
* @param methodToCodeMap
* @return
* @throws net.outlyer.plugins.PluginExecutionException
* @see #createDelayedImplementation(Class,String)
*/
<T> T createDelayedImplementation(final Class<T> interfaceClass,
final Map<Method, String> methodToCodeMap)
throws PluginExecutionException;
/**
* Run the script
*/
void execute() throws PluginExecutionException;
85,8 → 95,18
 
/**
* Obtains object containing the plugin object
* <br />
* <b>Note</b>: Implies a call to {@link #execute()}.
* @see #getPluginName
* @return Plugin object associated to this sandbox
*/
BasePluginObject getPluginObject() throws PluginExecutionException;
 
/**
* Obtains a reference to the engine currently in use, if any.
* If called during an execution it will return the current engine, from calling
* outside will return null.
* @return Current ScriptEngine
*/
ScriptEngine getCurrentEngine();
}
/pluggablejs/trunk/src/net/outlyer/plugins/NamespaceContainer.java
0,0 → 1,59
package net.outlyer.plugins;
 
/*
* Copyright (c) 2008, Toni Corvera. 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.
*
* THIS SOFTWARE IS PROVIDED "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.
*/
 
// $Id$
 
/**
* Provides the hierarchy exported to JavaScript as $net.outlyer.runtime.
*/
class NamespaceContainer {
public static class Runtime {
public final Sandbox sandbox;
public final PluginEnvironment pluginEnvironment;
public Object internal = null;
private Runtime(final PluginEnvironment pe, final Sandbox sandbox_) {
sandbox = sandbox_;
pluginEnvironment = pe;
}
}
 
public static class Outlyer {
public final Runtime runtime;
private Outlyer(final PluginEnvironment pe, final Sandbox sandbox) {
runtime = new Runtime(pe, sandbox);
}
}
public static class $Net {
public final Outlyer outlyer;
$Net(final PluginEnvironment pe, final Sandbox sandbox) {
outlyer = new Outlyer(pe, sandbox);
}
}
}
Property changes:
Added: svn:keywords
+Rev Id Date
\ No newline at end of property
/pluggablejs/trunk/src/net/outlyer/plugins/SandboxAccessorImpl.java
26,24 → 26,45
 
// $Id$
 
import java.lang.reflect.Field;
import java.util.concurrent.Callable;
 
/**
* {@see SandboxAccessor}
* Default implementation of a {@see SandboxAccessor}.
*/
public abstract class SandboxAccessorImpl implements SandboxAccessor {
public Callable<Sandbox> _getSandbox;
protected final Sandbox getSandbox() {
if (null == _getSandbox) {
public Object sandboxGetter;
 
public static Sandbox getSandbox(final SandboxAccessor sa) {
try {
// Retrieve the field...
final Field gS = sa.getClass().getField("sandboxGetter");
// Evaluate as a callable
return ((Callable<Sandbox>)gS.get(sa)).call();
}
catch (final NoSuchFieldException e) {
throw new IllegalStateException(sa.getClass()+" hasn't been correctly initialised", e);
}
catch (final Exception e) {
throw new IllegalStateException("getSandbox produced an exception ("+
e.getClass().getSimpleName()+"),"+
"for object "+sa+" which is not expected!: " +
e.getMessage(), e);
}
}
 
public final Sandbox getSandbox() {
if (null == sandboxGetter) {
throw new IllegalStateException(getClass()+" hasn't been correctly initialised");
}
try {
return _getSandbox.call();
return ((Callable<Sandbox>)sandboxGetter).call();
}
catch (final Exception e) {
throw new IllegalStateException("getSandbox produced an exception, which is not expected!");
throw new IllegalStateException("sandboxGetter produced an " +
"exception, which is not expected!");
}
 
}
}
/pluggablejs/trunk/ChangeLog
0,0 → 1,26
1.1.0build33: 2008-07-01
* Sandbox can be created with no associated file (only boilerPlate code
will be issued)
* Shell supports interactive mode
* Scripts have access to the PluginEnvironment
($net.outlyer.runtime.pluginEnvironment)
* Sandbox allows access to the ScriptEngine in use
* LanguageExtensions (eval and include)
* More opaque hierarchies where appropriate
* Output.print()
* PluginObject.features as a Set instead of a List
 
1.1.0build32: not a release
* Removed the deprecated versions of Sandbox.createDelayedImplementation()
* Cleaner boilerplate code, less intrusive variables created
* Debug mode (prints eval'ed code to stderr), by setting -Ddebug=1
* Corrected/refined SandboxAccessor's specs
* PluginEnvironment.exportGlobalObject -> PluginEnvironment.exportObject
* +PluginEnvironment.exportPackage
* Use of eval() to retrieve objects instead of get() (cleaner
boilerplate, no need for extra variables to retrieve objects)
* Removed extra enableSandboxAccess'es for the plugin object
* Redefined versioning meaning
 
1.0build29: 2008-06-29
* Initial public pre-release
/pluggablejs/trunk
Property changes:
Modified: svn:mergeinfo
Merged /pluggablejs/branches/1.1.0build33:r61