/*
* Created on Apr 7, 2004 by mschilli
*/
package alma.acs.commandcenter.engine;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import alma.acs.commandcenter.util.MiscUtils;
import alma.acs.commandcenter.util.PreparedString;
import alma.entity.xmlbinding.acscommandcentertools.AcsCommandCenterTools;
import alma.entity.xmlbinding.acscommandcentertools.Insertion;
import alma.entity.xmlbinding.acscommandcentertools.Tool;
import alma.entity.xmlbinding.acscommandcentertools.types.InsertionSourceType;
/**
* @author mschilli
*/
public class ToolManager {
static private Logger log = MiscUtils.getPackageLogger(ToolManager.class);
// ======================================================
// API
// ======================================================
//
// ====== "Extra" Tools =======
//
/**
* Reads the tool definitions from the specified reader. The tool definitions that were
* in place before will be REPLACED by this.
*/
static public void readExtraTools (Reader f) throws Exception {
// --- read in xml file
BufferedReader r;
r = new BufferedReader(f);
extraTools = AcsCommandCenterTools.unmarshalAcsCommandCenterTools(r);
}
static public AcsCommandCenterTools getExtraTools () throws Exception {
// attempt lazy reading of definition if no-one has called
// readExtraTools() or readDefaultExtraTools() before
if (extraTools.getToolCount() == 0) {
ToolManager.readDefaultExtraTools();
}
return extraTools;
}
static public String getDefaultExtraToolsName () {
return "AcsCommandCenterTools.xml";
}
static public void readDefaultExtraTools () throws Exception {
URL url = ToolManager.class.getClassLoader().getResource(getDefaultExtraToolsName());
InputStream is = url.openStream();
InputStreamReader r = new InputStreamReader(is);
readExtraTools(r);
}
//
// ====== "Built-in" Tools =======
//
/**
* Reads the tool definition from the specified reader. They are ADDED to an internal
* map that uses toolnames as it keys. This implies that if a read-in tool has a name
* that - after trim() - doesn't exactly match the required name , it will have no
* effect.
*/
static public void readBuiltinTools (Reader f) throws Exception {
// --- read in xml file
BufferedReader r;
r = new BufferedReader(f);
AcsCommandCenterTools tools = AcsCommandCenterTools.unmarshalAcsCommandCenterTools(r);
// --- put all into map
// (some of the previous definitions are likely to be overwritten
// through this)
for (int i = 0; i < tools.getToolCount(); i++) {
Tool t = tools.getTool(i);
builtinTools.put(t.getCaption().trim(), t);
}
}
/**
* Returns the builtin tool with the specified name.
* <p>
* If no builtin-tool definition has yet been read in, this will try to read the
* default tools definition file (see <code>getDefaultBuiltinToolsName()</code>). If
* an exception occurs during that, it will be passed to the caller. To avoid this lazy
* attempy to read the default definitions, invoke one of
* <ul>
* <li><code>readDefaultBuiltinTools()</code>
* <li><code>readBuiltinTools(Reader)</code>
* </ul>
* before using this method.
* </p>
*
* @param caption the name of a tool
* @return a tool descriptor as defined in the tools definition
* @throws IllegalArgumentException if non-defined tool is requested
* @throws Exception if no tool defined yet, and loading of default definition fails
*/
static public Tool getBuiltinTool (String caption) throws IllegalArgumentException, Exception {
// attempt lazy reading of definition if no-one has called
// readBuiltinTools() or readDefaultBuiltinTools() before
if (builtinTools.size() == 0) {
ToolManager.readDefaultBuiltinTools();
}
Tool ret;
ret = (Tool) builtinTools.get(caption);
if (ret == null) {
throw new IllegalArgumentException("no such built-in tool: '" + caption + "'; currently defined built-in tools are: "
+ builtinTools.keySet());
}
return ret;
}
static public String getDefaultBuiltinToolsName () {
return "AcsCommandCenterBuiltinTools.xml";
}
static public void readDefaultBuiltinTools () throws Exception {
URL url = ToolManager.class.getClassLoader().getResource(getDefaultBuiltinToolsName());
InputStream is = url.openStream();
InputStreamReader r = new InputStreamReader(is);
readBuiltinTools(r);
}
//
// ====== Command Generation =======
//
static public String generateCommand (Tool tool, RunModel runModel) throws Exception {
return generateCommand(tool, runModel, emptyMap);
}
static private HashMap<String,Object> emptyMap = new HashMap<String,Object>();
static public String generateCommand (Tool tool, RunModel runModel, Map<String,Object> input) throws Exception {
String ret;
String[] pieces = collectInsertions(tool, runModel, input);
PreparedString prep = new PreparedString(tool.getCommand());
String command = prep.toString(pieces);
// VariableString vari = new VariableString(command, false);
// ret = vari.toString(getVariables());
ret = command;
return ret;
}
// ======================================================
// Internal
// ======================================================
/**
* Initializes the builtinTools map with hardcoded definitions
*/
static {
extraTools = new AcsCommandCenterTools();
builtinTools = new HashMap<String, Tool>();
}
static protected AcsCommandCenterTools extraTools;
static protected HashMap<String, Tool> builtinTools;
static protected String[] collectInsertions (Tool tool, RunModel runModel, Map<String,Object> input) throws Exception {
String[] ret = new String[tool.getInsertionCount()];
for (int i = 0; i < ret.length; i++) {
Insertion ins = tool.getInsertion(i);
String name = (ins.getContent() != null) ? ins.getContent().trim() : "";
String fallback = (ins.getDefault() != null) ? ins.getDefault().trim() : "";
if (ins.getSource().equals(InsertionSourceType.MODEL))
ret[i] = readFromModel(runModel, name, fallback);
else
ret[i] = readFromInput(input, name, fallback);
}
return ret;
}
static protected String readFromModel (RunModel runModel, String name, String fallback) throws Exception {
try {
Object ret = null;
// --- normalization: strip "()", prepend "get"
if (name.endsWith("()"))
name = name.substring(0, name.length() - 2);
if (!name.startsWith("get"))
name = "get" + name;
// --- find method and invoke
Method m = RunModel.class.getDeclaredMethod(name, new Class[]{});
ret = m.invoke(runModel, new Object[]{});
if (ret == null || ret.equals("")) {
ret = fallback;
}
log.finer("readFromModel('" + name + "','" + fallback + "') returns '" + ret + "'");
return ret.toString();
} catch (InvocationTargetException exc) {
log.fine("readFromModel(" + name + "," + fallback + ") failed: " + exc);
// in general, the root cause should be interesting to our callers.
// this is particularly true if reading from model failed because of an
// unresolvable variable. thus, we unwrap and throw the cause
Throwable cause = exc.getCause();
if (cause != null && cause instanceof Exception) {
throw (Exception)cause;
} else {
throw exc;
}
} catch (Exception exc) {
log.fine("readFromModel(" + name + "," + fallback + ") failed: " + exc);
throw exc;
}
}
static protected String readFromInput (Map<String, Object> input, String name, String fallback) {
Object ret = null;
ret = input.get(name);
if (ret == null || ret.equals("")) {
ret = fallback;
}
return ret.toString();
}
}