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 * @return a cancelable boolean used by the interpreter. 092 */ 093 AtomicBoolean getCancellation(); 094 } 095 096 /** 097 * A marker interface that solves a simple class name into a fully-qualified one. 098 * 099 * @since 3.3 100 * @since 3.6.0 Removes {@code String resolveClassName(String name)} and extends {@link JexlUberspect.ClassNameResolver} which implements 101 * {@code String resolveClassName(String name)}. 102 */ 103 interface ClassNameResolver extends JexlUberspect.ClassNameResolver {} 104 105 /** 106 * A marker interface of the JexlContext that processes module definitions. 107 * It is used by the interpreter during evaluation of the pragma module definitions. 108 * 109 * @since 3.3 110 */ 111 interface ModuleProcessor { 112 /** 113 * Defines a module. 114 * The module name will be the namespace mapped to the object returned by the evaluation 115 * of its body. 116 * 117 * @param engine the engine evaluating this module pragma. 118 * @param info the info at the pragma location. 119 * @param name the module name. 120 * @param body the module definition which can be its location or source. 121 * @return the module object. 122 */ 123 Object processModule(JexlEngine engine, JexlInfo info, String name, String body); 124 } 125 126 /** 127 * A marker interface of the JexlContext, NamespaceFunctor allows creating an instance 128 * to delegate namespace methods calls to. 129 * 130 * <p>The functor is created once during the lifetime of a script evaluation.</p> 131 */ 132 interface NamespaceFunctor { 133 /** 134 * Creates the functor object that will be used instead of the namespace. 135 * 136 * @param context the context. 137 * @return the namespace functor instance. 138 */ 139 Object createFunctor(JexlContext context); 140 } 141 142 /** 143 * A marker interface of the JexlContext that declares how to resolve a namespace from its name; 144 * it is used by the interpreter during evaluation. 145 * 146 * <p>In JEXL, a namespace is an object that serves the purpose of encapsulating functions; for instance, 147 * the "math" namespace would be the proper object to expose functions like "log(...)", "sinus(...)", etc.</p> 148 * 149 * In expressions like "ns:function(...)", the resolver is called with resolveNamespace("ns"). 150 * 151 * <p>JEXL itself reserves 'jexl' and 'ujexl' as namespaces for internal purpose; resolving those may lead to 152 * unexpected results.</p> 153 * 154 * @since 3.0 155 */ 156 interface NamespaceResolver { 157 158 /** 159 * Resolves a namespace by its name. 160 * @param name the name. 161 * @return the namespace object. 162 */ 163 Object resolveNamespace(String name); 164 } 165 166 /** 167 * A marker interface of the JexlContext that exposes runtime evaluation options. 168 * @since 3.2 169 */ 170 interface OptionsHandle { 171 /** 172 * Gets the current set of options though the context. 173 * <p> 174 * This method will be called once at beginning of evaluation and an interpreter private copy 175 * of the context handled JexlOptions instance used for the duration of the execution; 176 * the context handled JexlOptions instance being only used as the source of that copy, 177 * it can safely alter its boolean flags during execution with no effect, avoiding any behavior ambiguity. 178 * </p> 179 * 180 * @return the engine options. 181 */ 182 JexlOptions getEngineOptions(); 183 } 184 185 /** 186 * A marker interface of the JexlContext that processes pragmas. 187 * It is called by the engine before interpreter creation; as a marker of 188 * JexlContext, it is expected to have access and interact with the context 189 * instance. 190 * 191 * @since 3.2 192 */ 193 interface PragmaProcessor { 194 195 /** 196 * Process one pragma. 197 * 198 * @param opts the current evaluator options. 199 * @param key the key. 200 * @param value the value. 201 * @since 3.3 202 */ 203 default void processPragma(final JexlOptions opts, final String key, final Object value) { 204 processPragma(key, value); 205 } 206 207 /** 208 * Process one pragma. 209 * 210 * <p>Never called in 3.3, must be implemented for 3.2 binary compatibility reasons.</p> 211 * <p>Typical implementation in 3.3:</p> 212 * <code> 213 * @Override 214 * public void processPragma(String key, Object value) { 215 * processPragma(null, key, value); 216 * } 217 * </code> 218 * 219 * @param key the key. 220 * @param value the value. 221 * @deprecated 3.3 222 */ 223 @Deprecated 224 void processPragma(String key, Object value); 225 } 226 227 /** 228 * A marker interface of the {@link JexlContext} that indicates the interpreter to put this context 229 * in the {@link JexlEngine} thread local context instance during evaluation. 230 * <p> 231 * This allows user functions or methods to access the context during a call. 232 * Note that the usual caveats regarding using thread local apply (caching, leaking references, and so on); in particular, 233 * keeping a reference to such a context is to be considered with great care and caution. 234 * It should also be noted that sharing such a context between threads should implicate synchronizing variable 235 * accessing the implementation class. 236 * </p> 237 * 238 * @see JexlEngine#setThreadContext(JexlContext.ThreadLocal) 239 * @see JexlEngine#getThreadContext() 240 */ 241 interface ThreadLocal extends JexlContext { 242 // no specific method 243 } 244 245 /** 246 * Gets the value of a variable. 247 * 248 * @param name the variable's name. 249 * @return the value. 250 */ 251 Object get(String name); 252 253 /** 254 * Checks whether a variable is defined in this context. 255 * 256 * <p>A variable may be defined with a null value; this method checks whether the 257 * value is null or if the variable is undefined.</p> 258 * 259 * @param name the variable's name. 260 * @return true if it exists, false otherwise. 261 */ 262 boolean has(String name); 263 264 /** 265 * Sets the value of a variable. 266 * 267 * @param name the variable's name. 268 * @param value the variable's value. 269 */ 270 void set(String name, Object value); 271}