    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         * Gets a cancelable boolean used by the interpreter
    077         * @return a cancelable boolean used by the interpreter
    078         */
    079        AtomicBoolean getCancellation();
    080    }
    081
    082    /**
    083     * A marker interface that solves a simple class name into a fully-qualified one.
    084     * @since 3.3
    085     */
    086    interface ClassNameResolver {
    087        /**
    088         * Resolves a class name.
    089         * @param name the simple class name
    090         * @return the fully qualified class name
    091         */
    092        String resolveClassName(String name);
    093    }
    094
    095    /**
    096     * A marker interface of the JexlContext that processes module definitions.
    097     * It is used by the interpreter during evaluation of the pragma module definitions.
    098     * @since 3.3
    099     */
    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         *         &#64;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}