Merge "Issue #1486: Commit initial implementation of a generic PythonScript controller class based on GFE's AbstractGfePyController, refactor GFE code to use it." into development

Former-commit-id: 73d470a83799446554b4dd86eb20638c0d5fc48f
This commit is contained in:
Nate Jensen 2013-01-21 11:42:37 -06:00 committed by Gerrit Code Review
commit 36fc48eb53
16 changed files with 563 additions and 295 deletions

View file

@ -30,6 +30,8 @@
# Date Ticket# Engineer Description
# ------------ ---------- ----------- --------------------------
# 11/05/08 njensen Initial Creation.
# 01/17/13 1486 dgilling Re-factor based on
# RollbackMasterInterface.
#
#
#
@ -37,15 +39,13 @@
import sys
import Exceptions
import MasterInterface
from com.raytheon.uf.common.localization import PathManagerFactory
import RollbackMasterInterface
class ProcedureInterface(MasterInterface.MasterInterface):
class ProcedureInterface(RollbackMasterInterface.RollbackMasterInterface):
def __init__(self, scriptPath):
MasterInterface.MasterInterface.__init__(self)
self.importModules(scriptPath)
self.pathMgr = PathManagerFactory.getPathManager()
super(ProcedureInterface, self).__init__(scriptPath)
self.importModules()
self.menuToProcMap = {}
for script in self.scripts:
@ -72,26 +72,20 @@ class ProcedureInterface(MasterInterface.MasterInterface):
return scriptList
def addModule(self, moduleName):
MasterInterface.MasterInterface.addModule(self, moduleName)
super(ProcedureInterface, self).addModule(moduleName)
self.__mapMenuList(moduleName)
def removeModule(self, moduleName):
MasterInterface.MasterInterface.removeModule(self, moduleName)
super(ProcedureInterface, self).removeModule(moduleName)
for key in self.menuToProcMap:
procList = self.menuToProcMap.get(key)
if moduleName in procList:
procList.remove(moduleName)
self.menuToProcMap[key] = procList
if self.pathMgr.getStaticLocalizationFile("gfe/userPython/procedures/" + moduleName + ".py") is not None:
self.addModule(moduleName)
def getStartupErrors(self):
from java.util import ArrayList
errorList = ArrayList()
for err in self.getImportErrors():
errorList.add(str(err))
return errorList
# in-case we removed just an override, let's
# check to see if another script with the same name exists
if sys.modules.has_key(moduleName):
self.__mapMenuList(moduleName)
def getMethodArgNames(self, moduleName, className, methodName):
from java.util import ArrayList
@ -133,10 +127,5 @@ class ProcedureInterface(MasterInterface.MasterInterface):
# wasn't in list
pass
MasterInterface.MasterInterface.reloadModule(self, moduleName)
super(ProcedureInterface, self).reloadModule(moduleName)
self.__mapMenuList(moduleName)

View file

@ -30,6 +30,8 @@
# Date Ticket# Engineer Description
# ------------ ---------- ----------- --------------------------
# 10/21/08 njensen Initial Creation.
# 01/17/13 1486 dgilling Re-factor based on
# RollbackMasterInterface.
#
#
#
@ -37,19 +39,17 @@
import sys
import Exceptions
import MasterInterface
from com.raytheon.uf.common.localization import PathManagerFactory
import RollbackMasterInterface
class SmartToolInterface(MasterInterface.MasterInterface):
class SmartToolInterface(RollbackMasterInterface.RollbackMasterInterface):
def __init__(self, scriptPath):
MasterInterface.MasterInterface.__init__(self)
self.importModules(scriptPath)
super(SmartToolInterface, self).__init__(scriptPath)
self.importModules()
self.parmToModuleMap = {'variableElement' : set()}
for script in self.scripts:
self.__mapDisplayList(script)
self.pathMgr = PathManagerFactory.getPathManager()
def __mapDisplayList(self, script):
if hasattr(sys.modules[script], "WeatherElementEdited"):
@ -137,20 +137,21 @@ class SmartToolInterface(MasterInterface.MasterInterface):
return argList
def addModule(self, moduleName):
MasterInterface.MasterInterface.addModule(self, moduleName)
super(SmartToolInterface, self).addModule(moduleName)
self.__mapDisplayList(moduleName)
def reloadModule(self, moduleName):
if sys.modules.has_key(moduleName):
self.__removeModuleFromMap(moduleName)
MasterInterface.MasterInterface.reloadModule(self, moduleName)
self.__removeModuleFromMap(moduleName)
super(SmartToolInterface, self).reloadModule(moduleName)
self.__mapDisplayList(moduleName)
def removeModule(self, moduleName):
MasterInterface.MasterInterface.removeModule(self, moduleName)
super(SmartToolInterface, self).removeModule(moduleName)
self.__removeModuleFromMap(moduleName)
if self.pathMgr.getStaticLocalizationFile("gfe/userPython/smartTools/" + moduleName + ".py") is not None:
self.addModule(moduleName)
# in-case we removed just an override, let's
# check to see if another script with the same name exists
if sys.modules.has_key(moduleName):
self.__mapDisplayList(moduleName)
def __removeModuleFromMap(self, moduleName):
for parm in self.parmToModuleMap:
@ -159,13 +160,6 @@ class SmartToolInterface(MasterInterface.MasterInterface):
toolList.remove(moduleName)
self.parmToModuleMap[parm] = toolList
def getStartupErrors(self):
from java.util import ArrayList
errorList = ArrayList()
for err in self.getImportErrors():
errorList.add(str(err))
return errorList
def runTool(self, moduleName, className, methodName, **kwargs):
try:
return self.runMethod(moduleName, className, methodName, **kwargs)

