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