    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}