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 * @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}