001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.jexl3.internal.introspection;
018
019import org.apache.commons.jexl3.JexlArithmetic;
020import org.apache.commons.jexl3.JexlOperator;
021import org.apache.commons.jexl3.introspection.JexlMethod;
022import org.apache.commons.jexl3.introspection.JexlPropertyGet;
023import org.apache.commons.jexl3.introspection.JexlPropertySet;
024import org.apache.commons.jexl3.introspection.JexlSandbox;
025import org.apache.commons.jexl3.introspection.JexlUberspect;
026
027import java.util.Iterator;
028import java.util.List;
029
030/**
031 * An uberspect that controls usage of properties, methods and constructors through a sandbox.
032 * @since 3.0
033 */
034public final class SandboxUberspect implements JexlUberspect {
035    /** The base uberspect. */
036    private final JexlUberspect uberspect;
037    /**  The sandbox. */
038    private final JexlSandbox sandbox;
039
040    /**
041     * A constructor for JexlSandbox uberspect.
042     * @param theUberspect the JexlUberspect to sandbox
043     * @param theSandbox the sandbox which is copied to avoid changes at runtime
044     */
045    public SandboxUberspect(final JexlUberspect theUberspect, final JexlSandbox theSandbox) {
046        if (theSandbox == null) {
047            throw new NullPointerException("sandbox can not be null");
048        }
049        if (theUberspect == null) {
050            throw new NullPointerException("uberspect can not be null");
051        }
052        this.uberspect = theUberspect;
053        this.sandbox = theSandbox.copy();
054    }
055
056    @Override
057    public void setClassLoader(final ClassLoader loader) {
058        uberspect.setClassLoader(loader);
059    }
060
061    @Override
062    public ClassLoader getClassLoader() {
063        return uberspect.getClassLoader();
064    }
065
066    @Override
067    public int getVersion() {
068        return uberspect.getVersion();
069    }
070
071    @Override
072    public JexlMethod getConstructor(final Object ctorHandle, final Object... args) {
073        final String className;
074        if (ctorHandle instanceof Class<?>) {
075            className = sandbox.execute((Class<?>) ctorHandle, "");
076        } else if (ctorHandle != null) {
077            className = sandbox.execute(ctorHandle.toString(), "");
078        } else {
079            className = null;
080        }
081        return className != null? uberspect.getConstructor(className, args) : null;
082    }
083
084    @Override
085    public JexlMethod getMethod(final Object obj, final String method, final Object... args) {
086        if (obj != null && method != null) {
087            final Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
088            final String actual = sandbox.execute(clazz, method);
089            if (actual != null) {
090                return uberspect.getMethod(obj, actual, args);
091            }
092        }
093        return null;
094    }
095
096    @Override
097    public List<PropertyResolver> getResolvers(final JexlOperator op, final Object obj) {
098        return uberspect.getResolvers(op, obj);
099    }
100
101    @Override
102    public JexlPropertyGet getPropertyGet(final Object obj, final Object identifier) {
103        return getPropertyGet(null, obj, identifier);
104    }
105
106    @Override
107    public JexlPropertyGet getPropertyGet(final List<PropertyResolver> resolvers,
108                                          final Object obj,
109                                          final Object identifier) {
110        if (obj != null && identifier != null) {
111            final String property = identifier.toString();
112            final String actual = sandbox.read(obj.getClass(), property);
113            if (actual != null) {
114                 // no transformation, strict equality: use identifier before string conversion
115                final Object pty = actual == property? identifier : actual;
116                return uberspect.getPropertyGet(resolvers, obj, pty);
117            }
118        }
119        return null;
120    }
121
122    @Override
123    public JexlPropertySet getPropertySet(final Object obj,final Object identifier,final Object arg) {
124        return getPropertySet(null, obj, identifier, arg);
125    }
126
127    @Override
128    public JexlPropertySet getPropertySet(final List<PropertyResolver> resolvers,
129                                          final Object obj,
130                                          final Object identifier,
131                                          final Object arg) {
132        if (obj != null && identifier != null) {
133            final String property = identifier.toString();
134            final String actual = sandbox.write(obj.getClass(), property);
135            if (actual != null) {
136                 // no transformation, strict equality: use identifier before string conversion
137                final Object pty = actual == property? identifier : actual;
138                return uberspect.getPropertySet(resolvers, obj, pty, arg);
139            }
140        }
141        return null;
142    }
143
144    @Override
145    public Iterator<?> getIterator(final Object obj) {
146        return uberspect.getIterator(obj);
147    }
148
149    @Override
150    public JexlArithmetic.Uberspect getArithmetic(final JexlArithmetic arithmetic) {
151        return uberspect.getArithmetic(arithmetic);
152    }
153}