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