Author: henrib
Date: Mon Jul 18 11:10:42 2011
New Revision: 1147809

URL: http://svn.apache.org/viewvc?rev=1147809&view=rev
Log:
JEXL-116:
* Added sandbox and sandbox-uberspect + tests

Added:
    
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/Sandbox.java
   (with props)
    
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/SandboxUberspectImpl.java
   (with props)
    
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/TokenMgrError.java
   (with props)
    
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/SandboxTest.java
   (with props)

Added: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/Sandbox.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/Sandbox.java?rev=1147809&view=auto
==============================================================================
--- 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/Sandbox.java
 (added)
+++ 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/Sandbox.java
 Mon Jul 18 11:10:42 2011
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl2.introspection;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A sandbox describes permissions on a class by explicitly allowing or 
forbidding access to methods and properties
+ * through "whitelists" and "blacklists".
+ * <p>
+ * A <b>whitelist</b> explicitly allows methods/properties for a class;
+ * <ul>
+ * <li>
+ * If a whitelist is empty and thus does not contain any names, all 
properties/methods are allowed for its class.
+ * </li>
+ * <li>
+ * If it is not empty, the only allowed properties/methods are the ones 
contained.
+ * </li>
+ * </ul>
+ * </p>
+ * <p>
+ * A <b>blacklist</b> explicitly forbids methods/properties for a class;
+ * <ul>
+ * <li>
+ * If a blacklist is empty and thus does not contain any names, all 
properties/methods are forbidden for its class.
+ * </li>
+ * <li>
+ * If it is not empty, the only forbidden properties/methods are the ones 
contained.
+ * </li>
+ * </ul>
+ * <p>
+ * Permissions are composed of three lists, read, write, execute, each being 
"white" or "black"; .
+ * <ul>
+ * <li><b>read</b> controls readable properties </li>
+ * <li><b>write</b> controls writeable properties</li>
+ * <li><b>execute</b> controls executable methods and constructor/<li>
+ * </ul>
+ * </p>
+ * 
+ * @since 2.1
+ */
+public class Sandbox {
+    /**
+     * The map from class names to permissions.
+     */
+    private final Map<String, Permissions> sandbox;
+    
+    /**
+     * Creates a new default sandbox.
+     */
+    public Sandbox() {
+        sandbox = new HashMap<String, Permissions>();
+    }
+
+    /**
+     * Creates a sandbox based on an existing permissions map.
+     * @param map the permissions map
+     */
+    private Sandbox(Map<String, Permissions> map) {
+        sandbox = map;
+    }
+
+    /**
+     * A base set of names.
+     */
+    public abstract static class Names {
+        /** The set of controlled names. */
+        protected Set<String> names = null;
+
+        /**
+         * Adds a name to this set.
+         * @param name the name to add
+         * @return  true if the name was really added, false if it was already 
present
+         */
+        private boolean add(String name) {
+            if (names == null) {
+                names = new HashSet<String>();
+            }
+            return names.add(name);
+        }
+
+        /**
+         * Whether a given name is allowed or not.
+         * @param name the method/property name to check
+         * @return true if allowed, false if forbidden
+         */
+        public abstract boolean allows(String name);
+    }
+
+    /**
+     * A white set of names.
+     */
+    public static class WhiteSet extends Names {
+        @Override
+        public boolean allows(String name) {
+            return names == null || names.contains(name);
+        }
+    }
+
+    /**
+     * A black set of names.
+     */
+    public static class BlackSet extends Names {
+        @Override
+        public boolean allows(String name) {
+            return names != null && !names.contains(name);
+        }
+    }
+
+    /**
+     * Contains the white or black lists for properties and methods for a 
given class.
+     */
+    public static class Permissions {
+        /** The controlled readable properties. */
+        private final Names read;
+        /** The controlled  writeable properties. */
+        private final Names write;
+        /** The controlled methods. */
+        private final Names execute;
+
+        /**
+         * Creates a new permissions instance.
+         * @param readFlag whether the read property list is white or black
+         * @param writeFlag whether the write property list is white or black
+         * @param executeFlag whether the method list is white of black
+         */
+        Permissions(boolean readFlag, boolean writeFlag, boolean executeFlag) {
+            this.read = readFlag ? new WhiteSet() : new BlackSet();
+            this.write = writeFlag ? new WhiteSet() : new BlackSet();
+            this.execute = executeFlag ? new WhiteSet() : new BlackSet();
+        }
+
+        /**
+         * Adds a list of readable property names to these permissions.
+         * @param pnames the property names
+         * @return this instance of permissions
+         */
+        public Permissions read(String... pnames) {
+            for (String pname : pnames) {
+                read.add(pname);
+            }
+            return this;
+        }
+        /**
+         * Adds a list of writeable property names to these permissions.
+         * @param pnames the property names
+         * @return this instance of permissions
+         */
+        public Permissions write(String... pnames) {
+            for (String pname : pnames) {
+                write.add(pname);
+            }
+            return this;
+        }
+
+        /**
+         * Adds a list of executable methods names to these permissions.
+         * <p>The constructor is denoted as the empty-string, all other 
methods by their names.</p>
+         * @param mnames the method names
+         * @return this instance of permissions
+         */
+        public Permissions execute(String... mnames) {
+            for (String mname : mnames) {
+                execute.add(mname);
+            }
+            return this;
+        }
+
+        /**
+         * Gets the set of readable property names in these permissions.
+         * @return the set of property names
+         */
+        public Names read() {
+            return read;
+        }
+        
+        /**
+         * Gets the set of writeable property names in these permissions.
+         * @return the set of property names
+         */
+        public Names write() {
+            return write;
+        }
+        
+        /**
+         * Gets the set of method names in these permissions.
+         * @return the set of method names
+         */
+        public Names execute() {
+            return execute;
+        }
+
+    }
+
+    /**
+     * Creates the set of permissions for a given class.
+     * @param clazz the class for which these permissions apply
+     * @param readFlag whether the readable property list is white or black
+     * @param writeFlag whether the writeable property list is white or black
+     * @param executeFlag whether the executable method list is white or black
+     * @return the 
+     */
+    public Permissions permissions(String clazz, boolean readFlag, boolean 
writeFlag, boolean executeFlag) {
+        Permissions box = new Permissions(readFlag, writeFlag, executeFlag);
+        sandbox.put(clazz, box);
+        return box;
+    }
+
+    /**
+     * Creates the set of permissions based on white lists for methods and 
properties for a given class.
+     * @param clazz the whitened class name
+     * @return the permissions instance
+     */
+    public Permissions white(String clazz) {
+        return permissions(clazz, true, true, true);
+    }
+
+    /**
+     * Creates the set of permissions based on black lists for methods and 
properties for a given class.
+     * @param clazz the blackened class name
+     * @return the permissions instance
+     */
+    public Permissions black(String clazz) {
+        return permissions(clazz, false, false, false);
+    }
+
+    /**
+     * Gets the set of permissions associated to a class.
+     * @param clazz the class name
+     * @return the permissions or null if none were defined
+     */
+    public Permissions get(String clazz) {
+        return sandbox.get(clazz);
+    }
+}

