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