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