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 *      http://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
023/**
024 * Manages variables which can be referenced in a JEXL expression.
025 *
026 * <p>JEXL variable names in their simplest form are 'java-like' identifiers.
027 * JEXL also considers 'ant' inspired variables expressions as valid.
028 * For instance, the expression 'x.y.z' is an 'antish' variable and will be resolved as a whole by the context,
029 * i.e. using the key "x.y.z". This proves to be useful to solve "fully qualified class names".</p>
030 *
031 * <p>The interpreter variable resolution algorithm will try the different sequences of identifiers till it finds
032 * one that exists in the context; if "x" is an object known in the context (JexlContext.has("x") returns true),
033 * "x.y" will <em>not</em> be looked up in the context but will most likely refer to "x.getY()".</p>
034 *
035 * <p>Note that JEXL may use '$jexl' and '$ujexl' variables for internal purpose; setting or getting those
036 * variables may lead to unexpected results unless specified otherwise.</p>
037 *
038 * @since 1.0
039 */
040public interface JexlContext {
041
042    /**
043     * A marker interface of the JexlContext that processes annotations.
044     * It is used by the interpreter during evaluation to execute annotation evaluations.
045     * <p>If the JexlContext is not an instance of an AnnotationProcessor, encountering an annotation will generate
046     * an error or a warning depending on the engine strictness.
047     * @since 3.1
048     */
049    interface AnnotationProcessor {
050        /**
051         * Processes an annotation.
052         * <p>All annotations are processed through this method; the statement 'call' is to be performed within
053         * the processAnnotation method. The implementation <em>must</em> perform the call explicitly.
054         * <p>The arguments and the statement <em>must not</em> be referenced or cached for longer than the duration
055         * of the processAnnotation call.
056         *
057         * @param name the annotation name
058         * @param args the arguments of the annotation, evaluated as arguments of this call
059         * @param statement the statement that was annotated; the processor should invoke this statement 'call' method
060         * @return the result of statement.call()
061         * @throws Exception if annotation processing fails
062         */
063        Object processAnnotation(String name, Object[] args, Callable<Object> statement) throws Exception;
064    }
065
066    /**
067     * A marker interface of the JexlContext sharing a cancelling flag.
068     * <p>A script running in a thread can thus be notified through this reference
069     * of its cancellation through the context. It uses the same interpreter logic
070     * that reacts to cancellation and is an alternative to using callable() and/or
071     * interrupting script interpreter threads.
072     * @since 3.2
073     */
074    interface CancellationHandle {
075        /**
076         * @return a cancelable boolean used by the interpreter
077         */
078        AtomicBoolean getCancellation();
079    }
080
081    /**
082     * A marker interface that solves a simple class name into a fully-qualified one.
083     * @since 3.3
084     */
085    interface ClassNameResolver {
086        /**
087         * Resolves a class name.
088         * @param name the simple class name
089         * @return the fully qualified class name
090         */
091        String resolveClassName(String name);
092    }
093
094    /**
095     * A marker interface of the JexlContext that processes module definitions.
096     * It is used by the interpreter during evaluation of the pragma module definitions.
097     * @since 3.3
098     */
099    interface ModuleProcessor {
100        /**
101         * Defines a module.
102         * The module name will be the namespace mapped to the object returned by the evaluation
103         * of its body.
104         * @param engine the engine evaluating this module pragma
105         * @param info the info at the pragma location
106         * @param name the module name
107         * @param body the module definition which can be its location or source
108         * @return the module object
109         */
110        Object processModule(JexlEngine engine, JexlInfo info, String name, String body);
111    }
112
113    /**
114     * A marker interface of the JexlContext, NamespaceFunctor allows creating an instance
115     * to delegate namespace methods calls to.
116     *
117     * <p>The functor is created once during the lifetime of a script evaluation.</p>
118     */
119    interface NamespaceFunctor {
120        /**
121         * Creates the functor object that will be used instead of the namespace.
122         * @param context the context
123         * @return the namespace functor instance
124         */
125        Object createFunctor(JexlContext context);
126    }
127
128    /**
129     * A marker interface of the JexlContext that declares how to resolve a namespace from its name;
130     * it is used by the interpreter during evaluation.
131     *
132     * <p>In JEXL, a namespace is an object that serves the purpose of encapsulating functions; for instance,
133     * the "math" namespace would be the proper object to expose functions like "log(...)", "sinus(...)", etc.</p>
134     *
135     * In expressions like "ns:function(...)", the resolver is called with resolveNamespace("ns").
136     *
137     * <p>JEXL itself reserves 'jexl' and 'ujexl' as namespaces for internal purpose; resolving those may lead to
138     * unexpected results.</p>
139     *
140     * @since 3.0
141     */
142    interface NamespaceResolver {
143
144        /**
145         * Resolves a namespace by its name.
146         * @param name the name
147         * @return the namespace object
148         */
149        Object resolveNamespace(String name);
150    }
151
152    /**
153     * A marker interface of the JexlContext that exposes runtime evaluation options.
154     * @since 3.2
155     */
156    interface OptionsHandle {
157        /**
158         * Retrieves the current set of options though the context.
159         * <p>
160         * This method will be called once at beginning of evaluation and an interpreter private copy
161         * of the context handled JexlOptions instance used for the duration of the execution;
162         * the context handled JexlOptions instance being only used as the source of that copy,
163         * it can safely alter its boolean flags during execution with no effect, avoiding any behavior ambiguity.
164         * @return the engine options
165         */
166        JexlOptions getEngineOptions();
167    }
168
169    /**
170     * A marker interface of the JexlContext that processes pragmas.
171     * It is called by the engine before interpreter creation; as a marker of
172     * JexlContext, it is expected to have access and interact with the context
173     * instance.
174     * @since 3.2
175     */
176    interface PragmaProcessor {
177        /**
178         * Process one pragma.
179         * @param opts the current evaluator options
180         * @param key the key
181         * @param value the value
182         * @since 3.3
183         */
184        default void processPragma(final JexlOptions opts, final String key, final Object value) {
185            processPragma(key, value);
186        }
187
188        /**
189         * Process one pragma.
190         * <p>Never called in 3.3, must be implemented for 3.2 binary compatibility reasons.</p>
191         * <p>Typical implementation in 3.3:</p>
192         * <code>
193         *         &#64;Override
194         *         public void processPragma(String key, Object value) {
195         *             processPragma(null, key, value);
196         *         }
197         * </code>
198         * @param key the key
199         * @param value the value
200         * @deprecated 3.3
201         */
202        @Deprecated
203        void processPragma(String key, Object value);
204    }
205
206    /**
207     * A marker interface  of the JexlContext that indicates the interpreter to put this context
208     * in the JexlEngine thread local context instance during evaluation.
209     * This allows user functions or methods to access the context during a call.
210     * Note that the usual caveats wrt using thread local apply (caching/leaking references, etc.); in particular,
211     * keeping a reference to such a context is to be considered with great care and caution.
212     * It should also be noted that sharing such a context between threads should implicate synchronizing variable
213     * accessing the implementation class.
214     *
215     * @see JexlEngine#setThreadContext(JexlContext.ThreadLocal)
216     * @see JexlEngine#getThreadContext()
217     */
218    interface ThreadLocal extends JexlContext {
219        // no specific method
220    }
221
222    /**
223     * Gets the value of a variable.
224     *
225     * @param name the variable's name
226     * @return the value
227     */
228    Object get(String name);
229
230    /**
231     * Checks whether a variable is defined in this context.
232     *
233     * <p>A variable may be defined with a null value; this method checks whether the
234     * value is null or if the variable is undefined.</p>
235     *
236     * @param name the variable's name
237     * @return true if it exists, false otherwise
238     */
239    boolean has(String name);
240
241    /**
242     * Sets the value of a variable.
243     *
244     * @param name the variable's name
245     * @param value the variable's value
246     */
247    void set(String name, Object value);
248}