/*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version. You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.aitools.programd.processor.aiml;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.aitools.programd.Core;
import org.aitools.programd.CoreSettings;
import org.aitools.programd.parser.TemplateParser;
import org.aitools.programd.processor.ProcessorException;
import org.aitools.util.resource.Filesystem;
import org.jdom.Element;
/**
* <p>
* Handles a <code><a href="http://aitools.org/aiml/TR/2001/WD-aiml/#section-system">system</a></code> element.
* </p>
* <p>
* No attempt is made to check whether the command passed to the OS interpreter is harmful.
* </p>
*
* @author Jon Baer
* @author Mark Anacker
* @author Thomas Ringate, Pedro Colla
* @author <a href="mailto:noel@aitools.org">Noel Bush</a>
*/
public class SystemProcessor extends AIMLProcessor {
/** The label (as required by the registration scheme). */
public static final String label = "system";
/**
* Known names of operating systems which tend to require the array form of ProcessBuilder().
*/
private static final String[] arrayFormOSnames = { "mac os x", "linux", "solaris", "sunos", "mpe", "hp-ux",
"pa_risc", "aix", "freebsd", "irix", "unix", "windows xp" };
/** Whether to use the array form of Runtime.exec(). */
private static boolean useArrayExecForm;
/**
* Tries to guess whether to use the array form of Runtime.exec().
*/
static {
String os = System.getProperty("os.name").toLowerCase();
for (int index = arrayFormOSnames.length; --index >= 0;) {
if (os.indexOf(arrayFormOSnames[index]) != -1) {
useArrayExecForm = true;
}
}
}
/**
* Creates a new SystemProcessor using the given Core.
*
* @param core the Core object to use
*/
public SystemProcessor(Core core) {
super(core);
}
/**
* @see AIMLProcessor#process(Element, TemplateParser)
*/
@SuppressWarnings("unchecked")
@Override
public String process(Element element, TemplateParser parser) throws ProcessorException {
CoreSettings coreSettings = parser.getCore().getSettings();
// Don't use the system tag if not permitted.
if (!coreSettings.allowOSAccess()) {
logger.warn("Use of <system> prohibited!");
return "";
}
String directoryPath = coreSettings.getSystemInterpreterDirectory().getPath();
String prefix = coreSettings.getSystemInterpreterPrefix();
String commandLine = parser.evaluate(element.getContent());
if (prefix != null) {
commandLine = prefix + commandLine;
}
String output = "";
commandLine = commandLine.trim();
logger.debug("<system> call: " + commandLine);
if (directoryPath == null || "".equals(directoryPath)) {
logger.error("No programd.interpreter.system.directory defined!");
return "";
}
File directory = Filesystem.getExistingDirectory(directoryPath);
logger.debug("Executing <system> call in \"" + directory.getPath() + "\"");
ProcessBuilder processBuilder = null;
if (useArrayExecForm) {
processBuilder = new ProcessBuilder(commandLine.split("\\s"));
}
else {
processBuilder = new ProcessBuilder(commandLine);
}
processBuilder.directory(directory);
Process child = null;
try {
child = processBuilder.start();
}
catch (IOException e) {
logger.warn(String.format("Error executing <system> command \"%s\"", commandLine), e);
return "";
}
if (child == null) {
logger.error("Could not get separate process for <system> command.");
return "";
}
try {
child.waitFor();
}
catch (InterruptedException e) {
logger.error("System process interruped; could not complete.");
return "";
}
try {
InputStream in = child.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
output = output + line + "\n";
}
logger.debug("output: " + output);
commandLine = output;
in.close();
logger.debug("System process exit value: " + child.exitValue());
}
catch (IOException e) {
logger.warn(String.format("Error reading result of <system> command \"%s\"", commandLine), e);
}
return commandLine.trim();
}
}