package com.revolsys.parallel.tools;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.beans.InvalidPropertyException;
import org.springframework.beans.MethodInvocationException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyAccessException;
import org.springframework.beans.PropertyBatchUpdateException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.support.GenericApplicationContext;
import com.revolsys.beans.propertyeditor.ResourceEditorRegistrar;
import com.revolsys.collection.map.ThreadSharedProperties;
import com.revolsys.logging.Logs;
import com.revolsys.logging.log4j.ThreadLocalFileAppender;
import com.revolsys.parallel.AbstractRunnable;
import com.revolsys.parallel.process.ProcessNetwork;
import com.revolsys.spring.factory.Parameter;
public class ScriptExecutorRunnable extends AbstractRunnable {
private static Throwable getBeanExceptionCause(final BeanCreationException e) {
Throwable cause = e.getCause();
while (cause instanceof BeanCreationException || cause instanceof MethodInvocationException
|| cause instanceof PropertyAccessException || cause instanceof PropertyBatchUpdateException
|| cause instanceof InvalidPropertyException) {
Throwable newCause;
if (cause instanceof PropertyBatchUpdateException) {
final PropertyBatchUpdateException batchEx = (PropertyBatchUpdateException)cause;
newCause = batchEx.getPropertyAccessExceptions()[0];
} else {
newCause = cause.getCause();
}
if (newCause != null) {
cause = newCause;
} else {
return cause;
}
}
return cause;
}
private Map<String, Object> attributes = new LinkedHashMap<>();
private Map<String, Object> beans = new LinkedHashMap<>();
private boolean logScriptInfo = true;
private final String script;
public ScriptExecutorRunnable(final String script) {
this.script = script;
}
public ScriptExecutorRunnable(final String script, final Map<String, Object> attributes) {
this.script = script;
this.attributes = attributes;
}
public void addBean(final String name, final Object value) {
this.beans.put(name, value);
}
public void addBeans(final Map<String, ?> beans) {
this.beans.putAll(beans);
}
public Map<String, Object> getBeans() {
return this.beans;
}
public boolean isLogScriptInfo() {
return this.logScriptInfo;
}
@Override
public void runDo() {
final long startTime = System.currentTimeMillis();
try {
String logPath = null;
final String logFileName = (String)this.attributes.get("logFile");
if (logFileName != null && logFileName.trim().length() > 0) {
final File logFile = new File(logFileName);
final File parentFile = logFile.getParentFile();
if (parentFile != null) {
parentFile.mkdirs();
}
logPath = logFile.getAbsolutePath();
ThreadLocalFileAppender.getAppender().setLocalFile(logPath);
}
if (this.logScriptInfo) {
final StringBuilder message = new StringBuilder("Processing ");
message.append(" -s ");
message.append(this.script);
if (logPath != null) {
message.append(" -l ");
message.append(logPath);
}
for (final Entry<String, Object> parameter : this.attributes.entrySet()) {
message.append(" ");
message.append(parameter.getKey());
message.append("=");
message.append(parameter.getValue());
}
Logs.info(this, message.toString());
}
ThreadSharedProperties.setProperties(this.attributes);
final GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.getBeanFactory().addPropertyEditorRegistrar(new ResourceEditorRegistrar());
for (final Entry<String, Object> entry : this.beans.entrySet()) {
final String key = entry.getKey();
if (key.indexOf('.') == -1 && key.indexOf('[') == -1) {
final Object value = entry.getValue();
final GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(Parameter.class);
final MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
propertyValues.add("type", value.getClass());
propertyValues.add("value", value);
applicationContext.registerBeanDefinition(key, beanDefinition);
}
}
final XmlBeanDefinitionReader beanReader = new XmlBeanDefinitionReader(applicationContext);
if (new File(this.script).exists()) {
beanReader.loadBeanDefinitions("file:" + this.script);
} else {
beanReader.loadBeanDefinitions("classpath:" + this.script);
}
applicationContext.refresh();
try {
final Object bean = applicationContext.getBean("processNetwork");
final ProcessNetwork pipeline = (ProcessNetwork)bean;
pipeline.startAndWait();
} finally {
applicationContext.close();
System.gc();
}
} catch (final BeanCreationException e) {
final Throwable cause = getBeanExceptionCause(e);
Logs.error(this, cause.getMessage(), cause);
System.err.println(cause.getMessage());
System.err.flush();
} catch (final Throwable t) {
Logs.error(this, t.getMessage(), t);
}
if (this.logScriptInfo) {
final long endTime = System.currentTimeMillis();
final long time = endTime - startTime;
long seconds = time / 1000;
final long minutes = seconds / 60;
seconds = seconds % 60;
Logs.info(this, minutes + " minutes " + seconds + " seconds");
}
}
public void setBeans(final Map<String, Object> beans) {
this.beans = beans;
}
public void setLogScriptInfo(final boolean logScriptInfo) {
this.logScriptInfo = logScriptInfo;
}
}