Propchange: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/Sandbox.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/SandboxUberspectImpl.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/SandboxUberspectImpl.java?rev=1147809&view=auto
==============================================================================
--- 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/SandboxUberspectImpl.java
 (added)
+++ 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/SandboxUberspectImpl.java
 Mon Jul 18 11:10:42 2011
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl2.introspection;
+
+import java.lang.reflect.Constructor;
+import org.apache.commons.jexl2.JexlInfo;
+import org.apache.commons.logging.Log;
+
+/**
+ * An uberspect that controls usage of properties, methods and contructors 
through a sandbox.
+ * @since 2.1
+ */
+public class SandboxUberspectImpl extends UberspectImpl {
+    /**  The sandbox. */
+    protected final Sandbox sandbox;
+
+    /**
+     * A constructor for Sandbox uberspect.
+     * @param runtimeLogger the logger to use or null to use default
+     * @param theSandbox the sandbox instance to use
+     */
+    public SandboxUberspectImpl(Log runtimeLogger, Sandbox theSandbox) {
+        super(runtimeLogger);
+        if (theSandbox == null) {
+            throw new NullPointerException("sandbox can not be null");
+        }
+        this.sandbox = theSandbox;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setLoader(ClassLoader cloader) {
+        base().setLoader(cloader);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Constructor<?> getConstructor(Object ctorHandle, Object[] args, 
JexlInfo info) {
+        String className = null;
+        Class<?> clazz = null;
+        if (ctorHandle instanceof Class<?>) {
+            clazz = (Class<?>) ctorHandle;
+            className = clazz.getName();
+        } else if (ctorHandle != null) {
+            className = ctorHandle.toString();
+        } else {
+            return null;
+        }
+        Sandbox.Permissions box = sandbox.get(className);
+        if (box == null || box.execute().allows("")) {
+            return getConstructor(className, args);
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public JexlMethod getMethod(Object obj, String method, Object[] args, 
JexlInfo info) {
+        if (obj != null) {
+            Sandbox.Permissions box = sandbox.get(obj.getClass().getName());
+            if (box == null || box.execute().allows(method)) {
+                return getMethodExecutor(obj, method, args);
+            }
+
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public JexlPropertyGet getPropertyGet(Object obj, Object identifier, 
JexlInfo info) {
+        if (obj != null) {
+            Sandbox.Permissions box = sandbox.get(obj.getClass().getName());
+            if (box == null || box.read().allows(identifier.toString())) {
+                return super.getPropertyGet(obj, identifier, info);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public JexlPropertySet getPropertySet(final Object obj, final Object 
identifier, Object arg, JexlInfo info) {
+        if (obj != null) {
+            Sandbox.Permissions box = sandbox.get(obj.getClass().getName());
+            if (box == null || box.write().allows(identifier.toString())) {
+                return super.getPropertySet(obj, identifier, arg, info);
+            }
+        }
+        return null;
+
+    }
+}

Propchange: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/SandboxUberspectImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/TokenMgrError.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/TokenMgrError.java?rev=1147809&view=auto
==============================================================================
--- 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/TokenMgrError.java
 (added)
+++ 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/TokenMgrError.java
 Mon Jul 18 11:10:42 2011
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl2.parser;
+
+/**
+ * Token Manager Error.
+ */
+public class TokenMgrError extends Error {
+    /**
+     * The version identifier for this Serializable class.
+     * Increment only if the <i>serialized</i> form of the
+     * class changes.
+     */
+    private static final long serialVersionUID = 1L;
+
+    /*
+     * Ordinals for various reasons why an Error of this type can be thrown.
+     */
+    /**
+     * Lexical error occurred.
+     */
+    public static final int LEXICAL_ERROR = 0;
+    /**
+     * An attempt was made to create a second instance of a static token 
manager.
+     */
+    public static final int STATIC_LEXER_ERROR = 1;
+    /**
+     * Tried to change to an invalid lexical state.
+     */
+    public static final int INVALID_LEXICAL_STATE = 2;
+    /**
+     * Detected (and bailed out of) an infinite loop in the token manager.
+     */
+    public static final int LOOP_DETECTED = 3;
+    /**
+     * Indicates the reason why the exception is thrown. It will have
+     * one of the above 4 values.
+     */
+    private int errorCode;
+    /**
+     * The lexer state.
+     */
+    private int state;
+    /**
+     * The current character.
+     */
+    private char current;
+    /**
+     * Last correct input before error occurs.
+     */
+    private String after;
+    /**
+     * 
+     */
+    private boolean eof;
+    /**
+     * Error line.
+     */
+    private int line;
+    /**
+     * Error column.
+     */
+    private int column;
+    
+    /**
+     * Gets the reason why the exception is thrown.
+     * @return one of the 4 lexical error codes
+     */
+    public int getErrorCode() {
+        return errorCode;
+    }
+
+    /**
+     * Gets the line number.
+     * @return line number.
+     */
+    public int getLine() {
+        return line;
+    }
+
+    /**
+     * Gets the column number.
+     * @return the column.
+     */
+    public int getColumn() {
+        return column;
+    }
+    
+    /**
+     * Gets the last correct input.
+     * @return the string after which the error occured
+     */
+    public String getAfer() {
+        return after;
+    }
+ 
+
+    /**
+     * Returns a detailed message for the Error when it is thrown by the
+     * token manager to indicate a lexical error.
+     * @return the message
+     */
+    @Override
+    public String getMessage() {
+        return ("Lexical error at line "
+                + line + ", column "
+                + column + ".  Encountered: "
+                + (eof ? "<EOF> "
+                   : ("\"" + 
StringParser.escapeString(String.valueOf(current)) + "\"") + " (" + (int) 
current + "), ")
+                + "after : \"" + StringParser.escapeString(after) + "\"");
+    }
+
+
+    /** Constructor with message and reason. */
+    public TokenMgrError(String message, int reason) {
+        super(message);
+        errorCode = reason;
+    }
+
+    /** Full Constructor. */
+    public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int 
errorColumn, String errorAfter, char curChar, int reason) {
+        eof = EOFSeen;
+        state = lexState;
+        line = errorLine;
+        column = errorColumn;
+        after = errorAfter;
+        current = curChar;
+        errorCode = reason;
+    }
+}

Propchange: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/TokenMgrError.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/SandboxTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/SandboxTest.java?rev=1147809&view=auto
==============================================================================
--- 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/SandboxTest.java
 (added)
+++ 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/SandboxTest.java
 Mon Jul 18 11:10:42 2011
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl2;
+
+import java.util.logging.Logger;
+import org.apache.commons.jexl2.introspection.Sandbox;
+import org.apache.commons.jexl2.introspection.SandboxUberspectImpl;
+import org.apache.commons.jexl2.introspection.Uberspect;
+
+/**
+ * Tests sandbox features.
+ */
+public class SandboxTest extends JexlTestCase {
+    static final Logger LOGGER = Logger.getLogger(VarTest.class.getName());
+
+    public static class Foo {
+        String name;
+        public String alias;
+
+        public Foo(String name) {
+            this.name = name;
+            this.alias = name + "-alias";
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String Quux() {
+            return name + "-quux";
+        }
+    }
+
+    public void testCtorBlack() throws Exception {
+        String expr = "new('" + Foo.class.getName() + "', '42')";
+        Script script = JEXL.createScript(expr);
+        Object result;
+        result = script.execute(null);
+        assertEquals("42", ((Foo) result).getName());
+
+        Sandbox sandbox = new Sandbox();
+        sandbox.black(Foo.class.getName()).execute("");
+        Uberspect uber = new SandboxUberspectImpl(null, sandbox);
+        JexlEngine sjexl = new JexlEngine(uber, null, null, null);
+        sjexl.setStrict(true);
+
+        script = sjexl.createScript(expr);
+        try {
+            result = script.execute(null);
+            fail("ctor should not be accessible");
+        } catch (JexlException.Method xmethod) {
+            // ok, ctor should not have been accessible
+            LOGGER.info(xmethod.toString());
+        }
+    }
+
+    public void testMethodBlack() throws Exception {
+        String expr = "foo.Quux()";
+        Script script = JEXL.createScript(expr, "foo");
+        Foo foo = new Foo("42");
+        Object result;
+        result = script.execute(null, foo);
+        assertEquals(foo.Quux(), result);
+
+        Sandbox sandbox = new Sandbox();
+        sandbox.black(Foo.class.getName()).execute("Quux");
+        Uberspect uber = new SandboxUberspectImpl(null, sandbox);
+        JexlEngine sjexl = new JexlEngine(uber, null, null, null);
+        sjexl.setStrict(true);
+
+        script = sjexl.createScript(expr, "foo");
+        try {
+            result = script.execute(null, foo);
+            fail("Quux should not be accessible");
+        } catch (JexlException.Method xmethod) {
+            // ok, Quux should not have been accessible
+            LOGGER.info(xmethod.toString());
+        }
+    }
+
+    public void testGetBlack() throws Exception {
+        String expr = "foo.alias";
+        Script script = JEXL.createScript(expr, "foo");
+        Foo foo = new Foo("42");
+        Object result;
+        result = script.execute(null, foo);
+        assertEquals(foo.alias, result);
+
+        Sandbox sandbox = new Sandbox();
+        sandbox.black(Foo.class.getName()).read("alias");
+        Uberspect uber = new SandboxUberspectImpl(null, sandbox);
+        JexlEngine sjexl = new JexlEngine(uber, null, null, null);
+        sjexl.setStrict(true);
+
+        script = sjexl.createScript(expr, "foo");
+        try {
+            result = script.execute(null, foo);
+            fail("alias should not be accessible");
+        } catch (JexlException.Variable xvar) {
+            // ok, alias should not have been accessible
+            LOGGER.info(xvar.toString());
+        }
+    }
+
+    public void testSetBlack() throws Exception {
+        String expr = "foo.alias = $0";
+        Script script = JEXL.createScript(expr, "foo", "$0");
+        Foo foo = new Foo("42");
+        Object result;
+        result = script.execute(null, foo, "43");
+        assertEquals("43", result);
+
+        Sandbox sandbox = new Sandbox();
+        sandbox.black(Foo.class.getName()).write("alias");
+        Uberspect uber = new SandboxUberspectImpl(null, sandbox);
+        JexlEngine sjexl = new JexlEngine(uber, null, null, null);
+        sjexl.setStrict(true);
+
+        script = sjexl.createScript(expr, "foo", "$0");
+        try {
+            result = script.execute(null, foo, "43");
+            fail("alias should not be accessible");
+        } catch (JexlException.Variable xvar) {
+            // ok, alias should not have been accessible
+            LOGGER.info(xvar.toString());
+        }
+    }
+
+    public void testCtorWhite() throws Exception {
+        String expr = "new('" + Foo.class.getName() + "', '42')";
+        Script script;
+        Object result;
+
+        Sandbox sandbox = new Sandbox();
+        sandbox.white(Foo.class.getName()).execute("");
+        Uberspect uber = new SandboxUberspectImpl(null, sandbox);
+        JexlEngine sjexl = new JexlEngine(uber, null, null, null);
+        sjexl.setStrict(true);
+
+        script = sjexl.createScript(expr);
+        result = script.execute(null);
+        assertEquals("42", ((Foo) result).getName());
+    }
+
+    public void testMethodWhite() throws Exception {
+        Foo foo = new Foo("42");
+        String expr = "foo.Quux()";
+        Script script;
+        Object result;
+
+        Sandbox sandbox = new Sandbox();
+        sandbox.white(Foo.class.getName()).execute("Quux");
+        Uberspect uber = new SandboxUberspectImpl(null, sandbox);
+        JexlEngine sjexl = new JexlEngine(uber, null, null, null);
+        sjexl.setStrict(true);
+
+        script = sjexl.createScript(expr, "foo");
+        result = script.execute(null, foo);
+        assertEquals(foo.Quux(), result);
+    }
+
+    public void testGetWhite() throws Exception {
+        Foo foo = new Foo("42");
+        String expr = "foo.alias";
+        Script script;
+        Object result;
+
+        Sandbox sandbox = new Sandbox();
+        sandbox.white(Foo.class.getName()).read("alias");
+        Uberspect uber = new SandboxUberspectImpl(null, sandbox);
+        JexlEngine sjexl = new JexlEngine(uber, null, null, null);
+        sjexl.setStrict(true);
+
+        script = sjexl.createScript(expr, "foo");
+        result = script.execute(null, foo);
+        assertEquals(foo.alias, result);
+    }
+
+    public void testSetWhite() throws Exception {
+        Foo foo = new Foo("42");
+        String expr = "foo.alias = $0";
+        Script script;
+        Object result;
+
+        Sandbox sandbox = new Sandbox();
+        sandbox.white(Foo.class.getName()).write("alias");
+        Uberspect uber = new SandboxUberspectImpl(null, sandbox);
+        JexlEngine sjexl = new JexlEngine(uber, null, null, null);
+        sjexl.setStrict(true);
+
+        script = sjexl.createScript(expr, "foo", "$0");
+        result = script.execute(null, foo, "43");
+        assertEquals("43", result);
+        assertEquals("43", foo.alias);
+    }
+}

Propchange: 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/SandboxTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to