001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.jexl3;
019
020import java.util.concurrent.Callable;
021import java.util.concurrent.atomic.AtomicBoolean;
022
023import org.apache.commons.jexl3.introspection.JexlUberspect;
024
025/**
026 * Manages variables which can be referenced in a JEXL expression.
027 *
028 * <p>JEXL variable names in their simplest form are 'java-like' identifiers.
029 * JEXL also considers 'ant' inspired variables expressions as valid.
030 * For instance, the expression 'x.y.z' is an 'antish' variable and will be resolved as a whole by the context,
031 * i.e. using the key "x.y.z". This proves to be useful to solve "fully qualified class names".</p>
032 *
033 * <p>The interpreter variable resolution algorithm will try the different sequences of identifiers till it finds
034 * one that exists in the context; if "x" is an object known in the context (JexlContext.has("x") returns true),
035 * "x.y" will <em>not</em> be looked up in the context but will most likely refer to "x.getY()".</p>
036 *
037 * <p>Note that JEXL may use '$jexl' and '$ujexl' variables for internal purpose; setting or getting those
038 * variables may lead to unexpected results unless specified otherwise.</p>
039 *
040 * @since 1.0
041 */
042public interface JexlContext {
043
044    /**
045     * A marker interface of the JexlContext that processes annotations.
046     * It is used by the interpreter during evaluation to execute annotation evaluations.
047     * <p>
048     * If the JexlContext is not an instance of an AnnotationProcessor, encountering an annotation will generate
049     * an error or a warning depending on the engine strictness.
050     * </p>
051     *
052     * @since 3.1
053     */
054    interface AnnotationProcessor {
055
056        /**
057         * Processes an annotation.
058         * <p>
059         * All annotations are processed through this method; the statement 'call' is to be performed within
060         * the processAnnotation method. The implementation <em>must</em> perform the call explicitly.
061         * </p>
062         * <p>
063         * The arguments and the statement <em>must not</em> be referenced or cached for longer than the duration
064         * of the processAnnotation call.
065         * </p>
066         *
067         * @param name the annotation name
068         * @param args the arguments of the annotation, evaluated as arguments of this call
069         * @param statement the statement that was annotated; the processor should invoke this statement 'call' method
070         * @return the result of statement.call()
071         * @throws Exception if annotation processing fails
072         */
073        Object processAnnotation(String name, Object[] args, Callable<Object> statement) throws Exception;
074    }
075
076    /**
077     * A marker interface of the JexlContext sharing a cancelling flag.
078     * <p>
079     * A script running in a thread can thus be notified through this reference
080     * of its cancellation through the context. It uses the same interpreter logic
081     * that reacts to cancellation and is an alternative to using callable() and/or
082     * interrupting script interpreter threads.
083     * </p>
084     *
085     * @since 3.2
086     */
087    interface CancellationHandle {
088
089        /**
090         * Gets a cancelable boolean used by the interpreter.
091         *
092         * @return a cancelable boolean used by the interpreter.
093         */
094        AtomicBoolean getCancellation();
095    }
096
097    /**
098     * A marker interface that solves a simple class name into a fully-qualified one.
099     *
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}