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 package org.apache.commons.jexl2;
018
019 import java.math.MathContext;
020
021 /**
022 * A derived arithmetic that allows different threads to operate with
023 * different strict/lenient/math modes using the same JexlEngine.
024 * @since 2.1
025 */
026 public class JexlThreadedArithmetic extends JexlArithmetic {
027
028 /** Holds the threaded version of some arithmetic features. */
029 static class Features {
030 /** Default ctor. */
031 Features() {}
032 /** Whether this JexlArithmetic instance behaves in strict or lenient mode. */
033 private Boolean lenient = null;
034 /** The big decimal math context. */
035 private MathContext mathContext = null;
036 /** The big decimal scale. */
037 private Integer mathScale = null;
038 }
039
040 /**
041 * Standard ctor.
042 * @param lenient lenient versus strict evaluation flag
043 */
044 public JexlThreadedArithmetic(boolean lenient) {
045 super(lenient);
046 }
047
048 /**
049 * Creates a JexlThreadedArithmetic instance.
050 * @param lenient whether this arithmetic is lenient or strict
051 * @param bigdContext the math context instance to use for +,-,/,*,% operations on big decimals.
052 * @param bigdScale the scale used for big decimals.
053 */
054 public JexlThreadedArithmetic(boolean lenient, MathContext bigdContext, int bigdScale) {
055 super(lenient, bigdContext, bigdScale);
056 }
057
058 /** Whether this JexlArithmetic instance behaves in strict or lenient mode for this thread. */
059 static final ThreadLocal<Features> FEATURES = new ThreadLocal<Features>() {
060 @Override
061 protected synchronized Features initialValue() {
062 return new Features();
063 }
064 };
065
066
067 /**
068 * Overrides the default behavior and sets whether this JexlArithmetic instance triggers errors
069 * during evaluation when null is used as an operand for the current thread.
070 * <p>It is advised to protect calls by either calling JexlThreadedArithmetic.setLenient explicitly
071 * before evaluation or add a try/finally clause resetting the flag to avoid unexpected reuse of the lenient
072 * flag value through thread pools side-effects.</p>
073 * @see JexlEngine#setSilent
074 * @see JexlEngine#setDebug
075 * @param flag true means no JexlException will occur, false allows them, null reverts to default behavior
076 */
077 public static void setLenient(Boolean flag) {
078 FEATURES.get().lenient = flag;
079 }
080
081 /**
082 * Sets the math scale.
083 * <p>The goal and constraints are the same than for setLenient.</p>
084 * @param scale the scale
085 */
086 public static void setMathScale(Integer scale) {
087 FEATURES.get().mathScale = scale;
088 }
089
090 /**
091 * Sets the math context.
092 * <p>The goal and constraints are the same than for setLenient.</p>
093 * @param mc the math context
094 */
095 public static void setMathContext(MathContext mc) {
096 FEATURES.get().mathContext = mc;
097 }
098
099 /** {@inheritDoc} */
100 @Override
101 public boolean isLenient() {
102 Boolean lenient = FEATURES.get().lenient;
103 return lenient == null ? super.isLenient() : lenient.booleanValue();
104 }
105
106 @Override
107 public int getMathScale() {
108 Integer scale = FEATURES.get().mathScale;
109 return scale == null ? super.getMathScale() : scale.intValue();
110 }
111
112 @Override
113 public MathContext getMathContext() {
114 MathContext mc = FEATURES.get().mathContext;
115 return mc == null? super.getMathContext() : mc;
116 }
117 }