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           * @return a cancelable boolean used by the interpreter.
92           */
93          AtomicBoolean getCancellation();
94      }
95  
96      /**
97       * A marker interface that solves a simple class name into a fully-qualified one.
98       *
99       * @since 3.3
100      * @since 3.6.0 Removes {@code String resolveClassName(String name)} and extends {@link JexlUberspect.ClassNameResolver} which implements
101      *        {@code String resolveClassName(String name)}.
102      */
103     interface ClassNameResolver extends JexlUberspect.ClassNameResolver {}
104 
105     /**
106      * A marker interface of the JexlContext that processes module definitions.
107      * It is used by the interpreter during evaluation of the pragma module definitions.
108      *
109      * @since 3.3
110      */
111     interface ModuleProcessor {
112         /**
113          * Defines a module.
114          * The module name will be the namespace mapped to the object returned by the evaluation
115          * of its body.
116          *
117          * @param engine the engine evaluating this module pragma.
118          * @param info the info at the pragma location.
119          * @param name the module name.
120          * @param body the module definition which can be its location or source.
121          * @return the module object.
122          */
123         Object processModule(JexlEngine engine, JexlInfo info, String name, String body);
124     }
125 
126     /**
127      * A marker interface of the JexlContext, NamespaceFunctor allows creating an instance
128      * to delegate namespace methods calls to.
129      *
130      * <p>The functor is created once during the lifetime of a script evaluation.</p>
131      */
132     interface NamespaceFunctor {
133         /**
134          * Creates the functor object that will be used instead of the namespace.
135          *
136          * @param context the context.
137          * @return the namespace functor instance.
138          */
139         Object createFunctor(JexlContext context);
140     }
141 
142     /**
143      * A marker interface of the JexlContext that declares how to resolve a namespace from its name;
144      * it is used by the interpreter during evaluation.
145      *
146      * <p>In JEXL, a namespace is an object that serves the purpose of encapsulating functions; for instance,
147      * the "math" namespace would be the proper object to expose functions like "log(...)", "sinus(...)", etc.</p>
148      *
149      * In expressions like "ns:function(...)", the resolver is called with resolveNamespace("ns").
150      *
151      * <p>JEXL itself reserves 'jexl' and 'ujexl' as namespaces for internal purpose; resolving those may lead to
152      * unexpected results.</p>
153      *
154      * @since 3.0
155      */
156     interface NamespaceResolver {
157 
158         /**
159          * Resolves a namespace by its name.
160          * @param name the name.
161          * @return the namespace object.
162          */
163         Object resolveNamespace(String name);
164     }
165 
166     /**
167      * A marker interface of the JexlContext that exposes runtime evaluation options.
168      * @since 3.2
169      */
170     interface OptionsHandle {
171         /**
172          * Gets the current set of options though the context.
173          * <p>
174          * This method will be called once at beginning of evaluation and an interpreter private copy
175          * of the context handled JexlOptions instance used for the duration of the execution;
176          * the context handled JexlOptions instance being only used as the source of that copy,
177          * it can safely alter its boolean flags during execution with no effect, avoiding any behavior ambiguity.
178          * </p>
179          *
180          * @return the engine options.
181          */
182         JexlOptions getEngineOptions();
183     }
184 
185     /**
186      * A marker interface of the JexlContext that processes pragmas.
187      * It is called by the engine before interpreter creation; as a marker of
188      * JexlContext, it is expected to have access and interact with the context
189      * instance.
190      *
191      * @since 3.2
192      */
193     interface PragmaProcessor {
194 
195         /**
196          * Process one pragma.
197          *
198          * @param opts the current evaluator options.
199          * @param key the key.
200          * @param value the value.
201          * @since 3.3
202          */
203         default void processPragma(final JexlOptions opts, final String key, final Object value) {
204             processPragma(key, value);
205         }
206 
207         /**
208          * Process one pragma.
209          *
210          * <p>Never called in 3.3, must be implemented for 3.2 binary compatibility reasons.</p>
211          * <p>Typical implementation in 3.3:</p>
212          * <code>
213          *         &#64;Override
214          *         public void processPragma(String key, Object value) {
215          *             processPragma(null, key, value);
216          *         }
217          * </code>
218          *
219          * @param key the key.
220          * @param value the value.
221          * @deprecated 3.3
222          */
223         @Deprecated
224         void processPragma(String key, Object value);
225     }
226 
227     /**
228      * A marker interface of the {@link JexlContext} that indicates the interpreter to put this context
229      * in the {@link JexlEngine} thread local context instance during evaluation.
230      * <p>
231      * This allows user functions or methods to access the context during a call.
232      * Note that the usual caveats regarding using thread local apply (caching, leaking references, and so on); in particular,
233      * keeping a reference to such a context is to be considered with great care and caution.
234      * It should also be noted that sharing such a context between threads should implicate synchronizing variable
235      * accessing the implementation class.
236      * </p>
237      *
238      * @see JexlEngine#setThreadContext(JexlContext.ThreadLocal)
239      * @see JexlEngine#getThreadContext()
240      */
241     interface ThreadLocal extends JexlContext {
242         // no specific method
243     }
244 
245     /**
246      * Gets the value of a variable.
247      *
248      * @param name the variable's name.
249      * @return the value.
250      */
251     Object get(String name);
252 
253     /**
254      * Checks whether a variable is defined in this context.
255      *
256      * <p>A variable may be defined with a null value; this method checks whether the
257      * value is null or if the variable is undefined.</p>
258      *
259      * @param name the variable's name.
260      * @return true if it exists, false otherwise.
261      */
262     boolean has(String name);
263 
264     /**
265      * Sets the value of a variable.
266      *
267      * @param name the variable's name.
268      * @param value the variable's value.
269      */
270     void set(String name, Object value);
271 }