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 * @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 }