/pluggablejs/trunk/ChangeLog |
---|
File deleted |
/pluggablejs/trunk/build.num |
---|
1,3 → 1,3 |
#Build Number for ANT. Do not edit! |
#Mon Jun 30 20:53:31 CEST 2008 |
build.number=33 |
#Sun Jun 29 04:30:52 CEST 2008 |
build.number=29 |
/pluggablejs/trunk/debian/changelog |
---|
1,9 → 1,3 |
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/rules |
---|
67,7 → 67,7 |
binary-arch: build install |
dh_testdir |
dh_testroot |
dh_installchangelogs ChangeLog |
dh_installchangelogs |
dh_installdocs |
dh_installexamples |
# dh_install |
/pluggablejs/trunk/debian/docs |
---|
File deleted |
/pluggablejs/trunk/debian/README.Debian |
---|
1,7 → 1,6 |
libpluggablejs-java for Debian |
------------------------------ |
This is debian package created from the upstream source, it might |
not follow the Debian policy correctly. |
<possible notes regarding this package - if none, delete this file> |
-- Toni Corvera <outlyer@gmail.com> Thu, 26 Jun 2008 02:54:11 +0200 |
/pluggablejs/trunk/src/net/outlyer/plugins/EngineSink.java |
---|
File deleted |
Property changes: |
Deleted: svn:keywords |
-Rev Id Date |
\ No newline at end of property |
/pluggablejs/trunk/src/net/outlyer/plugins/package-info.java |
---|
File deleted |
Property changes: |
Deleted: svn:keywords |
-Rev Id Date |
\ No newline at end of property |
/pluggablejs/trunk/src/net/outlyer/plugins/NamespaceContainer.java |
---|
File deleted |
Property changes: |
Deleted: svn:keywords |
-Rev Id Date |
\ No newline at end of property |
/pluggablejs/trunk/src/net/outlyer/plugins/Shell.java |
---|
27,95 → 27,34 |
// $Id$ |
import java.io.File; |
import javax.script.ScriptEngine; |
import javax.script.ScriptException; |
import net.outlyer.plugins.utils.*; |
/** |
* Sample shell for tests, or scripts. |
* Files passed as arguments will be loaded and executed. |
* Sample shell for tests, 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: \n" + |
" java [...] %s <file1.js [file2.js [...]]>\n"+ |
" or\n"+ |
" java [...] %1$s <-i|--interactive>\n", |
System.err.printf("Usage: java [...] %s [file1.js [file2.js [...]]]\n", |
Shell.class.getName()); |
System.exit(1); |
} |
final PluginEnvironment pe = new PluginEnvironment(); |
pe.exportObject("input", new Input()); |
pe.exportObject("out", new Output()); |
pe.exportObject("err", new Output(System.err)); |
pe.exportObject("hooks", new Hooks()); |
pe.exportGlobalObject("input", new Input()); |
pe.exportGlobalObject("out", new Output()); |
pe.exportGlobalObject("err", new Output(System.err)); |
pe.exportGlobalObject("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.exportObject("ui", new GUI()); |
pe.exportObject("gui", new GUI()); |
pe.exportObject("cui", new UI()); // cui stands for Console UI |
pe.exportObject("lang", new LanguageExtensions()); |
pe.exportGlobalObject("ui", new GUI()); |
pe.exportGlobalObject("gui", new GUI()); |
pe.exportGlobalObject("cui", new UI()); // cui stands for Console UI |
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/SandboxImpl.java |
---|
26,9 → 26,6 |
// $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; |
53,24 → 50,11 |
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 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"); |
} |
{ |
78,19 → 62,16 |
hooks.put(END_KEY, new LinkedList<Runnable>()); |
} |
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, final PluginProperties pp) { |
this(plugin, bs, pp, null); |
} |
protected SandboxImpl(final PluginEnvironment pe, final URI plugin, |
final Bindings bs, |
protected SandboxImpl(final URI plugin, final Bindings bs, |
final PluginProperties pp, final String boilerPlate) { |
bindings = bs; |
pluginUri = plugin; // if null => sandbox without file |
pluginUri = plugin; |
this.boilerPlate = boilerPlate; |
properties = pp; |
pE = pe; |
} |
public void addEndHook(Runnable r) { |
101,7 → 82,7 |
* Namespace for variables used by the enviroment |
*/ |
private static String namespace() { |
return "$net.outlyer.runtime.internal"; |
return "$net.outlyer.runtime"; |
} |
/** |
121,32 → 102,42 |
.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() { |
final ScriptEngine se = new ScriptEngineManager().getEngineByName("rhino"); |
if (debug) { |
return new EngineSink(se); |
return new ScriptEngineManager().getEngineByName("rhino"); |
} |
return se; |
} |
private ExecResult execute(final String prependText, |
private ScriptEngine 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) { |
bindings.putAll(extraBindings); |
for (final String key : extraBindings.keySet()) { |
bindings.put(key, extraBindings.get(key)); |
} |
} |
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); |
157,26 → 148,14 |
rhino.eval(boilerPlate); |
} |
// $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={};"); |
// Create the $net.outlyer.runtime pseudo-namespace... |
rhino.eval(runtime.toString()); |
if (null != prependText) { |
rhino.eval(prependText); |
} |
if (null != pluginUri) { |
result = rhino.eval(new PluginReader(pluginUri)); |
} |
else { |
result = null; |
} |
rhino.eval(new PluginReader(pluginUri)); |
if (null != appendText) { |
rhino.eval(appendText); |
193,11 → 172,8 |
catch (final ScriptException e) { |
throw new PluginExecutionException("Script exception: " + e.getMessage(), e); |
} |
finally { |
currentEngine = null; |
} |
return new ExecResult(rhino, result); |
return rhino; |
} |
public void execute() throws PluginExecutionException { |
204,31 → 180,16 |
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 { |
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 String varImpl = uniqueVarName(); |
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() == Object.class) { // Implement everything, including hierarchies |
if (method.getDeclaringClass() != c) { |
continue; |
} |
preCode.append(method.getName()).append(": null,\n"); |
235,16 → 196,6 |
} |
preCode.append("};\n"); |
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"); |
} |
// Could be safely instantiated before actually being assigned IF |
// plugins were required to define their methods with |
// objectName.methodName = function() {} ... |
251,88 → 202,98 |
// 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 ") |
.append(c.getCanonicalName()).append("(").append(objectName).append(");"); |
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()); |
final ScriptEngine rhino = execute(preCode.toString(), postCode.toString(), null); |
assert (c.isInstance(rhino.get(varImpl))); |
return (T) rhino.get(varImpl); |
} |
finally { |
currentEngine = null; |
public <T> T createDelayedImplementation(final Class<T> c) |
throws PluginExecutionException { |
return createDelayedImplementation(c, false); |
} |
public <T> T createDelayedImplementation(final Class<T> c, boolean allowPartial) |
throws PluginExecutionException { |
return createDelayedImplementation(c, null, allowPartial); |
} |
catch (final ScriptException e) { |
throw new PluginExecutionException("Failed to create the delayed " + |
"implementation instance: " + e.getMessage(), e); |
} |
} |
/** |
* {@inheritDoc} |
*/ |
public <T> T createDelayedImplementation(final Class<T> c, |
final Map<Method, String> map) |
public <T> T createDelayedImplementation(final Class<T> interfaceClass, |
final T fallbackObject) |
throws PluginExecutionException { |
if (null == c) { |
throw new IllegalArgumentException("Can't instantiate null"); |
if (null == fallbackObject) { |
throw new IllegalArgumentException("Can't use a null fallback object"); |
} |
if (!c.isInterface()) { |
throw new IllegalArgumentException("Can only create delayed " + |
"implementations for interfaces"); |
return createDelayedImplementation(interfaceClass, fallbackObject, true); |
} |
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"); |
} |
final StringBuffer preCode = new StringBuffer(); |
private <T> T createDelayedImplementation(final Class<T> c, |
final T fallback, |
boolean allowPartial) |
throws PluginExecutionException { |
final StringBuilder hack = new StringBuilder(); |
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(); |
preCode.append(var).append(" = {\n"); |
hack.append(var).append("={\n"); |
for (final Method method : map.keySet()) { |
preCode.append(method.getName()).append(": ") |
.append(map.get(method)) |
.append("\n,\n"); |
} |
final StringBuilder script = new StringBuilder(); |
preCode.append("};\n"); |
final String varFallback = uniqueVarName(); |
final ScriptEngine rhino = execute(preCode.toString(), null, null).rhino; |
try { |
final StringBuilder retriever = new StringBuilder(); |
retriever.append("new ") |
.append(c.getCanonicalName()).append("(").append(var).append(");"); |
if (debug) { |
retriever.append("// <== Actual delayed implementation creation"); |
for (final Method m : c.getMethods()) { |
if (m.getDeclaringClass() != c) { |
continue; |
} |
// 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 String implFuncName = c.getSimpleName()+"_"+m.getName(); |
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()); |
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"); |
} |
finally { |
currentEngine = null; |
// script.append("if (!").append(implFuncName).append(") ") |
// .append(implFuncName).append("=null;\n"); |
} |
hack.append("\t").append(m.getName()).append(" : ").append(implFuncName).append(",\n"); |
} |
catch (final ScriptException e) { |
throw new PluginExecutionException("Failed to create the delayed " + |
"implementation instance: " + e.getMessage(), e); |
hack.append("};\nvar ") |
.append(varImpl).append("=new ") |
.append(c.getCanonicalName()).append("(").append(var).append(");"); |
script.append(hack.toString()); |
final HashMap<String, Object> bn = new HashMap(); |
bn.put(varFallback, fallback); |
if (null != fallback) { |
script.append("\n// " + bn.get(varFallback).getClass()); |
} |
//System.err.println(script.toString()); |
final ScriptEngine rhino = execute(null, script.toString(), bn); |
assert (c.isInstance(rhino.get(varImpl))); |
return (T) rhino.get(varImpl); |
} |
public BasePluginObject getPluginObject() throws PluginExecutionException { |
363,7 → 324,5 |
return pluginUri.normalize(); // FIXME: Return a copy |
} |
public ScriptEngine getCurrentEngine() { |
return currentEngine; |
} |
} |
/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.VERSION; |
private int maxApi=API.REVISION; |
// 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,11 → 71,6 |
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"); |
} |
//////////////////////////////////////////////////////// |
91,18 → 86,8 |
public Sandbox createSandbox(final URI forUri) throws PluginException { |
final ScriptEngine rhino = new ScriptEngineManager().getEngineByName("rhino"); |
PluginProperties pp; |
final PluginProperties pp = checkForSupport(forUri); |
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(); |
} |
116,9 → 101,9 |
bindings.put(objectName, exportedObjects.get(objectName)); |
} |
bindings.put("plugin", po); |
//enableSandboxAccess("plugin", po); |
enableSandboxAccess("plugin", po); |
return new SandboxImpl(this, forUri, bindings, pp, boilerPlate.toString()); |
return new SandboxImpl(forUri, bindings, pp, boilerPlate.toString()); |
} |
catch (final CloneNotSupportedException e) { |
assert false; |
132,17 → 117,12 |
* 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 exportObject(final String name, final Object object) { |
public void exportGlobalObject(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"); |
155,37 → 135,6 |
} |
/** |
* 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. |
220,24 → 169,9 |
// Non-public interface |
//////////////////////////////////////////////////////// |
/** |
* Makes a {@link SanboxAccessor}'s field <code>getSandbox</code> |
* be evaluable as a <code>Callable<Sandbox></code>, i.e., |
* from Java it will be possible to use:<br /> |
* <pre> |
* Sandbox sb = ( (Callable<Sandbox>) 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("sandboxGetter"); |
Field f = sa.getClass().getField("_getSandbox"); |
} |
catch (final NoSuchFieldException e) { |
throw new IllegalArgumentException("object " + name + " must comply " + |
244,9 → 178,12 |
"with the contract of SandboxAccessor"); |
} |
boilerPlate.append(name).append(".sandboxGetter=new java.util.concurrent.Callable(function() {") |
final String callback = name + "._getSandbox"; |
boilerPlate.append(callback).append("=function() {") |
.append(" return ") |
.append(EXPORTED_SANDBOX_VARIABLE).append("; });\n"); |
.append(EXPORTED_SANDBOX_VARIABLE).append(";\n};"); |
} |
PluginProperties checkForSupport(final URI uri) throws PluginException { |
/pluggablejs/trunk/src/net/outlyer/plugins/PluginObject.java |
---|
26,8 → 26,8 |
// $Id$ |
import java.util.HashSet; |
import java.util.Set; |
import java.util.LinkedList; |
import java.util.List; |
/** |
* Default plugin object, adds a "features" field intended to describe |
35,33 → 35,22 |
* the script has been executed. |
*/ |
public class PluginObject extends BasePluginObject { |
/** |
* 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; |
public List features; |
{ |
features = new HashSet<String>(); |
features = new LinkedList(); |
} |
/** |
* 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 { |
final PluginObject po = (PluginObject) super.clone(); |
po.features = new HashSet<String>(this.features); |
PluginObject po = (PluginObject) super.clone(); |
po.features = new LinkedList(); |
po.features.addAll(this.features); |
return po; |
} |
/pluggablejs/trunk/src/net/outlyer/plugins/RuntimeHooks.java |
---|
27,9 → 27,9 |
// $Id$ |
/** |
* Provides hooks to some points in the execution process. |
* Provides hooks to the execution |
*/ |
interface RuntimeHooks { |
public interface RuntimeHooks { |
/** |
* Adds a callback to be executed after the script is finished |
*/ |
/pluggablejs/trunk/src/net/outlyer/plugins/Sandbox.java |
---|
26,69 → 26,59 |
// $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; |
95,18 → 85,8 |
/** |
* 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/SandboxAccessorImpl.java |
---|
26,45 → 26,24 |
// $Id$ |
import java.lang.reflect.Field; |
import java.util.concurrent.Callable; |
/** |
* Default implementation of a {@see SandboxAccessor}. |
* {@see SandboxAccessor} |
*/ |
public abstract class SandboxAccessorImpl implements SandboxAccessor { |
public Object sandboxGetter; |
public Callable<Sandbox> _getSandbox; |
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) { |
protected final Sandbox getSandbox() { |
if (null == _getSandbox) { |
throw new IllegalStateException(getClass()+" hasn't been correctly initialised"); |
} |
try { |
return ((Callable<Sandbox>)sandboxGetter).call(); |
return _getSandbox.call(); |
} |
catch (final Exception e) { |
throw new IllegalStateException("sandboxGetter produced an " + |
"exception, which is not expected!"); |
throw new IllegalStateException("getSandbox produced an exception, which is not expected!"); |
} |
} |
} |
/pluggablejs/trunk/src/net/outlyer/plugins/API.java |
---|
27,51 → 27,34 |
// $Id$ |
/** |
* 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. |
* API versioning |
*/ |
public final class API { |
/** |
* API Version. |
* Newer versions might break backwards compatibility. |
*/ |
public static final int VERSION = 1; |
// Release will be REVISION.(IMPLEMENTATION-1) i.e. |
// for REVISION=1 and IMPLEMENTATION=1, release would be 1.0 |
/** |
* 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 |
* API Revision. |
* Newer revisions might break backwards compatibility (see |
* {@link #MIN_SUPPORTED_REVISION}). |
*/ |
public static final int REVISION = 0; |
public static final int REVISION = 1; |
/** |
* Number of previous Versions supported. |
* For future use. |
* {@see #VERSION} |
* {@see #MIN_SUPPORTED_VERSION} |
* Implementation of the API revision. |
* Different implementations of an API are guaranteed to maintain |
* the API unchanged. |
* @see #REVISION |
*/ |
public static final int AGE = 0; |
public static final int IMPLEMENTATION = 1; |
/** |
* Minimum API version supported by this implementation. |
* Minimum API revision 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 #VERSION |
* @pre MIN_SUPPORTED_VERSION <= VERSION |
* @see #REVISION |
* @pre MIN_SUPPORTED_REVISION <= REVISION |
*/ |
public static final int MIN_SUPPORTED_VERSION = VERSION - AGE; |
public static final int MIN_SUPPORTED_REVISION = 1; |
} |
/pluggablejs/trunk/src/net/outlyer/plugins/PluginProperties.java |
---|
30,32 → 30,9 |
* Common properties of the plugin object. All of them |
* take sane defaults. |
*/ |
class PluginProperties extends SandboxAccessorImpl { |
/** |
* pluggablejs Api Version against which this plugin was written. |
* Default: 1 |
* @see API#VERSION |
*/ |
public class PluginProperties extends SandboxAccessorImpl { |
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/SandboxProperties.java |
---|
29,10 → 29,10 |
import java.net.URI; |
/** |
* Provides access to properties of a sandbox |
* Provides access to some properties of a sandbox |
* @see Sandbox |
*/ |
interface SandboxProperties { |
public interface SandboxProperties { |
/** |
* Obtains the number of this execution (each time the script is executed |
/pluggablejs/trunk/src/net/outlyer/plugins/utils/LanguageExtensions.java |
---|
File deleted |
Property changes: |
Deleted: 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.PluginEnvironment#exportObject}. |
* {@see net.outlyer.plugins.sandboxing.PluginEnvironment#exportGlobalObject}. |
*/ |
// $Id$ |
/pluggablejs/trunk/src/net/outlyer/plugins/utils/Output.java |
---|
43,9 → 43,6 |
this.ps = ps; |
} |
// Note rhino already provides print() and println() in the global |
// namespace |
public void println() { |
ps.println(); |
} |
64,10 → 61,6 |
} |
public void printf(final String s) { |
print(s); |
ps.printf("%s", s); |
} |
public void print(final String s) { |
ps.print(s); |
} |
} |
/pluggablejs/trunk/src/net/outlyer/plugins/SandboxAccessor.java |
---|
32,28 → 32,12 |
* it enables exported objects to retrieve the sandbox object in which they're |
* being executed. |
* |
* Implementors must contain a field like |
* <pre> |
* public Object sandboxGetter = null; |
* </pre> |
* Implementors must contain a field exactly: |
* |
* sandboxGetter MUST be public, it can be of class Object or |
* Callable<Sandbox>, 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. |
* public Callable<Sandbox> _getSandbox = null; |
* |
* 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/Makefile |
---|
1,32 → 1,26 |
# $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 |
dist/$(jarbasename): |
$(JAR): |
ant dist.downstream |
clean: |
ant clean |
install: dist/$(jarbasename) |
test 0 -eq `id -u` # Must be root (or use fakeroot) |
install: $(JAR) |
mkdir -p $(DESTDIR)/$(prefix)/share/java $(bindir)/ |
install -m644 -o0 -g0 dist/$(jarbasename) $(DESTDIR)/$(prefix)/share/java/ |
cd $(DESTDIR)/$(prefix)/share/java && ln -s $(jarbasename) pluggablejs.jar |
install -m644 -o0 -g0 $(JAR) $(DESTDIR)/$(prefix)/share/java/ |
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/$(jarbasename) |
$(RM) $(DESTDIR)/$(prefix)/share/java/`basename "$(JAR)"` |
-rmdir -p $(DESTDIR)/$(prefix)/share/java |
Property changes: |
Deleted: svn:keywords |
-Rev Id Date |
\ No newline at end of property |
/pluggablejs/trunk/samples/interactive-call.js |
---|
File deleted |
/pluggablejs/trunk/samples/langext-included.js |
---|
File deleted |
/pluggablejs/trunk/samples/langext.js |
---|
File deleted |
/pluggablejs/trunk/build.xml |
---|
9,8 → 9,7 |
<property name="release" location="release"/> |
<property name="depends" location="lib"/> |
<property name="version" value="1.1.0"/> |
<property name="jarbasename" value="pluggablejs-${version}-build" /><!-- followed by build.number, can't resolve yet --> |
<property name="version" value="1.0"/> |
<target name="init"> |
<!-- Create timestamp, sets TODAY (full, human), DSTAMP (yyyymmdd) and |
42,7 → 41,7 |
<target name="dist.real" description="Generate the distribution"> |
<mkdir dir="${dist}/"/> |
<jar jarfile="${dist}/${jarbasename}${build.number}.jar" basedir="${build}"> |
<jar jarfile="${dist}/pluggablejs.jar" basedir="${build}"> |
<!-- <classpath refid="${third.party.libs}" /> --> |
<manifest> |
<attribute name="X-COMMENT" value="Standard build" /> |
55,7 → 54,7 |
--> |
</manifest> |
</jar> |
<jar destfile="${dist}/${jarbasename}${build.number}-src.jar" basedir="${src}"/> |
<jar destfile="${dist}/pluggablejs-src.jar" basedir="${src}"/> |
</target> |
<target name="dist.downstream" depends="compile.downstream, dist.real" /> |