View file

@ -28,7 +28,8 @@ Require-Bundle: org.eclipse.ui,
org.apache.commons.logging,
com.raytheon.uf.viz.application;bundle-version="1.0.0",
com.raytheon.viz.ui.personalities.awips;bundle-version="1.12.1174",
com.raytheon.uf.common.auth;bundle-version="1.12.1174"
com.raytheon.uf.common.auth;bundle-version="1.12.1174",
com.raytheon.uf.common.python;bundle-version="1.12.1174"
Bundle-ActivationPolicy: lazy
Export-Package: com.raytheon.viz.gfe,
com.raytheon.viz.gfe.constants,
@ -55,7 +56,6 @@ Import-Package: com.raytheon.edex.meteoLib,
com.raytheon.uf.common.colormap,
com.raytheon.uf.common.dissemination,
com.raytheon.uf.common.message,
com.raytheon.uf.common.python,
com.raytheon.uf.common.serialization.comm,
com.raytheon.uf.viz.python.swt,
com.raytheon.uf.viz.python.swt.widgets,

View file

@ -19,23 +19,13 @@
**/
package com.raytheon.viz.gfe;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jep.JepException;
import com.raytheon.uf.common.localization.FileUpdatedMessage;
import com.raytheon.uf.common.localization.FileUpdatedMessage.FileChangeType;
import com.raytheon.uf.common.localization.ILocalizationFileObserver;
import com.raytheon.uf.common.localization.IPathManager;
import com.raytheon.uf.common.localization.LocalizationFile;
import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.common.python.PyConstants;
import com.raytheon.uf.common.python.PythonScript;
import com.raytheon.uf.common.python.controller.PythonScriptController;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
@ -51,29 +41,19 @@ import com.raytheon.viz.gfe.smartscript.FieldDefinition;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 10, 2008 njensen Initial creation
* Jan 08, 2013 1486 dgilling Refactor based on PythonScriptController.
* </pre>
*
* @author njensen
* @version 1.0
*/
public abstract class BaseGfePyController extends PythonScript implements
ILocalizationFileObserver {
public abstract class BaseGfePyController extends PythonScriptController {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(BaseGfePyController.class);
protected static final String INTERFACE = "interface";
protected DataManager dataMgr;
protected final String pythonClassName;
protected Set<String> pendingRemoves = new HashSet<String>();
protected Set<String> pendingAdds = new HashSet<String>();
protected Set<String> pendingReloads = new HashSet<String>();
/**
* Constructor
*
@ -92,41 +72,8 @@ public abstract class BaseGfePyController extends PythonScript implements
protected BaseGfePyController(String filePath, String anIncludePath,
ClassLoader classLoader, DataManager dataManager,
String aPythonClassName) throws JepException {
super(filePath, anIncludePath, classLoader);
super(filePath, anIncludePath, classLoader, aPythonClassName);
dataMgr = dataManager;
pythonClassName = aPythonClassName;
}
/**
* Convenience method for getting an argument map with moduleNames and
* classNames
*
* @param moduleName
* the name of the module
* @return an argument map
*/
protected Map<String, Object> getStarterMap(String moduleName) {
HashMap<String, Object> args = new HashMap<String, Object>();
args.put(PyConstants.MODULE_NAME, moduleName);
args.put(PyConstants.CLASS_NAME, pythonClassName);
return args;
}
/**
* Checks if a module has the specified method
*
* @param moduleName
* the name of the module to check
* @param methodName
* the method to look up
* @return if the method exists
* @throws JepException
*/
public boolean hasMethod(String moduleName, String methodName)
throws JepException {
Map<String, Object> args = getStarterMap(moduleName);
args.put(PyConstants.METHOD_NAME, methodName);
return (Boolean) execute("hasMethod", INTERFACE, args);
}
/**
@ -136,38 +83,13 @@ public abstract class BaseGfePyController extends PythonScript implements
* the name of the module to instantiate
* @throws JepException
*/
public void instantiatePythonTool(String moduleName) throws JepException {
@Override
public void instantiatePythonScript(String moduleName) throws JepException {
Map<String, Object> instanceMap = getStarterMap(moduleName);
instanceMap.put("dbss", dataMgr);
execute("instantiate", INTERFACE, instanceMap);
}
public boolean isInstantiated(String moduleName) throws JepException {
HashMap<String, Object> argMap = new HashMap<String, Object>(1);
argMap.put(PyConstants.MODULE_NAME, moduleName);
return (Boolean) execute("isInstantiated", INTERFACE, argMap);
}
/**
* Returns the names of the specified method's arguments
*
* @param moduleName
* the name of the module
* @param methodName
* the name of the method
* @return the method arguments from the python
* @throws JepException
*/
@SuppressWarnings(value = "unchecked")
public String[] getMethodArguments(String moduleName, String methodName)
throws JepException {
Map<String, Object> instanceMap = getStarterMap(moduleName);
instanceMap.put(PyConstants.METHOD_NAME, methodName);
List<String> list = (List<String>) execute("getMethodArgNames",
INTERFACE, instanceMap);
return list.toArray(new String[list.size()]);
}
/**
* Gets the VariableList variable from the python module
*
@ -211,7 +133,7 @@ public abstract class BaseGfePyController extends PythonScript implements
public List<FieldDefinition> getVarDictWidgets(String moduleName)
throws JepException {
if (!isInstantiated(moduleName)) {
instantiatePythonTool(moduleName);
instantiatePythonScript(moduleName);
}
List<FieldDefinition> fieldDefs = null;
if (getVariableList(moduleName) != null) {
@ -239,119 +161,4 @@ public abstract class BaseGfePyController extends PythonScript implements
}
return varDict;
}
/**
* Gets formatted errors of failures to import smart tools from the initial
* scan
*
* @return a list of error messages
* @throws JepException
*/
@SuppressWarnings("unchecked")
protected List<String> getStartupErrors() throws JepException {
return (List<String>) execute("getStartupErrors", INTERFACE, null);
}
protected void reloadModule(String name) throws JepException {
HashMap<String, Object> argMap = new HashMap<String, Object>(1);
argMap.put(PyConstants.MODULE_NAME, name);
execute("reloadModule", INTERFACE, argMap);
// it was already initialized, need to get a new instance in the
// interpreter now that the module was reloaded
// if it wasn't already initialized, it's either a utility or will be
// initialized when it's first used
if (this.isInstantiated(name)) {
this.instantiatePythonTool(name);
}
}
@Override
public void fileUpdated(FileUpdatedMessage message) {
File file = new File(message.getFileName());
String name = file.getName().replaceAll("\\.py.*", "");
FileChangeType changeType = message.getChangeType();
IPathManager pm = PathManagerFactory.getPathManager();
LocalizationFile lf = pm.getLocalizationFile(message.getContext(),
message.getFileName());
if (message.getChangeType() == FileChangeType.ADDED) {
if (lf != null) {
lf.getFile();
}
pendingAdds.add(name);
} else if (changeType == FileChangeType.DELETED) {
if (lf != null) {
File toDelete = lf.getFile();
toDelete.delete();
}
pendingRemoves.add(name);
} else if (changeType == FileChangeType.UPDATED) {
if (lf != null) {
lf.getFile();
}
pendingReloads.add(name);
}
}
/**
* Updates the modules in the interpreter that have been scheduled to be
* updated. This must be called from the correct thread to work.
*/
public void processFileUpdates() {
for (String toolName : pendingRemoves) {
try {
removeModule(toolName);
} catch (JepException e) {
statusHandler.handle(Priority.PROBLEM, "Error removing module "
+ toolName, e);
}
}
pendingRemoves.clear();
for (String toolName : pendingAdds) {
try {
addModule(toolName);
} catch (JepException e) {
String pythonErrMsg = PythonErrorExtractor.getPythonError(e,
toolName);
if (pythonErrMsg == null) {
statusHandler.handle(Priority.PROBLEM,
"Error adding module " + toolName, e);
} else {
statusHandler.error(pythonErrMsg, e);
}
}
}
pendingAdds.clear();
for (String toolName : pendingReloads) {
try {
reloadModule(toolName);
} catch (JepException e) {
String pythonErrMsg = PythonErrorExtractor.getPythonError(e,
toolName);
if (pythonErrMsg == null) {
statusHandler.handle(Priority.PROBLEM,
"Error reloading module " + toolName + "\n", e);
} else {
statusHandler.error(pythonErrMsg, e);
}
}
}
pendingReloads.clear();
}
protected void removeModule(String name) throws JepException {
HashMap<String, Object> argMap = new HashMap<String, Object>(1);
argMap.put(PyConstants.MODULE_NAME, name);
execute("removeModule", INTERFACE, argMap);
}
protected void addModule(String name) throws JepException {
HashMap<String, Object> argMap = new HashMap<String, Object>(1);
argMap.put(PyConstants.MODULE_NAME, name);
execute("addModule", INTERFACE, argMap);
}
}

View file

@ -47,6 +47,7 @@ import com.raytheon.viz.gfe.core.DataManager;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 17, 2011 dgilling Initial creation
* Jan 08, 2013 1486 dgilling Support changes to BaseGfePyController.
*
* </pre>
*
@ -97,21 +98,16 @@ public class VCModuleController extends BaseGfePyController {
*/
public List<String> getMethodArgs(String moduleName, String method)
throws JepException {
String[] argNames = getMethodArguments(moduleName, method);
List<String> retVal = new ArrayList<String>(argNames.length);
for (String arg : argNames) {
if (!arg.equals("self")) {
retVal.add(arg);
}
}
return retVal;
List<String> argNames = new ArrayList<String>(getMethodArguments(
moduleName, method));
argNames.remove("self");
return argNames;
}
public Object executeMethod(String moduleName, String methodName,
Map<String, Object> args, GridType type) throws JepException {
if (!isInstantiated(moduleName)) {
instantiatePythonTool(moduleName);
instantiatePythonScript(moduleName);
}
args.put(PyConstants.METHOD_NAME, methodName);
@ -227,7 +223,7 @@ public class VCModuleController extends BaseGfePyController {
* .String)
*/
@Override
public void instantiatePythonTool(String moduleName) throws JepException {
public void instantiatePythonScript(String moduleName) throws JepException {
Map<String, Object> instanceMap = getStarterMap(moduleName);
execute("instantiate", INTERFACE, instanceMap);
}

View file

@ -45,7 +45,8 @@ import com.raytheon.viz.gfe.core.DataManager;
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 5, 2008 njensen Initial creation
* Nov 5, 2008 njensen Initial creation
* Jan 8, 2013 1486 dgilling Support changes to BaseGfePyController.
* </pre>
*
* @author njensen
@ -120,7 +121,7 @@ public class ProcedureController extends BaseGfePyController {
public Object executeProcedure(String procedureName,
Map<String, Object> args) throws JepException {
if (!isInstantiated(procedureName)) {
instantiatePythonTool(procedureName);
instantiatePythonScript(procedureName);
}
args.put(PyConstants.METHOD_NAME, "execute");
args.put(PyConstants.MODULE_NAME, procedureName);

View file

@ -55,7 +55,8 @@ import com.raytheon.viz.gfe.jobs.AsyncProgressJob;
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 8, 2009 njensen Initial creation
* Oct 8, 2009 njensen Initial creation
* Jan 8, 2013 1486 dgilling Support changes to BaseGfePyController.
*
* </pre>
*
@ -376,8 +377,8 @@ public class ProcedureJob extends AbstractQueueJob<ProcedureRequest> {
Job progressJob = new AsyncProgressJob(procedureName, this);
IStatus pjStatus = Status.CANCEL_STATUS;
try {
String[] argNames = controller.getMethodArguments(procedureName,
"execute");
List<String> argNames = controller.getMethodArguments(
procedureName, "execute");
Map<String, Object> argMap = getArgValues(argNames, refSet,
timeRange);
controller.setVarDict(varDict);
@ -411,7 +412,7 @@ public class ProcedureJob extends AbstractQueueJob<ProcedureRequest> {
* @return a map of argument names to objects
* @throws GFEException
*/
private Map<String, Object> getArgValues(String[] args,
private Map<String, Object> getArgValues(List<String> args,
ReferenceData refSet, TimeRange timeRange) throws GFEException {
Map<String, Object> argValueMap = new HashMap<String, Object>();
// For each argument in args, append a value to the argValueList

View file

@ -20,7 +20,6 @@
package com.raytheon.viz.gfe.smarttool;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@ -62,6 +61,7 @@ import com.raytheon.viz.gfe.dialogs.TimeRangeWarningDialog;
* May 3, 2010 njensen Initial creation
* Nov 7, 2012 1298 rferrel Keep EmptyEditAreaWarningDialog blocking.
* Keep TimeRangeWarningdialog blocking.
* Jan 8, 2013 1486 dgilling Support changes to BaseGfePyController.
*
* </pre>
*
@ -408,9 +408,8 @@ public class EditActionProcessor {
@Override
public void run() {
try {
String[] args = dataMgr.getProcedureInterface()
List<String> argList = dataMgr.getProcedureInterface()
.getMethodArguments(name, "execute");
List<String> argList = Arrays.asList(args);
if (!argList.contains("timeRange")
&& checkedList.contains("EmptyTimeRange")) {
checkedList.remove("EmptyTimeRange");

View file

@ -60,6 +60,7 @@ import com.raytheon.viz.gfe.smarttool.script.SmartToolController;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 27, 2007 njensen Initial creation
* Jan 08, 2013 1486 dgilling Support changes to BaseGfePyController.
*
* </pre>
*
@ -113,7 +114,7 @@ public class Tool {
try {
if (!tool.isInstantiated(toolName)) {
tool.instantiatePythonTool(toolName);
tool.instantiatePythonScript(toolName);
}
} catch (JepException e) {
throw new SmartToolException("Error instantiating python tool "
@ -137,7 +138,7 @@ public class Tool {
* @return
* @throws SmartToolException
*/
public Object[] getArgValues(String[] args, TimeRange gridTimeRange,
public Object[] getArgValues(List<String> args, TimeRange gridTimeRange,
TimeRange toolTimeRange, ReferenceData editArea,
MissingDataMode dataMode) throws SmartToolException {
@ -441,8 +442,9 @@ public class Tool {
// # PreProcess Tool
handlePreAndPostProcess("preProcessTool", null, timeRange,
editArea, dataMode);
statusHandler.handle(Priority.DEBUG, "Running smartTool: " + toolName);
statusHandler.handle(Priority.DEBUG, "Running smartTool: "
+ toolName);
// Iterate over time range
// Process each grid in the time range.
int numberOfGrids = grids.length;
@ -602,10 +604,13 @@ public class Tool {
try {
parmToEdit.startParmEdit(new Date[] { timeInfluence });
} catch (GFEOperationFailedException e) {
statusHandler.handle(Priority.PROBLEM,
"Error during start parm edit for " + toolName + " - already running." +
" Please wait for the operation to complete and try again.",
e);
statusHandler
.handle(Priority.PROBLEM,
"Error during start parm edit for "
+ toolName
+ " - already running."
+ " Please wait for the operation to complete and try again.",
e);
return;
}
startedParmEdit = true;
@ -619,13 +624,13 @@ public class Tool {
}
}
}
String[] executeArgs = tool.getMethodArguments(toolName, "execute");
List<String> executeArgs = tool.getMethodArguments(toolName, "execute");
Object gridResult = null;
Object[] argValues = getArgValues(executeArgs, gridTimeRange,
toolTimeRange, editArea, dataMode);
HashMap<String, Object> argMap = new HashMap<String, Object>();
for (int i = 0; i < executeArgs.length; i++) {
argMap.put(executeArgs[i], argValues[i]);
for (int i = 0; i < executeArgs.size(); i++) {
argMap.put(executeArgs.get(i), argValues[i]);
}
gridResult = tool.executeTool(parmToEdit, toolName, argMap);
@ -697,13 +702,13 @@ public class Tool {
ReferenceData editArea, MissingDataMode dataMode)
throws SmartToolException, JepException {
if (tool.hasMethod(toolName, methodName)) {
String[] prePostToolArgs = tool.getMethodArguments(toolName,
List<String> prePostToolArgs = tool.getMethodArguments(toolName,
methodName);
Object[] prePostToolObjs = getArgValues(prePostToolArgs,
gridTimeRange, toolTimeRange, editArea, dataMode);
HashMap<String, Object> prePostToolMap = new HashMap<String, Object>();
for (int i = 0; i < prePostToolArgs.length; i++) {
prePostToolMap.put(prePostToolArgs[i], prePostToolObjs[i]);
for (int i = 0; i < prePostToolArgs.size(); i++) {
prePostToolMap.put(prePostToolArgs.get(i), prePostToolObjs[i]);
}
tool.runToolMethod(toolName, methodName, prePostToolMap);
}

View file

@ -32,6 +32,7 @@
# Date Ticket# Engineer Description
# ------------ ---------- ----------- --------------------------
# 10/20/08 njensen Initial Creation.
# 01/17/13 1486 dgilling Make a new-style class.
#
#
#
@ -40,7 +41,7 @@
import os, string
import sys, inspect, traceback
class MasterInterface():
class MasterInterface(object):
def __init__(self):
self.scripts = []

View file

@ -17,24 +17,24 @@ class RollBackImporter:
if match is not None:
level = match.group(1)
if level != 'base':
LogStream.logEvent("IMPORTING:", name, result)
# LogStream.logDebug("IMPORTING:", name, result)
self.newModules[result.__name__] = 1
else:
LogStream.logDebug("IGNORING BASE:", name, result)
else:
LogStream.logDebug("IGNORING NON-LOCALIZED:", name, result)
else:
LogStream.logDebug("IGNORING BUILTIN:", name, result)
# else:
# LogStream.logDebug("IGNORING BASE:", name, result)
# else:
# LogStream.logDebug("IGNORING NON-LOCALIZED:", name, result)
# else:
# LogStream.logDebug("IGNORING BUILTIN:", name, result)
return result
def rollback(self):
for modname in self.newModules.keys():
if not self.previousModules.has_key(modname):
# Force reload when modname next imported
LogStream.logEvent("UNLOADING:", modname, sys.modules[modname])
# LogStream.logDebug("UNLOADING:", modname, sys.modules[modname])
del(sys.modules[modname])
else:
LogStream.logDebug("SKIPPING PRELOADED:", modname)
# else:
# LogStream.logDebug("SKIPPING PRELOADED:", modname)
self.newModules = {}

View file

@ -0,0 +1,82 @@
##
# This software was developed and / or modified by Raytheon Company,
# pursuant to Contract DG133W-05-CQ-1067 with the US Government.
#
# U.S. EXPORT CONTROLLED TECHNICAL DATA
# This software product contains export-restricted data whose
# export/transfer/disclosure is restricted by U.S. law. Dissemination
# to non-U.S. persons whether in the United States or abroad requires
# an export license or other authorization.
#
# Contractor Name: Raytheon Company
# Contractor Address: 6825 Pine Street, Suite 340
# Mail Stop B8
# Omaha, NE 68106
# 402.291.0100
#
# See the AWIPS II Master Rights File ("Master Rights File.pdf") for
# further licensing information.
##
#
# Globally import and sets up instances of the scripts.
# Designed to be used as a master controller for inspecting and running
# python scripts from Java. Differs from base MasterInterface class because
# it utilizes the rollback importer.
#
# This class should remain purely python. For Java interactions, extend this class.
#
#
#
# SOFTWARE HISTORY
#
# Date Ticket# Engineer Description
# ------------ ---------- ----------- --------------------------
# 01/17/13 dgilling Initial Creation.
#
#
#
import os
import MasterInterface
import RollBackImporter
rollbackImporter = RollBackImporter.RollBackImporter()
class RollbackMasterInterface(MasterInterface.MasterInterface):
def __init__(self, scriptPath):
super(RollbackMasterInterface, self).__init__()
self._scriptPath = scriptPath
def importModules(self):
super(RollbackMasterInterface, self).importModules(self._scriptPath)
def getStartupErrors(self):
from java.util import ArrayList
errorList = ArrayList()
for err in self.getImportErrors():
errorList.add(str(err))
return errorList
def addModule(self, moduleName):
super(RollbackMasterInterface, self).addModule(moduleName)
self.reloadModules()
def reloadModule(self, moduleName):
super(RollbackMasterInterface, self).reloadModule(moduleName)
self.reloadModules()
def removeModule(self, moduleName):
super(RollbackMasterInterface, self).removeModule(moduleName)
self.reloadModules()
def reloadModules(self):
for script in self.scripts:
super(RollbackMasterInterface, self).removeModule(script)
rollbackImporter.rollback()
self.importModules()

View file

@ -5,7 +5,10 @@ Bundle-SymbolicName: com.raytheon.uf.common.python
Bundle-Version: 1.12.1174.qualifier
Bundle-Vendor: RAYTHEON
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.jep;bundle-version="1.0.0"
Require-Bundle: org.jep;bundle-version="1.0.0",
com.raytheon.uf.common.status;bundle-version="1.12.1174",
com.raytheon.uf.common.localization;bundle-version="1.12.1174"
Export-Package: com.raytheon.uf.common.python,
com.raytheon.uf.common.python.controller,
com.raytheon.uf.common.python.multiprocessing,
com.raytheon.uf.common.python.thread

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.gfe;
package com.raytheon.uf.common.python;
import java.io.File;
import java.util.regex.Matcher;
@ -37,8 +37,8 @@ import jep.JepException;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 2, 2011 wldougher Initial creation
*
* Jun 2, 2011 wldougher Initial creation
* Jan 8, 2013 1486 dgilling Move to common python plugin.
* </pre>
*
* @author wldougher

View file

@ -0,0 +1,53 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.python.controller;
import jep.JepException;
/**
* Interface for factory classes that build instances of PythonScriptController
* sub-classes.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 12, 2012 dgilling Initial creation
*
* </pre>
*
* @author dgilling
* @version 1.0
*/
public interface IPythonScriptControllerFactory {
/**
* Build and return an instance of PythonScriptController.
*
* @return A PythonScriptController instance.
* @throws JepException
* If a python Error is thrown during instantiation of the
* PythonScriptController.
*/
PythonScriptController buildScriptController() throws JepException;
}

View file

@ -0,0 +1,337 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.python.controller;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jep.JepException;
import com.raytheon.uf.common.localization.FileUpdatedMessage;
import com.raytheon.uf.common.localization.FileUpdatedMessage.FileChangeType;
import com.raytheon.uf.common.localization.ILocalizationFileObserver;
import com.raytheon.uf.common.localization.IPathManager;
import com.raytheon.uf.common.localization.LocalizationFile;
import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.common.python.PyConstants;
import com.raytheon.uf.common.python.PythonErrorExtractor;
import com.raytheon.uf.common.python.PythonScript;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
/**
* Base controller for executing python scripts in a similar manner. Sub-classes
* should base their implementation on this class and for the python code
* develop an extension based on
* /build.edex/esb/data/utility/common_static/base/python/MasterInterface.py.
* <p>
* Script instances are "cached" within the interpreter, so this class
* implements the ILocalizationFileObserver interface so the cached instances
* can be properly updated as necessary.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 12, 2012 dgilling Initial creation
*
* </pre>
*
* @author dgilling
* @version 1.0
*/
public abstract class PythonScriptController extends PythonScript implements
ILocalizationFileObserver {
private static final IUFStatusHandler statusHandler = UFStatus
.getHandler(PythonScriptController.class);
protected static final String INTERFACE = "interface";
protected final String pythonClassName;
protected Set<String> pendingRemoves = new HashSet<String>();
protected Set<String> pendingAdds = new HashSet<String>();
protected Set<String> pendingReloads = new HashSet<String>();
/**
* Constructor
*
* @param filePath
* path to the python interface, which should be based on
* MasterInterface.py
* @param anIncludePath
* path of directories to include
* @param classLoader
* Java classloader
* @param aPythonClassName
* the class name for the python scripts
* @throws JepException
* If a python Error is thrown during instantiation of the
* underlying python script.
*/
protected PythonScriptController(String filePath, String anIncludePath,
ClassLoader classLoader, String aPythonClassName)
throws JepException {
super(filePath, anIncludePath, classLoader);
this.pythonClassName = aPythonClassName;
}
/**
* Convenience method for getting an argument map with moduleNames and
* classNames
*
* @param moduleName
* the name of the module
* @return an argument map
*/
protected Map<String, Object> getStarterMap(String moduleName) {
Map<String, Object> args = new HashMap<String, Object>();
args.put(PyConstants.MODULE_NAME, moduleName);
args.put(PyConstants.CLASS_NAME, pythonClassName);
return args;
}
/**
* Gets formatted list of errors detailing errors trying to import python
* scripts based on initial scan.
*
* @return a list of error messages
* @throws JepException
* If an Error is thrown during python execution.
*/
@SuppressWarnings("unchecked")
protected List<String> getStartupErrors() throws JepException {
return (List<String>) execute("getStartupErrors", INTERFACE, null);
}
/**
* Checks if a module has the specified method
*
* @param moduleName
* the name of the module to check
* @param methodName
* the method to look up
* @return if the method exists
* @throws JepException
* If an Error is thrown during python execution.
*/
public boolean hasMethod(String moduleName, String methodName)
throws JepException {
Map<String, Object> args = getStarterMap(moduleName);
args.put(PyConstants.METHOD_NAME, methodName);
return (Boolean) execute("hasMethod", INTERFACE, args);
}
/**
* Instantiates an instance of the class in the module
*
* @param moduleName
* the name of the module to instantiate
* @throws JepException
* If an Error is thrown executing the module's constructor.
*/
public void instantiatePythonScript(String moduleName) throws JepException {
Map<String, Object> instanceMap = getStarterMap(moduleName);
execute("instantiate", INTERFACE, instanceMap);
}
/**
* Determines whether or not a specified module has been instantiated.
*
* @param moduleName
* The name of the module to check.
* @return If the module has been instantiated or not.
* @throws JepException
* If an Error is thrown during python execution.
*/
public boolean isInstantiated(String moduleName) throws JepException {
HashMap<String, Object> argMap = new HashMap<String, Object>(1);
argMap.put(PyConstants.MODULE_NAME, moduleName);
return (Boolean) execute("isInstantiated", INTERFACE, argMap);
}
/**
* Returns the names of the specified method's arguments
*
* @param moduleName
* the name of the module
* @param methodName
* the name of the method
* @return the method arguments from the python
* @throws JepException
* If an Error is thrown during python execution.
*/
@SuppressWarnings(value = "unchecked")
public List<String> getMethodArguments(String moduleName, String methodName)
throws JepException {
Map<String, Object> instanceMap = getStarterMap(moduleName);
instanceMap.put(PyConstants.METHOD_NAME, methodName);
List<String> list = (List<String>) execute("getMethodArgNames",
INTERFACE, instanceMap);
return Collections.unmodifiableList(list);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.common.localization.ILocalizationFileObserver#fileUpdated
* (com.raytheon.uf.common.localization.FileUpdatedMessage)
*/
@Override
public void fileUpdated(FileUpdatedMessage message) {
File file = new File(message.getFileName());
String name = file.getName().replaceAll("\\.py.*", "");
FileChangeType changeType = message.getChangeType();
IPathManager pm = PathManagerFactory.getPathManager();
LocalizationFile lf = pm.getLocalizationFile(message.getContext(),
message.getFileName());
if (message.getChangeType() == FileChangeType.ADDED) {
if (lf != null) {
lf.getFile();
}
pendingAdds.add(name);
} else if (changeType == FileChangeType.DELETED) {
if (lf != null) {
File toDelete = lf.getFile();
toDelete.delete();
}
pendingRemoves.add(name);
} else if (changeType == FileChangeType.UPDATED) {
if (lf != null) {
lf.getFile();
}
pendingReloads.add(name);
}
}
/**
* Updates the modules in the interpreter that have been scheduled to be
* updated. This must be called from the correct thread to work.
*/
public void processFileUpdates() {
for (String toolName : pendingRemoves) {
try {
removeModule(toolName);
} catch (JepException e) {
statusHandler.handle(Priority.PROBLEM, "Error removing module "
+ toolName, e);
}
}
pendingRemoves.clear();
for (String toolName : pendingAdds) {
try {
addModule(toolName);
} catch (JepException e) {
String pythonErrMsg = PythonErrorExtractor.getPythonError(e,
toolName);
if (pythonErrMsg == null) {
statusHandler.handle(Priority.PROBLEM,
"Error adding module " + toolName, e);
} else {
statusHandler.error(pythonErrMsg, e);
}
}
}
pendingAdds.clear();
for (String toolName : pendingReloads) {
try {
reloadModule(toolName);
} catch (JepException e) {
String pythonErrMsg = PythonErrorExtractor.getPythonError(e,
toolName);
if (pythonErrMsg == null) {
statusHandler.handle(Priority.PROBLEM,
"Error reloading module " + toolName + "\n", e);
} else {
statusHandler.error(pythonErrMsg, e);
}
}
}
pendingReloads.clear();
}
/**
* Reload an updated module in the interpreter's "cache".
*
* @param name
* Module to be reloaded.
* @throws JepException
* If an Error is thrown during python execution.
*/
protected void reloadModule(String name) throws JepException {
boolean wasInstantiated = isInstantiated(name);
HashMap<String, Object> argMap = new HashMap<String, Object>(1);
argMap.put(PyConstants.MODULE_NAME, name);
execute("reloadModule", INTERFACE, argMap);
// it was already initialized, need to get a new instance in the
// interpreter now that the module was reloaded
// if it wasn't already initialized, it's either a utility or will be
// initialized when it's first used
if (wasInstantiated) {
instantiatePythonScript(name);
}
}
/**
* Add a module to the interpreter's "cache".
*
* @param name
* Module to be added.
* @throws JepException
* If an Error is thrown during python execution.
*/
protected void removeModule(String name) throws JepException {
HashMap<String, Object> argMap = new HashMap<String, Object>(1);
argMap.put(PyConstants.MODULE_NAME, name);
execute("removeModule", INTERFACE, argMap);
}
/**
* Remove a module from the interpreter's "cache".
*
* @param name
* Module to be removed.
* @throws JepException
* If an Error is thrown during python execution.
*/
protected void addModule(String name) throws JepException {
HashMap<String, Object> argMap = new HashMap<String, Object>(1);
argMap.put(PyConstants.MODULE_NAME, name);
execute("addModule", INTERFACE, argMap);
}
}