Subversion Repositories pub

Compare Revisions

No changes between revisions

Ignore whitespace Rev 50 → Rev 51

/pluggablejs/tags/0.0build14/debian/rules
0,0 → 1,98
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
 
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
 
 
 
 
CFLAGS = -Wall -g
 
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS += -O0
else
CFLAGS += -O2
endif
 
configure: configure-stamp
configure-stamp:
dh_testdir
# Add here commands to configure the package.
 
touch configure-stamp
 
 
build: build-stamp
 
build-stamp: configure-stamp
dh_testdir
 
# Add here commands to compile the package.
$(MAKE)
#docbook-to-man debian/libpluggablejs-java.sgml > libpluggablejs-java.1
 
touch $@
 
clean:
dh_testdir
dh_testroot
rm -f build-stamp configure-stamp
 
# Add here commands to clean up after the build process.
-$(MAKE) clean
 
dh_clean
 
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
 
# Add here commands to install the package into debian/libpluggablejs-java.
$(MAKE) DESTDIR=$(CURDIR)/debian/libpluggablejs-java prefix=/usr install
 
 
# Build architecture-independent files here.
binary-indep: build install
# We have nothing to do by default.
 
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
dh_installchangelogs
dh_installdocs
dh_installexamples
# dh_install
# dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
# dh_installmime
# dh_python
# dh_installinit
# dh_installcron
# dh_installinfo
dh_installman
dh_link
dh_strip
dh_compress
dh_fixperms
# dh_perl
# dh_makeshlibs
dh_installdeb
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
 
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install configure
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/pluggablejs/tags/0.0build14/debian/changelog
0,0 → 1,5
pluggablejs (0.0build14-upstream.0) experimental; urgency=low
 
* Initial Release.
 
-- Toni Corvera <outlyer@gmail.com> Thu, 26 Jun 2008 03:08:21 +0200
/pluggablejs/tags/0.0build14/debian/copyright
0,0 → 1,42
This package was debianized by Toni Corvera <outlyer@gmail.com> on
Thu, 26 Jun 2008 02:54:11 +0200.
 
It was downloaded from <url://example.com>
 
Upstream Author(s):
 
<put author's name and email here>
<likewise for another author>
 
Copyright:
 
<Copyright (C) YYYY Name OfAuthor>
<likewise for another author>
 
License:
 
Redistribution and use in source and binary forms, with or without
modification, are permitted under the terms of the BSD License.
 
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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.
 
