package edu.isi.karma.er.helper;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.io.FileUtils;
import org.python.core.PyCode;
import org.python.core.PyStringMap;
import org.python.util.PythonInterpreter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PythonRepository {
private static Logger logger = LoggerFactory.getLogger(PythonRepository.class);
private ConcurrentHashMap<String, PyCode> scripts = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, PyCode> libraryScripts = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, Long> fileNameTolastTimeRead = new ConcurrentHashMap<>();
private List<String> localKeys = Arrays.asList("workspaceid", "selectionName", "command", "worksheetId", "selection", "nodeid");
private boolean libraryHasBeenLoaded = false;
private boolean reloadLibrary = true;
private PyStringMap initialLocals;
private PythonInterpreter interpreter;
private String repositoryPath;
public PythonRepository(boolean reloadLibrary, String repositoryPath)
{
this.repositoryPath = repositoryPath;
this.reloadLibrary = reloadLibrary;
initialize();
resetLibrary();
}
private void initialize()
{
scripts = new ConcurrentHashMap<>();
initialLocals = new PyStringMap();
interpreter = PythonInterpreter.threadLocalStateInterpreter(initialLocals);
compileAndAddToRepository(interpreter, PythonTransformationHelper.getImportStatements());
compileAndAddToRepository(interpreter, PythonTransformationHelper.getRowIndexDefStatement());
compileAndAddToRepository(interpreter, PythonTransformationHelper.getGetValueDefStatement());
compileAndAddToRepository(interpreter, PythonTransformationHelper.getGetValueFromNestedColumnByIndexDefStatement());
compileAndAddToRepository(interpreter, PythonTransformationHelper.getIsEmptyDefStatement());
compileAndAddToRepository(interpreter, PythonTransformationHelper.getHasSelectedRowsStatement());
compileAndAddToRepository(interpreter, PythonTransformationHelper.getVDefStatement());
compileAndAddToRepository(interpreter, PythonTransformationHelper.getTransformStatement());
compileAndAddToRepository(interpreter, PythonTransformationHelper.getSelectionStatement());
initializeInterpreter(interpreter);
}
public PyCode compileAndAddToRepositoryAndExec(PythonInterpreter interpreter, String statement)
{
PyCode py;
if(!scripts.containsKey(statement))
{
py = compileAndAddToRepository(interpreter,statement);
}
else
py = scripts.get(statement);
interpreter.exec(py);
return py;
}
public PyCode compileAndAddToRepository(PythonInterpreter interpreter,
String statement) {
PyCode py;
if(!scripts.containsKey(statement))
{
py = compile(interpreter, statement);
scripts.putIfAbsent(statement, py);
}
return scripts.get(statement);
}
private PyCode compile(PythonInterpreter interpreter, String statement) {
return interpreter.compile(statement);
}
public void initializeInterpreter(PythonInterpreter interpreter)
{
boolean localsUninitialized = interpreter.getLocals() == initialLocals;
if(localsUninitialized)
{
PyStringMap locals = new PyStringMap();
interpreter.setLocals(locals);
interpreter.exec(scripts.get(PythonTransformationHelper.getImportStatements()));
interpreter.exec(scripts.get(PythonTransformationHelper.getGetValueDefStatement()));
interpreter.exec(scripts.get(PythonTransformationHelper.getIsEmptyDefStatement()));
interpreter.exec(scripts.get(PythonTransformationHelper.getHasSelectedRowsStatement()));
interpreter.exec(scripts.get(PythonTransformationHelper.getGetValueFromNestedColumnByIndexDefStatement()));
interpreter.exec(scripts.get(PythonTransformationHelper.getRowIndexDefStatement()));
interpreter.exec(scripts.get(PythonTransformationHelper.getVDefStatement()));
}
if(localsUninitialized ||(!libraryHasBeenLoaded || reloadLibrary))
{
importUserScripts(interpreter);
}
}
public PyCode getTransformCode()
{
return scripts.get(PythonTransformationHelper.getTransformStatement());
}
public PyCode getSelectionCode()
{
return scripts.get(PythonTransformationHelper.getSelectionStatement());
}
public synchronized void importUserScripts(PythonInterpreter interpreter) {
if (repositoryPath != null && repositoryPath.compareTo("") != 0) {
if(!libraryHasBeenLoaded || reloadLibrary)
{
File f = new File(repositoryPath);
String[] scripts = f.list(new FilenameFilter(){
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".py");
}});
for(String script : scripts)
{
String fileName = repositoryPath + script;
Long lastTimeRead = fileNameTolastTimeRead.get(fileName);
File s = new File(fileName);
if(lastTimeRead == null || s.lastModified() > lastTimeRead)
{
String statement;
try {
statement = FileUtils.readFileToString(s);
PyCode py = compile(interpreter, statement);
libraryScripts.put(fileName, py);
fileNameTolastTimeRead.put(fileName, System.currentTimeMillis());
} catch (IOException e) {
logger.error("Unable to process python script in {}: {}", fileName,e.toString());
}
}
interpreter.exec(libraryScripts.get(fileName));
//TODO prune scripts no longer present
}
libraryHasBeenLoaded = true;
}
else
{
for(PyCode code : libraryScripts.values())
{
interpreter.exec(code);
}
}
}
}
public synchronized void resetLibrary()
{
libraryScripts = new ConcurrentHashMap<>();
fileNameTolastTimeRead = new ConcurrentHashMap<>();
libraryHasBeenLoaded = false;
}
protected String getRepositoryPath() {
return repositoryPath;
}
private void resetRuntimeLocal() {
for (String key : localKeys) {
try {
this.interpreter.getLocals().__delitem__(key);
} catch (Exception e) {
//Key is missing, do nothing
}
}
}
public PythonInterpreter getInterpreter() {
resetRuntimeLocal();
//interpreter.cleanup();
return this.interpreter;
}
}