View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jexl3.internal.introspection;
18  
19  import java.util.Iterator;
20  import java.util.List;
21  
22  import org.apache.commons.jexl3.JexlArithmetic;
23  import org.apache.commons.jexl3.JexlOperator;
24  import org.apache.commons.jexl3.introspection.JexlMethod;
25  import org.apache.commons.jexl3.introspection.JexlPropertyGet;
26  import org.apache.commons.jexl3.introspection.JexlPropertySet;
27  import org.apache.commons.jexl3.introspection.JexlSandbox;
28  import org.apache.commons.jexl3.introspection.JexlUberspect;
29  
30  /**
31   * An uberspect that controls usage of properties, methods and constructors through a sandbox.
32   * @since 3.0
33   */
34  public final class SandboxUberspect implements JexlUberspect {
35      /**
36       * Identity equality.
37       * <p>Spotbugs just <em>hates</em> string identity...</p>
38       * @param lhs left hand side
39       * @param rhs right hand side
40       * @return true if left is identical to right
41       */
42      private static boolean eq(final Object lhs, final Object rhs) {
43          return lhs == rhs;
44      }
45      /** The base uberspect. */
46      private final JexlUberspect uberspect;
47  
48      /**  The sandbox. */
49      private final JexlSandbox sandbox;
50  
51      /**
52       * A constructor for JexlSandbox uberspect.
53       * @param theUberspect the JexlUberspect to sandbox
54       * @param theSandbox the sandbox which is copied to avoid changes at runtime
55       */
56      public SandboxUberspect(final JexlUberspect theUberspect, final JexlSandbox theSandbox) {
57          if (theSandbox == null) {
58              throw new NullPointerException("sandbox can not be null");
59          }
60          if (theUberspect == null) {
61              throw new NullPointerException("uberspect can not be null");
62          }
63          this.uberspect = theUberspect;
64          this.sandbox = theSandbox.copy();
65      }
66  
67      @Override
68      public JexlArithmetic.Uberspect getArithmetic(final JexlArithmetic arithmetic) {
69          return uberspect.getArithmetic(arithmetic);
70      }
71  
72      @Override
73      public Class<?> getClassByName(final String className) {
74          return uberspect.getClassByName(className);
75      }
76  
77      @Override
78      public ClassLoader getClassLoader() {
79          return uberspect.getClassLoader();
80      }
81  
82      @Override
83      public JexlMethod getConstructor(final Object ctorHandle, final Object... args) {
84          final String className;
85          if (ctorHandle instanceof Class<?>) {
86              className = sandbox.execute((Class<?>) ctorHandle, "");
87          } else if (ctorHandle != null) {
88              className = sandbox.execute(ctorHandle.toString(), "");
89          } else {
90              className = null;
91          }
92          return className != null && className != JexlSandbox.NULL ? uberspect.getConstructor(className, args) : null;
93      }
94  
95      @Override
96      public Iterator<?> getIterator(final Object obj) {
97          return uberspect.getIterator(obj);
98      }
99  
100     @Override
101     public JexlMethod getMethod(final Object obj, final String method, final Object... args) {
102         if (obj != null && method != null) {
103             final Class<?> clazz = obj instanceof Class ? (Class<?>) obj : obj.getClass();
104             final String actual = sandbox.execute(clazz, method);
105             if (actual != null && actual != JexlSandbox.NULL) {
106                 return uberspect.getMethod(obj, actual, args);
107             }
108         }
109         return null;
110     }
111 
112     @Override
113     public JexlPropertyGet getPropertyGet(final List<PropertyResolver> resolvers,
114                                           final Object obj,
115                                           final Object identifier) {
116         if (obj != null) {
117             final Class<?> clazz = obj instanceof Class<?>? (Class<?>) obj : obj.getClass();
118             if (identifier != null) {
119                 final String property = identifier.toString();
120                 final String actual = sandbox.read(clazz, property);
121                 if (actual != null) {
122                     // no transformation, strict equality: use identifier before string conversion
123                     final Object pty = eq(actual, property) ? identifier : actual;
124                     return uberspect.getPropertyGet(resolvers, obj, pty);
125                 }
126             } else {
127                 final String actual = sandbox.read(clazz, null);
128                 if (actual != JexlSandbox.NULL) {
129                      return uberspect.getPropertyGet(resolvers, obj, null);
130                 }
131             }
132         }
133         return null;
134     }
135 
136     @Override
137     public JexlPropertyGet getPropertyGet(final Object obj, final Object identifier) {
138         return getPropertyGet(null, obj, identifier);
139     }
140 
141     @Override
142     public JexlPropertySet getPropertySet(final List<PropertyResolver> resolvers,
143                                           final Object obj,
144                                           final Object identifier,
145                                           final Object arg) {
146         if (obj != null) {
147             final Class<?> clazz = obj instanceof Class<?>? (Class<?>) obj : obj.getClass();
148             if (identifier != null) {
149                 final String property = identifier.toString();
150                 final String actual = sandbox.write(clazz, property);
151                 if (actual != null) {
152                     // no transformation, strict equality: use identifier before string conversion
153                     final Object pty = eq(actual, property) ? identifier : actual;
154                     return uberspect.getPropertySet(resolvers, obj, pty, arg);
155                 }
156             } else {
157                 final String actual = sandbox.write(clazz, null);
158                 if (actual != JexlSandbox.NULL) {
159                     return uberspect.getPropertySet(resolvers, obj, null, arg);
160                 }
161             }
162         }
163         return null;
164     }
165 
166     @Override
167     public JexlPropertySet getPropertySet(final Object obj,final Object identifier,final Object arg) {
168         return getPropertySet(null, obj, identifier, arg);
169     }
170 
171     @Override
172     public List<PropertyResolver> getResolvers(final JexlOperator op, final Object obj) {
173         return uberspect.getResolvers(op, obj);
174     }
175 
176     @Override
177     public int getVersion() {
178         return uberspect.getVersion();
179     }
180 
181     @Override
182     public void setClassLoader(final ClassLoader loader) {
183         uberspect.setClassLoader(loader);
184     }
185 }