package org.openntf.formula;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ServiceLoader;
import org.openntf.formula.impl.FormatterImpl;
import org.openntf.formula.parse.AtFormulaParserImpl;
/**
* This is the general factory
*
* @author Roland Praml, FOCONIS AG
*
*/
public enum Formulas {
;
private static final ThreadLocal<FormulaParser> parserCache = new ThreadLocal<FormulaParser>();
private static final ThreadLocal<Class<FormulaContext>> contextClassCache = new ThreadLocal<Class<FormulaContext>>();
private static final ThreadLocal<FunctionFactory> functionFactoryCache = new ThreadLocal<FunctionFactory>();
/*----------------------------------------------------------------------------*/
private static Map<Locale, Formatter> instances = new HashMap<Locale, Formatter>();
public static synchronized Formatter getFormatter(Locale loc) {
if (loc == null)
loc = Locale.getDefault();
Formatter ret = instances.get(loc);
if (ret == null)
instances.put(loc, ret = new FormatterImpl(loc));
return ret;
}
public static Formatter getFormatter() {
return getFormatter(null);
} /*----------------------------------------------------------------------------*/
public static void initialize() {
parserCache.set(null);
functionFactoryCache.set(null);
}
public static void terminate() {
parserCache.set(null);
functionFactoryCache.set(null);
}
/**
* This function returns a preconfigured default instance
*/
public static FormulaParser getParser(final Formatter formatter, final FunctionFactory factory) {
AtFormulaParserImpl parser = new AtFormulaParserImpl(new java.io.StringReader(""));
parser.reset();
parser.formatter = formatter;
parser.functionFactory = factory;
return parser;
}
public static FormulaParser getParser() {
FormulaParser parser = parserCache.get();
if (parser == null) {
parser = getParser(getFormatter(), getFunctionFactory());
parserCache.set(parser);
}
return parser;
}
public static FunctionFactory getFunctionFactory() {
FunctionFactory functionFactory = functionFactoryCache.get();
if (functionFactory == null) {
functionFactory = FunctionFactory.createInstance();
functionFactoryCache.set(functionFactory);
}
return functionFactory;
}
public static FormulaParser getMinimalParser() {
return getParser(getFormatter(), FunctionFactory.getMinimalFF());
}
public static FormulaContext createContext(final Map<String, Object> document, final FormulaParser parser) {
return createContext(document, parser == null ? null : parser.getFormatter(), parser);
}
@SuppressWarnings("unchecked")
public static FormulaContext createContext(final Map<String, Object> document, final Formatter formatter, final FormulaParser parser) {
Class<FormulaContext> ctxClass = contextClassCache.get();
FormulaContext instance = null;
if (ctxClass == null) {
ServiceLoader<FormulaContext> loader = ServiceLoader.load(FormulaContext.class);
Iterator<FormulaContext> it = loader.iterator();
if (it.hasNext()) {
instance = it.next();
} else {
instance = new FormulaContext();
}
ctxClass = (Class<FormulaContext>) instance.getClass();
contextClassCache.set(ctxClass);
} else {
try {
instance = ctxClass.newInstance();
} catch (InstantiationException e) {
throw new MissingResourceException("Can't instantiate context: " + e.getMessage(), ctxClass.getName(),
"InstantiationException");
} catch (IllegalAccessException e) {
throw new MissingResourceException("Can't instantiate context: " + e.getMessage(), ctxClass.getName(),
"IllegalAccessException");
}
}
instance.init(document, formatter, parser);
return instance;
}
public static List<Object> evaluate(final String formula, final Map<String, Object> map) throws FormulaParseException,
EvaluateException {
FormulaParser parser = Formulas.getParser();
ASTNode node = parser.parse(formula);
FormulaContext ctx = Formulas.createContext(map, parser);
return node.solve(ctx);
}
}