/* * © Copyright FOCONIS AG, 2014 * * Licensed 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.openntf.formula; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import org.openntf.formula.ValueHolder.DataType; /** * This is the FormulaContext that is used for evaluation * * @author Roland Praml, Foconis AG * */ public class FormulaContext { @SuppressWarnings("unused") private static final Logger log_ = Logger.getLogger(FormulaContext.class.getName()); protected Map<String, Object> dataMap; private Map<String, ValueHolder> vars = new HashMap<String, ValueHolder>(); private Map<String, Object> parameters = new HashMap<String, Object>(); /** the formatter is needed to parse/convert number and dateTime values */ private Formatter formatter; /** the parser is needed for evaluate */ private FormulaParser parser; /** the parameterProvider for <code>{@literal @}FocParam</code> or <code><#...#></code> parameters */ private FormulaProvider<?> paramProvider; public boolean useBooleans = true; public ValueHolder TRUE; public ValueHolder FALSE; public ValueHolder NEWLINE = ValueHolder.valueOf(System.getProperty("line.separator", "\n")); /** * @param dataMap * the context document * @param formatter * the formatter to format date/times * @param parser * the parser * */ public void init(final Map<String, Object> dataMap, final Formatter formatter, final FormulaParser parser) { this.dataMap = dataMap; this.formatter = formatter; this.parser = parser; useBooleans(true); } /** * the formula engine uses real booleans instead of 1 and 0. This is not 100% compatible to lotus, but it is more typesafe for * misspellings. If you do not want this, you can disable booleans here * * @param useit * Use booleans: <br> * <code>TRUE</code> if you want to use booleans (default) <br> * <code>FALSE</code> if you want to use 1 and 0 for boolean operatiosn. */ public void useBooleans(final boolean useit) { useBooleans = useit; if (useit) { TRUE = ValueHolder.valueOf(true); FALSE = ValueHolder.valueOf(false); } else { TRUE = ValueHolder.valueOf(1); FALSE = ValueHolder.valueOf(0); } } /** * Reading a value looks first in the internal vars and then in the document. Every value read from document is cached INTERNALLY. So * pay attention if you program functions that modify the document otherwise! * * @param keyLowercase * the key in lowercase. This is done for performance reasons * * @param key * the key in propercase * @return ValueHolder */ public ValueHolder getVarLC(final String keyLowercase, final String key) { ValueHolder var = vars.get(keyLowercase); if (var != null) { return var; } var = getField(key); // read valid value from doc. So cache it if (var != ValueHolder.valueDefault()) { vars.put(keyLowercase, var); } return var; } /** * Checks if a variable or a doc field is available * */ public boolean isAvailableVarLC(final String keyLowercase, final String key) { ValueHolder var = vars.get(keyLowercase); if (var != null) { if (var.dataType == DataType.UNAVAILABLE) return false; return true; } if (dataMap != null) { return dataMap.containsKey(key); } return false; } /** * Set a value in the internal var cache. Nothing is written to a Document * * @param keyLowercase * the key. Must be lowercase * @param elem * the ValueHolder to set * @return the OLD value */ public ValueHolder setVarLC(final String keyLowercase, final ValueHolder elem) { if (elem == null) { ValueHolder old = vars.get(keyLowercase); vars.remove(keyLowercase); return old; } else { return vars.put(keyLowercase, elem); } } /** * reads out a field from the dataMap * * @param key * the key in properCase */ public ValueHolder getField(final String key) { if (dataMap != null) { Object o = dataMap.get(key); if (o != null) return ValueHolder.valueOf(o); // RPr here it is allowed to access the deprecate method } return ValueHolder.valueDefault(); } /** * Set a field (and a value!) * * @param key * the fieldname to set * @param elem * the element to set in the field * @throws EvaluateException * in the case of an evaluation exception */ public void setField(final String key, final ValueHolder elem) { setVarLC(key.toLowerCase(), elem); if (dataMap != null) { if (elem.dataType == DataType.UNAVAILABLE) { dataMap.remove(key); } else { try { dataMap.put(key, elem.toList()); } catch (EvaluateException e) { // TODO Don't know what is the best here // dataMap.remove(key); dataMap.put(key, "@ERROR: " + e.getMessage()); } } } } /** * Set a default value * * @param key * the field to set * @param elem * the element to set */ public void setDefaultLC(final String keyLowercase, final String key, final ValueHolder elem) { if (vars.containsKey(keyLowercase)) return; if (dataMap != null) { if (dataMap.containsKey(key)) return; } setVarLC(keyLowercase, elem); } /** * returns the formatter for this context * */ public Formatter getFormatter() { return formatter; } /** * returns the parser (needed for evaluate/checkFormulaSyntax) * */ public FormulaParser getParser() { return parser; } /** * Reads a system property * */ public String getEnv(final String key) { return System.getProperty(key); } /** * writes a system property * */ public void setEnv(final String key, final String value) { System.setProperty(key, value); } //------------------------------------------------------ // // Parameter support // // ------------------------------------------------------ /** * Setup for the parameter provider (needed by FOCONIS) * */ public void setParameterProvider(final FormulaProvider<?> prov) { paramProvider = prov; } public void setParam(final String paramName, final Object value) { parameters.put(paramName, value); } /** * Read a formula parameter * */ public Object getParam(final String paramName) { if (parameters.containsKey(paramName)) return parameters.get(paramName); if (paramProvider != null) { return paramProvider.get(paramName); } return null; } }