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.parser;
18  
19  import org.apache.commons.jexl3.JexlException;
20  import org.apache.commons.jexl3.JexlFeatures;
21  import org.apache.commons.jexl3.JexlInfo;
22  import org.apache.commons.jexl3.internal.ScriptVisitor;
23  /**
24   * Controls that a script only uses enabled features.
25   */
26  public class FeatureController extends ScriptVisitor {
27  
28      /** The set of features. */
29      private JexlFeatures features;
30  
31      /**
32       * Creates a feature controller.
33       */
34      public FeatureController(final JexlFeatures features) {
35          this.features = features;
36      }
37  
38      /**
39       * Sets the features to controlNode.
40       * @param fdesc the features
41       */
42      public void setFeatures(final JexlFeatures fdesc) {
43          this.features = fdesc;
44      }
45  
46      /**
47       * @return the controlled features
48       */
49      public JexlFeatures getFeatures() {
50          return features;
51      }
52  
53      /**
54       * Perform the control on a node.
55       * <p>Note that controlNode() does *not* visit node children in this class.
56       * @param node the node to controlNode
57       * @throws JexlException.Feature if required feature is disabled
58       */
59      public void controlNode(final JexlNode node) {
60          node.jjtAccept(this, null);
61      }
62  
63      @Override
64      protected Object visitNode(final JexlNode node, final Object data) {
65          // no need to visit them since we close them one by one
66          return data;
67      }
68  
69      /**
70       * Throws a feature exception.
71       * @param feature the feature code
72       * @param node    the node that caused it
73       */
74      public void throwFeatureException(final int feature, final JexlNode node) {
75          final JexlInfo dbgInfo = node.jexlInfo();
76          throw new JexlException.Feature(dbgInfo, feature, "");
77      }
78  
79      /**
80       * Checks whether a node is a string or an integer.
81       * @param child the child node
82       * @return true if string / integer, false otherwise
83       */
84      private boolean isArrayReferenceLiteral(final JexlNode child) {
85          if (child instanceof ASTStringLiteral) {
86              return true;
87          }
88          if (child instanceof ASTNumberLiteral && ((ASTNumberLiteral) child).isInteger()) {
89              return true;
90          }
91          return false;
92      }
93  
94      @Override
95      protected Object visit(final ASTArrayAccess node, final Object data) {
96          if (!features.supportsArrayReferenceExpr()) {
97              for (int i = 0; i < node.jjtGetNumChildren(); ++i) {
98                  final JexlNode child = node.jjtGetChild(i);
99                  if (!isArrayReferenceLiteral(child)) {
100                     throwFeatureException(JexlFeatures.ARRAY_REF_EXPR, child);
101                 }
102             }
103         }
104         return data;
105     }
106 
107     @Override
108     protected Object visit(final ASTWhileStatement node, final Object data) {
109         if (!features.supportsLoops()) {
110             throwFeatureException(JexlFeatures.LOOP, node);
111         }
112         return data;
113     }
114 
115     @Override
116     protected Object visit(final ASTDoWhileStatement node, final Object data) {
117         if (!features.supportsLoops()) {
118             throwFeatureException(JexlFeatures.LOOP, node);
119         }
120         return data;
121     }
122 
123     @Override
124     protected Object visit(final ASTForeachStatement node, final Object data) {
125         if (!features.supportsLoops()) {
126             throwFeatureException(JexlFeatures.LOOP, node);
127         }
128         return data;
129     }
130 
131     @Override
132     protected Object visit(final ASTConstructorNode node, final Object data) {
133         if (!features.supportsNewInstance()) {
134             throwFeatureException(JexlFeatures.NEW_INSTANCE, node);
135         }
136         return data;
137     }
138 
139     @Override
140     protected Object visit(final ASTMethodNode node, final Object data) {
141         if (!features.supportsMethodCall()) {
142             throwFeatureException(JexlFeatures.METHOD_CALL, node);
143         }
144         return data;
145     }
146 
147     @Override
148     protected Object visit(final ASTAnnotation node, final Object data) {
149         if (!features.supportsAnnotation()) {
150             throwFeatureException(JexlFeatures.ANNOTATION, node);
151         }
152         return data;
153     }
154 
155     @Override
156     protected Object visit(final ASTArrayLiteral node, final Object data) {
157         if (!features.supportsStructuredLiteral()) {
158             throwFeatureException(JexlFeatures.STRUCTURED_LITERAL, node);
159         }
160         return data;
161     }
162 
163     @Override
164     protected Object visit(final ASTMapLiteral node, final Object data) {
165         if (!features.supportsStructuredLiteral()) {
166             throwFeatureException(JexlFeatures.STRUCTURED_LITERAL, node);
167         }
168         return data;
169     }
170 
171     @Override
172     protected Object visit(final ASTSetLiteral node, final Object data) {
173         if (!features.supportsStructuredLiteral()) {
174             throwFeatureException(JexlFeatures.STRUCTURED_LITERAL, node);
175         }
176         return data;
177     }
178 
179     @Override
180     protected Object visit(final ASTRangeNode node, final Object data) {
181         if (!features.supportsStructuredLiteral()) {
182             throwFeatureException(JexlFeatures.STRUCTURED_LITERAL, node);
183         }
184         return data;
185     }
186 
187     private Object controlSideEffect(final JexlNode node, final Object data) {
188         final JexlNode lv = node.jjtGetChild(0);
189         if (!features.supportsSideEffectGlobal() && lv.isGlobalVar()) {
190             throwFeatureException(JexlFeatures.SIDE_EFFECT_GLOBAL, lv);
191         }
192         if (!features.supportsSideEffect()) {
193             throwFeatureException(JexlFeatures.SIDE_EFFECT, lv);
194         }
195         return data;
196     }
197 
198     @Override
199     protected Object visit(final ASTAssignment node, final Object data) {
200         return controlSideEffect(node, data);
201     }
202 
203     @Override
204     protected Object visit(final ASTSetAddNode node, final Object data) {
205         return controlSideEffect(node, data);
206     }
207 
208     @Override
209     protected Object visit(final ASTSetMultNode node, final Object data) {
210         return controlSideEffect(node, data);
211     }
212 
213     @Override
214     protected Object visit(final ASTSetDivNode node, final Object data) {
215         return controlSideEffect(node, data);
216     }
217 
218     @Override
219     protected Object visit(final ASTSetModNode node, final Object data) {
220         return controlSideEffect(node, data);
221     }
222 
223     @Override
224     protected Object visit(final ASTSetAndNode node, final Object data) {
225         return controlSideEffect(node, data);
226     }
227 
228     @Override
229     protected Object visit(final ASTSetOrNode node, final Object data) {
230         return controlSideEffect(node, data);
231     }
232 
233     @Override
234     protected Object visit(final ASTSetXorNode node, final Object data) {
235         return controlSideEffect(node, data);
236     }
237 
238     @Override
239     protected Object visit(final ASTSetSubNode node, final Object data) {
240         return controlSideEffect(node, data);
241     }
242 
243     @Override
244     protected Object visit(final ASTSetShiftLeftNode node, final Object data) {
245         return controlSideEffect(node, data);
246     }
247 
248     @Override
249     protected Object visit(final ASTSetShiftRightNode node, final Object data) {
250         return controlSideEffect(node, data);
251     }
252 
253     @Override
254     protected Object visit(final ASTSetShiftRightUnsignedNode node, final Object data) {
255         return controlSideEffect(node, data);
256     }
257 
258     @Override
259     protected Object visit(final ASTGetDecrementNode node, final Object data) {
260         return controlSideEffect(node, data);
261     }
262 
263     @Override
264     protected Object visit(final ASTGetIncrementNode node, final Object data) {
265         return controlSideEffect(node, data);
266     }
267 
268     @Override
269     protected Object visit(final ASTDecrementGetNode node, final Object data) {
270         return controlSideEffect(node, data);
271     }
272 
273     @Override
274     protected Object visit(final ASTIncrementGetNode node, final Object data) {
275         return controlSideEffect(node, data);
276     }
277 }