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  
18  package org.apache.commons.jexl3;
19  
20  import java.util.concurrent.Callable;
21  import java.util.concurrent.atomic.AtomicBoolean;
22  
23  import org.apache.commons.jexl3.introspection.JexlUberspect;
24  
25  /**
26   * Manages variables which can be referenced in a JEXL expression.
27   *
28   * <p>JEXL variable names in their simplest form are 'java-like' identifiers.
29   * JEXL also considers 'ant' inspired variables expressions as valid.
30   * For instance, the expression 'x.y.z' is an 'antish' variable and will be resolved as a whole by the context,
31   * i.e. using the key "x.y.z". This proves to be useful to solve "fully qualified class names".</p>
32   *
33   * <p>The interpreter variable resolution algorithm will try the different sequences of identifiers till it finds
34   * one that exists in the context; if "x" is an object known in the context (JexlContext.has("x") returns true),
35   * "x.y" will <em>not</em> be looked up in the context but will most likely refer to "x.getY()".</p>
36   *
37   * <p>Note that JEXL may use '$jexl' and '$ujexl' variables for internal purpose; setting or getting those
38   * variables may lead to unexpected results unless specified otherwise.</p>
39   *
40   * @since 1.0
41   */
42  public interface JexlContext {
43  
44      /**
45       * A marker interface of the JexlContext that processes annotations.
46       * It is used by the interpreter during evaluation to execute annotation evaluations.
47       * <p>
48       * If the JexlContext is not an instance of an AnnotationProcessor, encountering an annotation will generate
49       * an error or a warning depending on the engine strictness.
50       * </p>
51       *
52       * @since 3.1
53       */
54      interface AnnotationProcessor {
55  
56          /**
57           * Processes an annotation.
58           * <p>
59           * All annotations are processed through this method; the statement 'call' is to be performed within
60           * the processAnnotation method. The implementation <em>must</em> perform the call explicitly.
61           * </p>
62           * <p>
63           * The arguments and the statement <em>must not</em> be referenced or cached for longer than the duration
64           * of the processAnnotation call.
65           * </p>
66           *
67           * @param name the annotation name
68           * @param args the arguments of the annotation, evaluated as arguments of this call
69           * @param statement the statement that was annotated; the processor should invoke this statement 'call' method
70           * @return the result of statement.call()
71           * @throws Exception if annotation processing fails
72           */
73          Object processAnnotation(String name, Object[] args, Callable<Object> statement) throws Exception;
74      }
75  
76      /**
77       * A marker interface of the JexlContext sharing a cancelling flag.
78       * <p>
79       * A script running in a thread can thus be notified through this reference
80       * of its cancellation through the context. It uses the same interpreter logic
81       * that reacts to cancellation and is an alternative to using callable() and/or
82       * interrupting script interpreter threads.
83       * </p>
84       *
85       * @since 3.2
86       */
87      interface CancellationHandle {
88  
89          /**
90           * Gets a cancelable boolean used by the interpreter.
91           *
92           * @return a cancelable boolean used by the interpreter.
93           */
94          AtomicBoolean getCancellation();
95      }
96  
97      /**
98       * A marker interface that solves a simple class name into a fully-qualified one.
99       *
100      * @since 3.3
101      * @since 3.6.0 Removes {@code String resolveClassName(String name)} and extends {@link JexlUberspect.ClassNameResolver} which implements
102      *        {@code String resolveClassName(String name)}.
103      */
104     interface ClassNameResolver extends JexlUberspect.ClassNameResolver {}
105 
106     /**
107      * A marker interface of the JexlContext that processes module definitions.
108      * It is used by the interpreter during evaluation of the pragma module definitions.
109      *
110      * @since 3.3
111      */
112     interface ModuleProcessor {
113 
114         /**
115          * Defines a module.
116          * The module name will be the namespace mapped to the object returned by the evaluation
117          * of its body.
118          *
119          * @param engine the engine evaluating this module pragma.
120          * @param info the info at the pragma location.
121          * @param name the module name.
122          * @param body the module definition which can be its location or source.
123          * @return the module object.
124          */
125         Object processModule(JexlEngine engine, JexlInfo info, String name, String body);
126     }
127 
128     /**
129      * A marker interface of the JexlContext, NamespaceFunctor allows creating an instance
130      * to delegate namespace methods calls to.
131      *
132      * <p>The functor is created once during the lifetime of a script evaluation.</p>
133      */
134     interface NamespaceFunctor {
135 
136         /**
137          * Creates the functor object that will be used instead of the namespace.
138          *
139          * @param context the context.
140          * @return the namespace functor instance.
141          */
142         Object createFunctor(JexlContext context);
143     }
144 
145     /**
146      * A marker interface of the JexlContext that declares how to resolve a namespace from its name;
147      * it is used by the interpreter during evaluation.
148      *
149      * <p>In JEXL, a namespace is an object that serves the purpose of encapsulating functions; for instance,
150      * the "math" namespace would be the proper object to expose functions like "log(...)", "sinus(...)", etc.</p>
151      *
152      * In expressions like "ns:function(...)", the resolver is called with resolveNamespace("ns").
153      *
154      * <p>JEXL itself reserves 'jexl' and 'ujexl' as namespaces for internal purpose; resolving those may lead to
155      * unexpected results.</p>
156      *
157      * @since 3.0
158      */
159     interface NamespaceResolver {
160 
161         /**
162          * Resolves a namespace by its name.
163          *
164          * @param name the name.
165          * @return the namespace object.
166          */
167         Object resolveNamespace(String name);
168     }
169 
170     /**
171      * A marker interface of the JexlContext that exposes runtime evaluation options.
172      *
173      * @since 3.2
174      */
175     interface OptionsHandle {
176 
177         /**
178          * Gets the current set of options though the context.
179          * <p>
180          * This method will be called once at beginning of evaluation and an interpreter private copy
181          * of the context handled JexlOptions instance used for the duration of the execution;
182          * the context handled JexlOptions instance being only used as the source of that copy,
183          * it can safely alter its boolean flags during execution with no effect, avoiding any behavior ambiguity.
184          * </p>
185          *
186          * @return the engine options.
187          */
188         JexlOptions getEngineOptions();
189     }
190 
191     /**
192      * A marker interface of the JexlContext that processes pragmas.
193      * It is called by the engine before interpreter creation; as a marker of
194      * JexlContext, it is expected to have access and interact with the context
195      * instance.
196      *
197      * @since 3.2
198      */
199     interface PragmaProcessor {
200 
201         /**
202          * Process one pragma.
203          *
204          * @param opts the current evaluator options.
205          * @param key the key.
206          * @param value the value.
207          * @since 3.3
208          */
209         default void processPragma(final JexlOptions opts, final String key, final Object value) {
210             processPragma(key, value);
211         }
212 
213         /**
214          * Process one pragma.
215          *
216          * <p>Never called in 3.3, must be implemented for 3.2 binary compatibility reasons.</p>
217          * <p>Typical implementation in 3.3:</p>
218          * <code>
219          *         &#64;Override
220          *         public void processPragma(String key, Object value) {
221          *             processPragma(null, key, value);
222          *         }
223          * </code>
224          *
225          * @param key the key.
226          * @param value the value.
227          * @deprecated 3.3
228          */
229         @Deprecated
230         void processPragma(String key, Object value);
231     }
232 
233     /**
234      * A marker interface of the {@link JexlContext} that indicates the interpreter to put this context
235      * in the {@link JexlEngine} thread local context instance during evaluation.
236      * <p>
237      * This allows user functions or methods to access the context during a call.
238      * Note that the usual caveats regarding using thread local apply (caching, leaking references, and so on); in particular,
239      * keeping a reference to such a context is to be considered with great care and caution.
240      * It should also be noted that sharing such a context between threads should implicate synchronizing variable
241      * accessing the implementation class.
242      * </p>
243      *
244      * @see JexlEngine#setThreadContext(JexlContext.ThreadLocal)
245      * @see JexlEngine#getThreadContext()
246      */
247     interface ThreadLocal extends JexlContext {
248         // no specific method
249     }
250 
251     /**
252      * Gets the value of a variable.
253      *
254      * @param name the variable's name.
255      * @return the value.
256      */
257     Object get(String name);
258 
259     /**
260      * Checks whether a variable is defined in this context.
261      *
262      * <p>A variable may be defined with a null value; this method checks whether the
263      * value is null or if the variable is undefined.</p>
264      *
265      * @param name the variable's name.
266      * @return true if it exists, false otherwise.
267      */
268     boolean has(String name);
269 
270     /**
271      * Sets the value of a variable.
272      *
273      * @param name the variable's name.
274      * @param value the variable's value.
275      */
276     void set(String name, Object value);
277 }