On Debian systems, the complete text of the BSD License can be
found in `/usr/share/common-licenses/BSD'.
 
 
The Debian packaging is (C) 2008, Toni Corvera <outlyer@gmail.com> and
is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
 
 
# Please also look if there are files or directories which have a
# different copyright/license attached and list them here.
/pluggablejs/tags/0.0build14/debian/docs
--- tags/0.0build14/debian/README (nonexistent)
+++ tags/0.0build14/debian/README (revision 51)
@@ -0,0 +1,6 @@
+The Debian Package libpluggablejs-java
+----------------------------
+
+Comments regarding the Package
+
+ -- Toni Corvera <outlyer@gmail.com> Thu, 26 Jun 2008 02:54:11 +0200
/pluggablejs/tags/0.0build14/debian/README.Debian
0,0 → 1,6
libpluggablejs-java for Debian
------------------------------
 
<possible notes regarding this package - if none, delete this file>
 
-- Toni Corvera <outlyer@gmail.com> Thu, 26 Jun 2008 02:54:11 +0200
/pluggablejs/tags/0.0build14/debian/control
0,0 → 1,16
Source: pluggablejs
Section: contrib/libs
Priority: extra
Maintainer: Toni Corvera <outlyer@gmail.com>
Build-Depends: debhelper (>= 5), ant
Standards-Version: 3.7.2
 
Package: libpluggablejs-java
Architecture: all
Homepage: http://p.outlyer.net/pluggablejs
Depends: java6-runtime-headless
Description: Simple framework for JavaScript-Java plugging
This package provides a simplistic approach to support plugins in Java
loaded from JavaScript code.
.
See the upstream site.
/pluggablejs/tags/0.0build14/debian/dirs
0,0 → 1,0
usr/bin
/pluggablejs/tags/0.0build14/debian/compat
0,0 → 1,0
5
/pluggablejs/tags/0.0build14/Makefile
0,0 → 1,21
 
prefix:=/usr/local
DESTDIR:=
JAR=dist/pluggablejs.jar
 
all:
ant compile.downstream
 
$(JAR):
ant dist.downstream
 
clean:
ant clean
 
install: $(JAR)
mkdir -p $(DESTDIR)/$(prefix)/share/java
install -m644 -o0 -g0 $(JAR) $(DESTDIR)/$(prefix)/share/java/
 
uninstall:
$(RM) $(DESTDIR)/$(prefix)/share/java/`basename "$(JAR)"`
-rmdir -p $(DESTDIR)/$(prefix)/share/java
/pluggablejs/tags/0.0build14/build.num
0,0 → 1,3
#Build Number for ANT. Do not edit!
#Thu Jun 26 02:53:26 CEST 2008
build.number=14
/pluggablejs/tags/0.0build14/build.xml
0,0 → 1,63
<?xml version="1.0" encoding="utf-8"?>
 
<project name="pluggablejs" default="dist" basedir=".">
<description>Pluggable JS framework</description>
 
<property name="src" location="src"/>
<property name="build" location="obj"/>
<property name="dist" location="dist"/>
<property name="release" location="release"/>
<property name="depends" location="lib"/>
 
<property name="version" value="0.0"/>
 
<target name="init">
<!-- Create timestamp, sets TODAY (full, human), DSTAMP (yyyymmdd) and
TSTAMP (hhmm) -->
<tstamp/>
<!-- Build directory structure -->
<mkdir dir="${build}" />
</target>
 
<target name="compile.real" depends="init" description="Source compilation">
<!-- from ${src} to ${build} -->
<javac srcdir="${src}" destdir="${build}" />
</target>
 
<target name="compile" depends="compile.real">
<!-- Build finished, update number -->
<buildnumber file="build.num"/>
</target>
 
<target name="compile.downstream" depends="compile.real"
description="Compilation without build number increase" />
 
<target name="dist.real" description="Generate the distribution">
<mkdir dir="${dist}/"/>
 
<jar jarfile="${dist}/pluggablejs.jar" basedir="${build}">
<!-- <classpath refid="${third.party.libs}" /> -->
<manifest>
<attribute name="X-COMMENT" value="Standard build" />
<attribute name="Build-Date" value="${TODAY}"/>
<!-- Package.getImplementationVersion() -->
<attribute name="Implementation-Version"
value="${version}-build${build.number}" />
<!--
<attribute name="Class-Path" value="${manifest.classpath}" />
-->
</manifest>
</jar>
<jar destfile="${dist}/pluggablejs-src.jar" basedir="${src}"/>
</target>
 
<target name="dist.downstream" depends="compile.downstream, dist.real" />
<target name="dist" depends="compile, dist.real" />
 
<target name="clean" description="Clean up">
<delete dir="${build}" />
<delete dir="${dist}" />
<delete dir="${release}" />
</target>
</project>
<!-- vim:set ts=4 et noai: -->
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/BasePluginObject.java
0,0 → 1,16
package net.outlyer.plugins;
 
import net.outlyer.plugins.sandboxing.SandboxAccessor;
 
/**
* Simplest object to be exported as "plugin"
* @see PluginObject
*/
public class BasePluginObject extends PluginProperties implements SandboxAccessor, Cloneable {
public String name;
public int version = 0;
 
@Override public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/utils/Input.java
0,0 → 1,34
package net.outlyer.plugins.utils;
 
import java.io.IOException;
import java.io.InputStream;
 
/**
*
*/
public class Input {
 
private final InputStream in;
{
in = System.in;
}
public String readline() {
final StringBuilder sb = new StringBuilder();
 
int c;
try {
do {
c = in.read();
sb.append((char) c);
} while (0 != c && '\n' != c);
}
catch (final IOException e) {
return null;
}
return sb.toString();
}
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/utils/Output.java
0,0 → 1,32
package net.outlyer.plugins.utils;
 
import java.io.PrintStream;
 
/**
* Provides a simplified wrapper for output
*/
public class Output {
 
private final PrintStream ps;
public Output(final PrintStream ps) {
this.ps = ps;
}
public void println(final String s) {
ps.println(s);
}
 
/**
* Note that varargs can't be used transparently from JS
* @param sfmt
* @param args
*/
public void printf(final String sfmt, final Object [] args) {
ps.printf(sfmt, args);
}
public void printf(final String s) {
ps.printf("%s", s);
}
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/utils/Hooks.java
0,0 → 1,14
package net.outlyer.plugins.utils;
 
import net.outlyer.plugins.sandboxing.SandboxAccessorImpl;
 
/**
*
*/
public class Hooks extends SandboxAccessorImpl {
// Due to Rhino's magic passing a JS function() is enough
public void atexit(Runnable callback) {
getSandbox().addEndHook(callback);
}
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/utils/package-info.java
0,0 → 1,10
 
/**
* This package provides some common functionality that might often be
* wanted to be exported as global objects.
* {@see net.outlyer.plugins.sandboxing.PluginEnvironment#exportGlobalObject}.
*/
 
package net.outlyer.plugins.utils;
 
 
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/PluginLocator.java
0,0 → 1,319
package net.outlyer.plugins;
 
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import net.outlyer.plugins.sandboxing.PluginEnvironment;
import net.outlyer.plugins.sandboxing.Sandbox;
 
/**
*
*/
public class PluginLocator {
 
private final List<URI> paths;
private final Library library;
private static final FileFilter jsFileFilter;
private boolean scanned = false;
static {
jsFileFilter = new FileFilter() {
public boolean accept(final File pathname) {
return pathname.isFile() && pathname.canRead() &&
pathname.getName().endsWith(".js");
}
};
}
private static class Library {
private final HashMap<String, List<Sandbox>> byType;
private final HashMap<String, Sandbox> byFilename;
private final HashMap<String, Sandbox> byName;
{
byType = new HashMap<String, List<Sandbox>>();
byFilename = new HashMap<String, Sandbox>();
byName = new HashMap<String, Sandbox>();
}
void add(final String fileName, final BasePluginObject bpo, final Sandbox sbox) {
byName.put(bpo.name, sbox);
byFilename.put(fileName, sbox);
if (byType.get(bpo.type) == null) {
byType.put(bpo.type, new LinkedList<Sandbox>());
}
byType.get(bpo.type).add(sbox);
}
void drop() {
byType.clear();
byFilename.clear();
byName.clear();
}
}
{
paths = new LinkedList<URI>();
library = new Library();
}
public PluginLocator(final URI defaultPath) {
if (null == defaultPath) {
throw new IllegalArgumentException("Null path in list of paths");
}
 
if (defaultPath.getScheme().equals("file")) {
final File path = new File(defaultPath.normalize()).getAbsoluteFile();
if (path.exists() && path.isDirectory() && path.canRead()) {
paths.add(path.toURI().normalize());
}
}
else if (defaultPath.getScheme().equals("jar")) {
final URI normalized = defaultPath.normalize();
if (!normalized.getSchemeSpecificPart().endsWith("/")) {
throw new IllegalArgumentException("Jar file entries must" +
" represent directories");
}
// TODO: Check for existence (Class.getResource())
paths.add(normalized);
}
else {
throw new IllegalArgumentException("Only directories or jar directories are accepted");
}
}
public Sandbox getFirst(final String type, final String name, final String fileName) {
if (null == type && null == name && null == fileName) {
throw new IllegalArgumentException("At least one of type, name or fileName must be non-null");
}
if (!scanned) {
throw new IllegalStateException("Can't retrieve before scanning");
}
final Set<Sandbox> sf = new HashSet<Sandbox>(),
sn = new HashSet<Sandbox>(),
st = new HashSet<Sandbox>();
// All keys are optional but if one of them is not null and yields no
// results then getFirst yields no result
if (null != fileName) {
final Sandbox s = library.byFilename.get(fileName);
if (null == s) {
return null;
}
sf.add(s);
}
if (null != name) {
final Sandbox s = library.byName.get(name);
if (null == s) {
return null;
}
sn.add(s);
}
if (null != type) {
final Collection<Sandbox> byType = library.byType.get(type);
if (byType.isEmpty()) {
return null;
}
st.addAll(byType);
}
Set<Sandbox> inters;
 
if (null != fileName) {
inters = sf;
 
if (null != name) {
assert ! sn.isEmpty();
inters.retainAll(sn);
}
if (!inters.isEmpty() && null != type) {
assert ! st.isEmpty();
inters.retainAll(st);
}
}
else if (null != name) {
assert null == fileName && sf.isEmpty();
inters = sn;
if (null != type) {
assert ! st.isEmpty();
sn.retainAll(st);
}
}
else {
assert null != type && ! st.isEmpty();
assert null == name && sn.isEmpty();
assert null == fileName && sf.isEmpty();
 
inters = st;
}
if (inters.isEmpty()) {
return null;
}
 
return inters.iterator().next();
}
public Collection<Sandbox> getAll(final String type, final String name, final String fileName) {
if (null == type && null == name && null == fileName) {
throw new IllegalArgumentException("At least one of type, name or fileName must be non-null");
}
if (!scanned) {
throw new IllegalStateException("Can't retrieve before scanning");
}
final Set<Sandbox> set = new HashSet<Sandbox>();
if (null != fileName) {
final Sandbox s = library.byFilename.get(fileName);
if (null != s) {
set.add(s);
}
}
if (null != name) {
final Sandbox s = library.byName.get(name);
if (null != s) {
set.add(s);
}
}
if (null != type) {
final Collection<Sandbox> sbox = library.byType.get(type);
if (null != sbox) {
set.addAll(sbox);
}
}
return Collections.unmodifiableSet(set);
}
public void scan(final PluginEnvironment pe) {
if (scanned) {
return;
}
 
for (final URI uri : paths) {
if (uri.getScheme().equals("file")) {
final File dir = new File(uri);
checkDirConsistency(dir);
scan(pe, dir);
}
else {
assert uri.getScheme().equals("jar");
scan(pe, uri);
}
}
 
scanned = true;
}
 
/**
* Scan over a directory
* @param dir Directory to scan
*/
private void scan(final PluginEnvironment pe, final File dir) {
assert dir.isDirectory() && dir.canRead();
for (final File candidateFile : dir.listFiles(jsFileFilter)) {
final URI fileURI = candidateFile.toURI();
try {
final Sandbox sb = pe.createSandbox(fileURI);
final BasePluginObject bpo = sb.getPluginObject();
if (bpo.name == null) {
bpo.name = candidateFile.getName();
}
library.add(candidateFile.getName(), bpo, sb);
}
catch (final Exception e) {
continue;
}
}
}
 
/**
* Scan over a directory inside a jar file
* @param jarUri Directory to scan
* @return LIst of plugins in directory <code>jarUri</code>
*/
private void scan(final PluginEnvironment pe, final URI jarUri) {
assert jarUri.getScheme().equals("jar");
 
try {
final JarURLConnection conn = (JarURLConnection) jarUri.toURL().openConnection();
assert null != conn.getEntryName();
final Enumeration<JarEntry> entries = conn.getJarFile().entries();
final String[] jarURIElements =jarUri.getSchemeSpecificPart().split("!");
assert jarURIElements.length == 2;
final String jarFile = jarURIElements[0]; // = file:....jar
final String root = jarURIElements[1]; // = /path
while (entries.hasMoreElements()) {
final JarEntry je = entries.nextElement();
 
final String url = "/"+je.getName();
if (url.startsWith(root) && !je.isDirectory()) {
// Accepted URI
 
try {
final Sandbox sb = pe.createSandbox(jarUri);
 
final BasePluginObject bpo = sb.getPluginObject();
 
final String fileName = new File(jarUri.getPath()).getName();
if (bpo.name == null) {
bpo.name = fileName;
}
library.add(fileName, bpo, sb);
}
catch (final Exception e) {
continue;
}
}
}
}
catch (IOException e) {
throw new IllegalStateException("Error reading jar file");
}
}
 
/**
* Throws an unchecked exception if something that, on construction, was
* a valid directory, is not anymore.
* @param dir Directory to check
* @throws java.lang.IllegalStateException If the <em>directory</em> is
* no longer a directory or can't be accessed or has ceased to exist.
*/
private static void checkDirConsistency(final File dir)
throws IllegalStateException {
if (!dir.exists() || !dir.isDirectory() || !dir.canRead()) {
throw new IllegalStateException("Permissions of " + dir +
" modified while running");
}
}
public Collection<Sandbox> list() {
if (!scanned) {
throw new IllegalStateException("Can't list before scanning");
}
return Collections.unmodifiableCollection(library.byFilename.values());
}
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/PluginObject.java
0,0 → 1,32
package net.outlyer.plugins;
 
import java.util.LinkedList;
import java.util.List;
 
/**
* Default plugin object, adds a "features" field intended to describe
* the plugin features, and execution() which provides the number of times
* the script has been executed.
*/
public class PluginObject extends BasePluginObject {
public List features;
 
{
features = new LinkedList();
}
public int execution() {
return getSandbox().getExecution();
}
 
@Override public Object clone() throws CloneNotSupportedException {
PluginObject po = (PluginObject) super.clone();
po.features = new LinkedList();
po.features.addAll(this.features);
return po;
}
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/API.java
0,0 → 1,9
package net.outlyer.plugins;
 
/**
*
*/
public final class API {
public static final int REVISION = 1;
public static final int IMPLEMENTATION = 1;
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/PluginProperties.java
0,0 → 1,11
package net.outlyer.plugins;
 
import net.outlyer.plugins.sandboxing.SandboxAccessorImpl;
 
/**
*
*/
public class PluginProperties extends SandboxAccessorImpl {
public int apiVersion = 1;
public String type;
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/sandboxing/PluginEnvironment.java
0,0 → 1,200
package net.outlyer.plugins.sandboxing;
 
import net.outlyer.plugins.PluginException;
import java.io.IOException;
import java.io.LineNumberReader;
import java.lang.reflect.Field;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import net.outlyer.plugins.API;
import net.outlyer.plugins.BasePluginObject;
import net.outlyer.plugins.PluginObject;
import net.outlyer.plugins.PluginProperties;
 
/**
* Provides the environment for {@link net.outlyer.plugins.sandboxing.Sandbox}es.
*/
public class PluginEnvironment {
static class UnsupportedAPIException extends PluginException {
public UnsupportedAPIException(int providedApi) {
super("Plugin has unsupported API ("+providedApi+")");
}
}
static class UnsupportedTypeException extends PluginException {
public UnsupportedTypeException(String pluginType) {
super("Plugin has unsupported type ("+pluginType+")");
}
}
private final Map<String, Object> exportedObjects;
private BasePluginObject pluginObject;
private StringBuilder boilerPlate;
private List<String> acceptedTypes = null;
private int maxApi=API.REVISION;
int linesToCheckForSupport = 5;
static final String EXPORTED_SANDBOX_VARIABLE = "$net.outlyer.runtime.sandbox";
{
exportedObjects = new HashMap();
pluginObject = null;
boilerPlate = new StringBuilder();
}
private void enableSandboxAccess(final String name, final SandboxAccessor sa) {
try {
Field f = sa.getClass().getField("_getSandbox");
}
catch (final NoSuchFieldException e) {
throw new IllegalArgumentException("object " + name + " must comply " +
"with the contract of SandboxAccessor");
}
 
final String callback = name + "._getSandbox";
 
boilerPlate.append(callback).append("=function() {")
.append(" return ")
.append(EXPORTED_SANDBOX_VARIABLE).append(";\n};");
 
}
public void exportGlobalObject(String name, Object object) {
exportedObjects.put(name, object);
if (object instanceof SandboxAccessor) {
enableSandboxAccess(name, (SandboxAccessor)object);
}
}
public void setPluginObject(BasePluginObject pObject) {
pluginObject = pObject;
}
public PluginProperties checkForSupport(final URI uri) throws PluginException {
final ScriptEngine rhino = new ScriptEngineManager().getEngineByName("rhino");
 
try {
// Define a Plugin object with a field named type
rhino.eval("var plugin={ type: null, apiVersion: null };");
}
catch (ScriptException e) {
assert false;
throw new IllegalStateException("Unknown error encountered");
}
 
// First of all check the script for support
Object type = null;
Object apiVersion = null;
// Try to eval each line, since it executes in a sandbox this is
// *relatively* safe
String line;
try {
final LineNumberReader script = new LineNumberReader(new PluginReader(uri));
try {
while ((null == type || null == apiVersion) &&
(null != (line = script.readLine())) &&
script.getLineNumber() < linesToCheckForSupport) {
try {
rhino.eval(line);
if (null == type) {
rhino.eval("$_1_$ = plugin.type;");
type = rhino.get("$_1_$");
}
if (null == apiVersion) {
rhino.eval("$_1_$ = plugin.apiVersion;");
apiVersion = rhino.get("$_1_$");
}
}
catch (ScriptException e) {
// Exceptions are to be expected since none of the guaranteed
// plugin tools are provided in this context they'll try to
// access unexisting objects
}
}
}
finally {
script.close();
}
}
catch (final IOException e) {
throw new PluginExecutionException("Failed while reading plugin: " + e.getMessage(), e);
}
 
if (null == type) {
type = "";
}
if (null == apiVersion) {
apiVersion = 0;
}
final PluginProperties pp = new PluginProperties();
 
try {
pp.apiVersion = Double.valueOf(apiVersion.toString()).intValue();
pp.type = type.toString();
}
catch (final NumberFormatException e) {
throw new PluginException("Incorrect value for apiVersion provided, must be integer");
}
if (null != acceptedTypes) {
if (!acceptedTypes.contains(pp.type)) {
throw new UnsupportedTypeException(pp.type);
}
}
if (pp.apiVersion > maxApi) {
throw new UnsupportedAPIException(pp.apiVersion);
}
return pp;
}
 
public Sandbox createSandbox(final URI forUri) throws PluginException {
final ScriptEngine rhino = new ScriptEngineManager().getEngineByName("rhino");
final PluginProperties pp = checkForSupport(forUri);
 
if (null == pluginObject) {
pluginObject = new PluginObject();
}
 
try {
final PluginObject po = (PluginObject) pluginObject.clone();
 
final Bindings bindings = rhino.createBindings();
 
for (final String objectName : exportedObjects.keySet()) {
bindings.put(objectName, exportedObjects.get(objectName));
}
bindings.put("plugin", po);
enableSandboxAccess("plugin", po);
 
return new SandboxImpl(forUri, bindings, boilerPlate.toString());
}
catch (final CloneNotSupportedException e) {
assert false;
throw new IllegalStateException("Incorrect implementation");
}
}
 
public void setAcceptedTypes(final String ... pluginTypes) {
if (null != pluginTypes) {
for (final String type : pluginTypes) {
if (null == type) {
throw new IllegalArgumentException("The set of plugin types" +
" must be either null, or a set of non-null values");
}
}
}
acceptedTypes = Arrays.asList(pluginTypes);
}
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/sandboxing/SandboxAccessorImpl.java
0,0 → 1,23
package net.outlyer.plugins.sandboxing;
 
import java.util.concurrent.Callable;
 
/**
* {@see SandboxAccessor}
*/
public abstract class SandboxAccessorImpl implements SandboxAccessor {
public Callable<Sandbox> _getSandbox;
protected final Sandbox getSandbox() {
if (null == _getSandbox) {
throw new IllegalStateException(getClass()+" hasn't been correctly initialised");
}
try {
return _getSandbox.call();
}
catch (final Exception e) {
throw new IllegalStateException("getSandbox produced an exception, which is not expected!");
}
}
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/sandboxing/RuntimeHooks.java
0,0 → 1,11
package net.outlyer.plugins.sandboxing;
 
/**
* Provides hooks to the execution
*/
public interface RuntimeHooks {
/**
* Adds a callback to be executed after the script is finished
*/
void addEndHook(final Runnable r);
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/sandboxing/SandboxProperties.java
0,0 → 1,9
package net.outlyer.plugins.sandboxing;
 
/**
* Provides access to some properties of a sandbox
* @see Sandbox
*/
public interface SandboxProperties {
public int getExecution();
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/sandboxing/Sandbox.java
0,0 → 1,46
package net.outlyer.plugins.sandboxing;
 
import net.outlyer.plugins.BasePluginObject;
 
/**
* Public methods provided by the sandbox.
* Note that all methods in this interface imply a call to {@link #execute}.
*/
public interface Sandbox extends RuntimeHooks, SandboxProperties {
 
/**
* @see #createDelayedImplementation(Class, boolean)
*/
<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
*/
<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
*/
<T> T createDelayedImplementation(final Class<T> interfaceClass, final T fallbackObject) throws PluginExecutionException;
<T> T createDelayedImplementation(final Class<T> interfaceClass, final String objectName) throws PluginExecutionException;
 
/**
* Run the script
*/
void execute() throws PluginExecutionException;
 
/**
* Obtains object contauning the plugin object
* @return
*/
BasePluginObject getPluginObject() throws PluginExecutionException;
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/sandboxing/SandboxImpl.java
0,0 → 1,253
package net.outlyer.plugins.sandboxing;
 
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import net.outlyer.plugins.BasePluginObject;
 
/**
* Implementation of the Sandbox interface
*/
class SandboxImpl implements Sandbox {
private final Bindings bindings;
private final URI pluginUri;
private static int nextUniqueVarNum;
private Map<String, Collection<Runnable>> hooks;
private final String boilerPlate;
private int execution = 0;
private static final String END_KEY = "e";
 
static {
nextUniqueVarNum = (int) (1193 * (1+Math.random()));
}
{
hooks = new HashMap<String, Collection<Runnable>>();
hooks.put(END_KEY, new LinkedList<Runnable>());
}
protected SandboxImpl(final URI plugin, final Bindings bs) {
this(plugin, bs, null);
}
protected SandboxImpl(final URI plugin, final Bindings bs, final String boilerPlate) {
bindings = bs;
pluginUri = plugin;
this.boilerPlate = boilerPlate;
}
public void addEndHook(Runnable r) {
hooks.get(END_KEY).add(r);
}
 
/**
* Namespace for variables used by the enviroment
*/
private static String namespace() {
return "$net.outlyer.runtime";
}
 
/**
* Creates a unique variable name.
*/
private static String uniqueVarName() {
return new StringBuilder("$_").append(nextUniqueVarNum+=1193).append("_$").toString();
}
 
/**
* Creates a unique variable name including namespace
* @see #namespace
* @see #uniqueVarName
*/
private static String uniqueFQVarName() {
return new StringBuilder(namespace()).append(".")
.append(uniqueVarName()).toString();
}
private static ScriptEngine getEngine() {
return new ScriptEngineManager().getEngineByName("rhino");
}
private ScriptEngine execute(boolean appendText, String text, final Map<String,Object> extraBindings)
throws PluginExecutionException {
final ScriptEngine rhino = getEngine();
// 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));
}
}
// 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);
 
execution++;
if (null != boilerPlate) {
rhino.eval(boilerPlate);
}
// Create the $net.outlyer.runtime pseudo-namespace...
rhino.eval(runtime.toString());
 
rhino.eval(new PluginReader(pluginUri));
if (appendText) {
rhino.eval(text);
}
// Execute any end hooks
for (final Runnable hook : hooks.get(END_KEY)) {
hook.run();
}
}
catch (final IOException e) {
throw new PluginExecutionException("I/O Error: " + e.getMessage(), e);
}
catch (final ScriptException e) {
throw new PluginExecutionException("Script exception: " + e.getMessage(), e);
}
return rhino;
}
public void execute() throws PluginExecutionException {
execute(false, null, null);
}
 
public <T> T createDelayedImplementation(Class<T> c, String objectName)
throws PluginExecutionException {
final String varImpl = uniqueVarName();
final StringBuilder code = new StringBuilder();
code.append(varImpl).append(" = new ")
.append(c.getCanonicalName()).append("(").append(objectName).append(");");
//System.err.println(code.toString());
final ScriptEngine rhino = execute(true, code.toString(), null);
assert (c.isInstance(rhino.get(varImpl)));
return (T) rhino.get(varImpl);
}
 
public <T> T createDelayedImplementation(Class<T> c) throws PluginExecutionException {
return createDelayedImplementation(c, false);
}
public <T> T createDelayedImplementation(Class<T> c, boolean allowPartial) throws PluginExecutionException {
return createDelayedImplementation(c, null, allowPartial);
}
 
public <T> T createDelayedImplementation(Class<T> interfaceClass, final T fallbackObject) throws PluginExecutionException {
if (null == fallbackObject) {
throw new IllegalArgumentException("Can't use a null fallback object");
}
return createDelayedImplementation(interfaceClass, fallbackObject, true);
}
private <T> T createDelayedImplementation(Class<T> c, 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();
 
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.
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");
}
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(true, script.toString(), bn);
 
assert (c.isInstance(rhino.get(varImpl)));
return (T) rhino.get(varImpl);
}
 
public BasePluginObject getPluginObject() throws PluginExecutionException {
execute();
assert bindings.get("plugin") instanceof BasePluginObject;
return (BasePluginObject) bindings.get("plugin");
}
public int getExecution() {
return execution;
}
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/sandboxing/PluginExecutionException.java
0,0 → 1,25
package net.outlyer.plugins.sandboxing;
 
import net.outlyer.plugins.PluginException;
 
/**
*
*/
public class PluginExecutionException extends PluginException {
 
public PluginExecutionException(Throwable cause) {
super(cause);
}
 
public PluginExecutionException(String message, Throwable cause) {
super(message, cause);
}
 
public PluginExecutionException(String message) {
super(message);
}
 
public PluginExecutionException() {
}
 
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/sandboxing/PluginReader.java
0,0 → 1,51
package net.outlyer.plugins.sandboxing;
 
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
 
/**
* java.io.Reader for plugins, tries to abstract the plugin location (file or jar)
*/
class PluginReader extends Reader {
 
private final Reader readerImpl;
 
PluginReader(final URI uri) throws IOException {
super();
assert null != uri;
try {
if (uri.getScheme().equals("file")) {
readerImpl = new FileReader(new File(uri));
}
else {
final String path = uri.getSchemeSpecificPart().split("!")[1];
final InputStream is = getClass().getResourceAsStream(path);
if (null == is) {
throw new IOException("Failed to get resource for " + uri);
}
readerImpl = new InputStreamReader(is);
}
}
catch (final FileNotFoundException e) {
throw new IOException("Can\'t read input " + uri);
}
}
 
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
return readerImpl.read(cbuf, off, len);
}
 
@Override
public void close() throws IOException {
readerImpl.close();
}
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/sandboxing/SandboxAccessor.java
0,0 → 1,17
package net.outlyer.plugins.sandboxing;
 
/**
* Optional interface for exported objects (see
* {@link net.outlyer.plugins.sandboxing.PluginEnvironment#exportGlobalObject}),
* it enables exported objects to retrieve the sandbox object in which they're
* being executed.
*
* Implementors must contain a field exactly:
*
* 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 {
}
/pluggablejs/tags/0.0build14/src/net/outlyer/plugins/PluginException.java
0,0 → 1,23
package net.outlyer.plugins;
 
/**
*
*/
public class PluginException extends Exception {
 
public PluginException(Throwable cause) {
super(cause);
}
 
public PluginException(String message, Throwable cause) {
super(message, cause);
}
 
public PluginException(String message) {
super(message);
}
 
public PluginException() {
}
 
}