All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.jexl3.JexlOptions Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.jexl3;

import java.math.MathContext;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;

import org.apache.commons.jexl3.internal.Engine;

/**
 * Flags and properties that can alter the evaluation behavior.
 * The flags, briefly explained, are the following:
 * 
    *
  • silent: whether errors throw exception
  • *
  • safe: whether navigation through null is notan error
  • *
  • cancellable: whether thread interruption is an error
  • *
  • lexical: whether redefining local variables is an error
  • *
  • lexicalShade: whether local variables shade global ones even outside their scope
  • *
  • strict: whether unknown or unsolvable identifiers are errors
  • *
  • strictArithmetic: whether null as operand is an error
  • *
  • sharedInstance: whether these options can be modified at runtime during execution (expert)
  • *
* The sensible default is cancellable, strict and strictArithmetic. *

This interface replaces the now deprecated JexlEngine.Options. * @since 3.2 */ public final class JexlOptions { /** The shared instance bit. */ private static final int SHARED = 7; /** The local shade bit. */ private static final int SHADE = 6; /** The antish var bit. */ private static final int ANTISH = 5; /** The lexical scope bit. */ private static final int LEXICAL = 4; /** The safe bit. */ private static final int SAFE = 3; /** The silent bit. */ private static final int SILENT = 2; /** The strict bit. */ private static final int STRICT = 1; /** The cancellable bit. */ private static final int CANCELLABLE = 0; /** The flag names ordered. */ private static final String[] NAMES = { "cancellable", "strict", "silent", "safe", "lexical", "antish", "lexicalShade", "sharedInstance" }; /** Default mask .*/ private static int DEFAULT = 1 /*<< CANCELLABLE*/ | 1 << STRICT | 1 << ANTISH | 1 << SAFE; /** The arithmetic math context. */ private MathContext mathContext = null; /** The arithmetic math scale. */ private int mathScale = Integer.MIN_VALUE; /** The arithmetic strict math flag. */ private boolean strictArithmetic = true; /** The default flags, all but safe. */ private int flags = DEFAULT; /** The namespaces .*/ private Map namespaces = Collections.emptyMap(); /** The imports. */ private Collection imports = Collections.emptySet(); /** * Sets the value of a flag in a mask. * @param ordinal the flag ordinal * @param mask the flags mask * @param value true or false * @return the new flags mask value */ private static int set(final int ordinal, final int mask, final boolean value) { return value? mask | (1 << ordinal) : mask & ~(1 << ordinal); } /** * Checks the value of a flag in the mask. * @param ordinal the flag ordinal * @param mask the flags mask * @return the mask value with this flag or-ed in */ private static boolean isSet(final int ordinal, final int mask) { return (mask & 1 << ordinal) != 0; } /** * Default ctor. */ public JexlOptions() { // all inits in members declarations } /** * Sets the default (static, shared) option flags. *

* Whenever possible, we recommend using JexlBuilder methods to unambiguously instantiate a JEXL * engine; this method should only be used for testing / validation. *

A '+flag' or 'flag' will set the option named 'flag' as true, '-flag' set as false. * The possible flag names are: * cancellable, strict, silent, safe, lexical, antish, lexicalShade *

Calling JexlBuilder.setDefaultOptions("+safe") once before JEXL engine creation * may ease validating JEXL3.2 in your environment. * @param flags the flags to set */ public static void setDefaultFlags(final String...flags) { DEFAULT = parseFlags(DEFAULT, flags); } /** * Parses flags by name. *

A '+flag' or 'flag' will set flag as true, '-flag' set as false. * The possible flag names are: * cancellable, strict, silent, safe, lexical, antish, lexicalShade * @param initial the initial mask state * @param flags the flags to set * @return the flag mask updated */ public static int parseFlags(final int initial, final String... flags) { int mask = initial; for (final String flag : flags) { boolean b = true; final String name; if (flag.charAt(0) == '+') { name = flag.substring(1); } else if (flag.charAt(0) == '-') { name = flag.substring(1); b = false; } else { name = flag; } for (int f = 0; f < NAMES.length; ++f) { if (NAMES[f].equals(name)) { if (b) { mask |= (1 << f); } else { mask &= ~(1 << f); } break; } } } return mask; } /** * Sets this option flags using the +/- syntax. * @param opts the option flags */ public void setFlags(final String... opts) { flags = parseFlags(flags, opts); } /** * The MathContext instance used for +,-,/,*,% operations on big decimals. * @return the math context */ public MathContext getMathContext() { return mathContext; } /** * The BigDecimal scale used for comparison and coercion operations. * @return the scale */ public int getMathScale() { return mathScale; } /** * Checks whether evaluation will attempt resolving antish variable names. * @return true if antish variables are solved, false otherwise */ public boolean isAntish() { return isSet(ANTISH, flags); } /** * Checks whether evaluation will throw JexlException.Cancel (true) or * return null (false) if interrupted. * @return true when cancellable, false otherwise */ public boolean isCancellable() { return isSet(CANCELLABLE, flags); } /** * Checks whether runtime variable scope is lexical. *

If true, lexical scope applies to local variables and parameters. * Redefining a variable in the same lexical unit will generate errors. * @return true if scope is lexical, false otherwise */ public boolean isLexical() { return isSet(LEXICAL, flags); } /** * Checks whether local variables shade global ones. *

After a symbol is defined as local, dereferencing it outside its * scope will trigger an error instead of seeking a global variable of the * same name. To further reduce potential naming ambiguity errors, * global variables (ie non-local) must be declared to be assigned (@link JexlContext#has(String) ) * when this flag is on; attempting to set an undeclared global variables will * raise an error. * @return true if lexical shading is applied, false otherwise */ public boolean isLexicalShade() { return isSet(SHADE, flags); } /** * Checks whether the engine considers null in navigation expression as * errors during evaluation.. * @return true if safe, false otherwise */ public boolean isSafe() { return isSet(SAFE, flags); } /** * Checks whether the engine will throw a {@link JexlException} when an * error is encountered during evaluation. * @return true if silent, false otherwise */ public boolean isSilent() { return isSet(SILENT, flags); } /** * Checks whether the engine considers unknown variables, methods and * constructors as errors during evaluation. * @return true if strict, false otherwise */ public boolean isStrict() { return isSet(STRICT, flags); } /** * Checks whether the arithmetic triggers errors during evaluation when null * is used as an operand. * @return true if strict, false otherwise */ public boolean isStrictArithmetic() { return strictArithmetic; } /** * Sets whether the engine will attempt solving antish variable names from * context. * @param flag true if antish variables are solved, false otherwise */ public void setAntish(final boolean flag) { flags = set(ANTISH, flags, flag); } /** * Sets whether the engine will throw JexlException.Cancel (true) or return * null (false) when interrupted during evaluation. * @param flag true when cancellable, false otherwise */ public void setCancellable(final boolean flag) { flags = set(CANCELLABLE, flags, flag); } /** * Sets whether the engine uses a strict block lexical scope during * evaluation. * @param flag true if lexical scope is used, false otherwise */ public void setLexical(final boolean flag) { flags = set(LEXICAL, flags, flag); } /** * Sets whether the engine strictly shades global variables. * Local symbols shade globals after definition and creating global * variables is prohibited during evaluation. * If setting to lexical shade, lexical scope is also set. * @param flag true if creation is allowed, false otherwise */ public void setLexicalShade(final boolean flag) { flags = set(SHADE, flags, flag); if (flag) { flags = set(LEXICAL, flags, true); } } /** * Sets the arithmetic math context. * @param mcontext the context */ public void setMathContext(final MathContext mcontext) { this.mathContext = mcontext; } /** * Sets the arithmetic math scale. * @param mscale the scale */ public void setMathScale(final int mscale) { this.mathScale = mscale; } /** * Sets whether the engine considers null in navigation expression as null or as errors * during evaluation. *

If safe, encountering null during a navigation expression - dereferencing a method or a field through a null * object or property - will not be considered an error but evaluated as null. It is recommended * to use setSafe(false) as an explicit default.

* @param flag true if safe, false otherwise */ public void setSafe(final boolean flag) { flags = set(SAFE, flags, flag); } /** * Sets whether the engine will throw a {@link JexlException} when an error * is encountered during evaluation. * @param flag true if silent, false otherwise */ public void setSilent(final boolean flag) { flags = set(SILENT, flags, flag); } /** * Sets whether the engine considers unknown variables, methods and * constructors as errors during evaluation. * @param flag true if strict, false otherwise */ public void setStrict(final boolean flag) { flags = set(STRICT, flags, flag); } /** * Sets the strict arithmetic flag. * @param stricta true or false */ public void setStrictArithmetic(final boolean stricta) { this.strictArithmetic = stricta; } /** * Whether these options are immutable at runtime. *

Expert mode; allows instance handled through context to be shared * instead of copied. * @param flag true if shared, false if not */ public void setSharedInstance(final boolean flag) { flags = set(SHARED, flags, flag); } /** * @return false if a copy of these options is used during execution, * true if those can potentially be modified */ public boolean isSharedInstance() { return isSet(SHARED, flags); } /** * Set options from engine. * @param jexl the engine * @return this instance */ public JexlOptions set(final JexlEngine jexl) { if (jexl instanceof Engine) { ((Engine) jexl).optionsSet(this); } return this; } /** * Set options from options. * @param src the options * @return this instance */ public JexlOptions set(final JexlOptions src) { mathContext = src.mathContext; mathScale = src.mathScale; strictArithmetic = src.strictArithmetic; flags = src.flags; namespaces = src.namespaces; imports = src.imports; return this; } /** * Gets the optional map of namespaces. * @return the map of namespaces, may be empty, not null */ public Map getNamespaces() { return namespaces; } /** * Sets the optional map of namespaces. * @param ns a namespaces map */ public void setNamespaces(final Map ns) { this.namespaces = ns == null || ns.isEmpty()? Collections.emptyMap() : ns; } /** * Gets the optional set of imported packages. * @return the set of imports, may be empty, not null */ public Collection getImports() { return imports; } /** * Sets the optional set of imports. * @param imports the imported packages */ public void setImports(final Collection imports) { this.imports = imports == null || imports.isEmpty()? Collections.emptySet() : imports; } /** * Creates a copy of this instance. * @return a copy */ public JexlOptions copy() { return new JexlOptions().set(this); } @Override public String toString() { final StringBuilder strb = new StringBuilder(); for(int i = 0; i < NAMES.length; ++i) { if (i > 0) { strb.append(' '); } strb.append((flags & (1 << i)) != 0? '+':'-'); strb.append(NAMES[i]); } return strb.toString(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy