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    *      https://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  import java.util.Objects;
22  
23  import org.apache.commons.jexl3.JexlArithmetic;
24  import org.apache.commons.jexl3.JexlOperator;
25  import org.apache.commons.jexl3.introspection.JexlMethod;
26  import org.apache.commons.jexl3.introspection.JexlPropertyGet;
27  import org.apache.commons.jexl3.introspection.JexlPropertySet;
28  import org.apache.commons.jexl3.introspection.JexlSandbox;
29  import org.apache.commons.jexl3.introspection.JexlUberspect;
30  
31  /**
32   * An uberspect that controls usage of properties, methods and constructors through a sandbox.
33   *
34   * @since 3.0
35   */
36  public final class SandboxUberspect implements JexlUberspect {
37  
38      /**
39       * Identity equality.
40       * <p>Spotbugs just <em>hates</em> string identity...</p>
41       *
42       * @param lhs left hand side
43       * @param rhs right hand side
44       * @return true if left is identical to right
45       */
46      private static boolean eq(final Object lhs, final Object rhs) {
47          return lhs == rhs;
48      }
49  
50      /** The base uberspect. */
51      private final JexlUberspect uberspect;
52  
53      /**  The sandbox. */
54      private final JexlSandbox sandbox;
55  
56      /**
57       * A constructor for JexlSandbox uberspect.
58       *
59       * @param theUberspect the JexlUberspect to sandbox
60       * @param theSandbox the sandbox which is copied to avoid changes at runtime
61       */
62      public SandboxUberspect(final JexlUberspect theUberspect, final JexlSandbox theSandbox) {
63          Objects.requireNonNull(theSandbox, "theSandbox");
64          Objects.requireNonNull(theUberspect, "theUberspect");
65          this.uberspect = theUberspect;
66          this.sandbox = theSandbox.copy();
67      }
68  
69      @Override
70      public JexlArithmetic.Uberspect getArithmetic(final JexlArithmetic arithmetic) {
71          return uberspect.getArithmetic(arithmetic);
72      }
73  
74      @Override
75      public Class<?> getClassByName(final String className) {
76          return uberspect.getClassByName(className);
77      }
78  
79      @Override
80      public ClassLoader getClassLoader() {
81          return uberspect.getClassLoader();
82      }
83  
84      @Override
85      public JexlMethod getConstructor(final Object ctorHandle, final Object... args) {
86          final String className;
87          if (ctorHandle instanceof Class<?>) {
88              className = sandbox.execute((Class<?>) ctorHandle, "");
89          } else if (ctorHandle != null) {
90              className = sandbox.execute(ctorHandle.toString(), "");
91          } else {
92              className = null;
93          }
94          return className != null && className != JexlSandbox.NULL ? uberspect.getConstructor(className, args) : null;
95      }
96  
97      @Override
98      public Iterator<?> getIterator(final Object obj) {
99          return uberspect.getIterator(obj);
100     }
101 
102     @Override
103     public JexlMethod getMethod(final Object obj, final String method, final Object... args) {
104         if (obj != null && method != null) {
105             final Class<?> clazz = obj instanceof Class ? (Class<?>) obj : obj.getClass();
106             final String actual = sandbox.execute(clazz, method);
107             if (actual != null && actual != JexlSandbox.NULL) {
108                 return uberspect.getMethod(obj, actual, args);
109             }
110         }
111         return null;
112     }
113 
114     @Override
115     public JexlPropertyGet getPropertyGet(final List<PropertyResolver> resolvers,
116                                           final Object obj,
117                                           final Object identifier) {
118         if (obj != null) {
119             final Class<?> clazz = obj instanceof Class<?>? (Class<?>) obj : obj.getClass();
120             if (identifier != null) {
121                 final String property = identifier.toString();
122                 final String actual = sandbox.read(clazz, property);
123                 if (actual != null) {
124                     // no transformation, strict equality: use identifier before string conversion
125                     final Object pty = eq(actual, property) ? identifier : actual;
126                     return uberspect.getPropertyGet(resolvers, obj, pty);
127                 }
128             } else {
129                 final String actual = sandbox.read(clazz, null);
130                 if (actual != JexlSandbox.NULL) {
131                      return uberspect.getPropertyGet(resolvers, obj, null);
132                 }
133             }
134         }
135         return null;
136     }
137 
138     @Override
139     public JexlPropertyGet getPropertyGet(final Object obj, final Object identifier) {
140         return getPropertyGet(null, obj, identifier);
141     }
142 
143     @Override
144     public JexlPropertySet getPropertySet(final List<PropertyResolver> resolvers,
145                                           final Object obj,
146                                           final Object identifier,
147                                           final Object arg) {
148         if (obj != null) {
149             final Class<?> clazz = obj instanceof Class<?>? (Class<?>) obj : obj.getClass();
150             if (identifier != null) {
151                 final String property = identifier.toString();
152                 final String actual = sandbox.write(clazz, property);
153                 if (actual != null) {
154                     // no transformation, strict equality: use identifier before string conversion
155                     final Object pty = eq(actual, property) ? identifier : actual;
156                     return uberspect.getPropertySet(resolvers, obj, pty, arg);
157                 }
158             } else {
159                 final String actual = sandbox.write(clazz, null);
160                 if (actual != JexlSandbox.NULL) {
161                     return uberspect.getPropertySet(resolvers, obj, null, arg);
162                 }
163             }
164         }
165         return null;
166     }
167 
168     @Override
169     public JexlPropertySet getPropertySet(final Object obj,final Object identifier,final Object arg) {
170         return getPropertySet(null, obj, identifier, arg);
171     }
172 
173     @Override
174     public List<PropertyResolver> getResolvers(final JexlOperator op, final Object obj) {
175         return uberspect.getResolvers(op, obj);
176     }
177 
178     @Override
179     public int getVersion() {
180         return uberspect.getVersion();
181     }
182 
183     @Override
184     public void setClassLoader(final ClassLoader loader) {
185         uberspect.setClassLoader(loader);
186     }
187 }