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;
021
022/**
023 * Manages variables which can be referenced in a JEXL expression.
024 *
025 * <p>JEXL variable names in their simplest form are 'java-like' identifiers.
026 * JEXL also considers 'ant' inspired variables expressions as valid.
027 * For instance, the expression 'x.y.z' is an 'antish' variable and will be resolved as a whole by the context,
028 * i.e. using the key "x.y.z". This proves to be useful to solve "fully qualified class names".</p>
029 *
030 * <p>The interpreter variable resolution algorithm will try the different sequences of identifiers till it finds
031 * one that exists in the context; if "x" is an object known in the context (JexlContext.has("x") returns true),
032 * "x.y" will <em>not</em> be looked up in the context but will most likely refer to "x.getY()".</p>
033 *
034 * <p>Note that JEXL may use '$jexl' and '$ujexl' variables for internal purpose; setting or getting those
035 * variables may lead to unexpected results unless specified otherwise.</p>
036 *
037 * @since 1.0
038 */
039public interface JexlContext {
040
041    /**
042     * Gets the value of a variable.
043     *
044     * @param name the variable's name
045     * @return the value
046     */
047    Object get(String name);
048
049    /**
050     * Sets the value of a variable.
051     *
052     * @param name the variable's name
053     * @param value the variable's value
054     */
055    void set(String name, Object value);
056
057    /**
058     * Checks whether a variable is defined in this context.
059     *
060     * <p>A variable may be defined with a null value; this method checks whether the
061     * value is null or if the variable is undefined.</p>
062     *
063     * @param name the variable's name
064     * @return true if it exists, false otherwise
065     */
066    boolean has(String name);
067
068    /**
069     * A marker interface of the JexlContext that declares how to resolve a namespace from its name;
070     * it is used by the interpreter during evaluation.
071     *
072     * <p>In JEXL, a namespace is an object that serves the purpose of encapsulating functions; for instance,
073     * the "math" namespace would be the proper object to expose functions like "log(...)", "sinus(...)", etc.</p>
074     *
075     * In expressions like "ns:function(...)", the resolver is called with resolveNamespace("ns").
076     *
077     * <p>JEXL itself reserves 'jexl' and 'ujexl' as namespaces for internal purpose; resolving those may lead to
078     * unexpected results.</p>
079     *
080     * @since 3.0
081     */
082    interface NamespaceResolver {
083
084        /**
085         * Resolves a namespace by its name.
086         * @param name the name
087         * @return the namespace object
088         */
089        Object resolveNamespace(String name);
090    }
091
092    /**
093     * A marker interface of the JexlContext, NamespaceFunctor allows creating an instance
094     * to delegate namespace methods calls to.
095     *
096     * <p>The functor is created once during the lifetime of a script evaluation.</p>
097     */
098    interface NamespaceFunctor {
099        /**
100         * Creates the functor object that will be used instead of the namespace.
101         * @param context the context
102         * @return the namespace functor instance
103         */
104        Object createFunctor(JexlContext context);
105    }
106
107    /**
108     * A marker interface  of the JexlContext that indicates the interpreter to put this context
109     * in the JexlEngine thread local context instance during evaluation.
110     * This allows user functions or methods to access the context during a call.
111     * Note that the usual caveats wrt using thread local apply (caching/leaking references, etc.); in particular,
112     * keeping a reference to such a context is to be considered with great care and caution.
113     * It should also be noted that sharing such a context between threads should implicate synchronizing variable
114     * accessing the implementation class.
115     *
116     * @see JexlEngine#setThreadContext(JexlContext.ThreadLocal)
117     * @see JexlEngine#getThreadContext()
118     */
119    interface ThreadLocal extends JexlContext {
120        // no specific method
121    }
122
123    /**
124     * A marker interface of the JexlContext that allows to process annotations.
125     * It is used by the interpreter during evaluation to execute annotation evaluations.
126     * <p>If the JexlContext is not an instance of an AnnotationProcessor, encountering an annotation will generate
127     * an error or a warning depending on the engine strictness.
128     * @since 3.1
129     */
130    interface AnnotationProcessor {
131        /**
132         * Processes an annotation.
133         * <p>All annotations are processed through this method; the statement 'call' is to be performed within
134         * the processAnnotation method. The implementation <em>must</em> perform the call explicitly.
135         * <p>The arguments and the statement <em>must not</em> be referenced or cached for longer than the duration
136         * of the processAnnotation call. 
137         *
138         * @param name the annotation name
139         * @param args the arguments of the annotation, evaluated as arguments of this call
140         * @param statement the statement that was annotated; the processor should invoke this statement 'call' method
141         * @return the result of statement.call()
142         * @throws Exception if annotation processing fails
143         */
144        Object processAnnotation(String name, Object[] args, Callable<Object> statement) throws Exception;
145    }
146
147}