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

View file

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

View file

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

View file

@ -19,23 +19,13 @@
**/ **/
package com.raytheon.viz.gfe; package com.raytheon.viz.gfe;
import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import jep.JepException; import jep.JepException;
import com.raytheon.uf.common.localization.FileUpdatedMessage; import com.raytheon.uf.common.python.controller.PythonScriptController;
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.status.IUFStatusHandler; import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.status.UFStatus.Priority;
@ -51,29 +41,19 @@ import com.raytheon.viz.gfe.smartscript.FieldDefinition;
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Nov 10, 2008 njensen Initial creation * Nov 10, 2008 njensen Initial creation
* Jan 08, 2013 1486 dgilling Refactor based on PythonScriptController.
* </pre> * </pre>
* *
* @author njensen * @author njensen
* @version 1.0 * @version 1.0
*/ */
public abstract class BaseGfePyController extends PythonScript implements public abstract class BaseGfePyController extends PythonScriptController {
ILocalizationFileObserver {
private static final transient IUFStatusHandler statusHandler = UFStatus private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(BaseGfePyController.class); .getHandler(BaseGfePyController.class);
protected static final String INTERFACE = "interface";
protected DataManager dataMgr; 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 * Constructor
* *
@ -92,41 +72,8 @@ public abstract class BaseGfePyController extends PythonScript implements
protected BaseGfePyController(String filePath, String anIncludePath, protected BaseGfePyController(String filePath, String anIncludePath,
ClassLoader classLoader, DataManager dataManager, ClassLoader classLoader, DataManager dataManager,
String aPythonClassName) throws JepException { String aPythonClassName) throws JepException {
super(filePath, anIncludePath, classLoader); super(filePath, anIncludePath, classLoader, aPythonClassName);
dataMgr = dataManager; 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 * the name of the module to instantiate
* @throws JepException * @throws JepException
*/ */
public void instantiatePythonTool(String moduleName) throws JepException { @Override
public void instantiatePythonScript(String moduleName) throws JepException {
Map<String, Object> instanceMap = getStarterMap(moduleName); Map<String, Object> instanceMap = getStarterMap(moduleName);
instanceMap.put("dbss", dataMgr); instanceMap.put("dbss", dataMgr);
execute("instantiate", INTERFACE, instanceMap); 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 * 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) public List<FieldDefinition> getVarDictWidgets(String moduleName)
throws JepException { throws JepException {
if (!isInstantiated(moduleName)) { if (!isInstantiated(moduleName)) {
instantiatePythonTool(moduleName); instantiatePythonScript(moduleName);
} }
List<FieldDefinition> fieldDefs = null; List<FieldDefinition> fieldDefs = null;
if (getVariableList(moduleName) != null) { if (getVariableList(moduleName) != null) {
@ -239,119 +161,4 @@ public abstract class BaseGfePyController extends PythonScript implements
} }
return varDict; 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 * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Nov 17, 2011 dgilling Initial creation * Nov 17, 2011 dgilling Initial creation
* Jan 08, 2013 1486 dgilling Support changes to BaseGfePyController.
* *
* </pre> * </pre>
* *
@ -97,21 +98,16 @@ public class VCModuleController extends BaseGfePyController {
*/ */
public List<String> getMethodArgs(String moduleName, String method) public List<String> getMethodArgs(String moduleName, String method)
throws JepException { throws JepException {
String[] argNames = getMethodArguments(moduleName, method); List<String> argNames = new ArrayList<String>(getMethodArguments(
List<String> retVal = new ArrayList<String>(argNames.length); moduleName, method));
for (String arg : argNames) { argNames.remove("self");
if (!arg.equals("self")) { return argNames;
retVal.add(arg);
}
}
return retVal;
} }
public Object executeMethod(String moduleName, String methodName, public Object executeMethod(String moduleName, String methodName,
Map<String, Object> args, GridType type) throws JepException { Map<String, Object> args, GridType type) throws JepException {
if (!isInstantiated(moduleName)) { if (!isInstantiated(moduleName)) {
instantiatePythonTool(moduleName); instantiatePythonScript(moduleName);
} }
args.put(PyConstants.METHOD_NAME, methodName); args.put(PyConstants.METHOD_NAME, methodName);
@ -227,7 +223,7 @@ public class VCModuleController extends BaseGfePyController {
* .String) * .String)
*/ */
@Override @Override
public void instantiatePythonTool(String moduleName) throws JepException { public void instantiatePythonScript(String moduleName) throws JepException {
Map<String, Object> instanceMap = getStarterMap(moduleName); Map<String, Object> instanceMap = getStarterMap(moduleName);
execute("instantiate", INTERFACE, instanceMap); execute("instantiate", INTERFACE, instanceMap);
} }

View file

@ -45,7 +45,8 @@ import com.raytheon.viz.gfe.core.DataManager;
* SOFTWARE HISTORY * SOFTWARE HISTORY
* Date Ticket# Engineer Description * 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> * </pre>
* *
* @author njensen * @author njensen
@ -120,7 +121,7 @@ public class ProcedureController extends BaseGfePyController {
public Object executeProcedure(String procedureName, public Object executeProcedure(String procedureName,
Map<String, Object> args) throws JepException { Map<String, Object> args) throws JepException {
if (!isInstantiated(procedureName)) { if (!isInstantiated(procedureName)) {
instantiatePythonTool(procedureName); instantiatePythonScript(procedureName);
} }
args.put(PyConstants.METHOD_NAME, "execute"); args.put(PyConstants.METHOD_NAME, "execute");
args.put(PyConstants.MODULE_NAME, procedureName); args.put(PyConstants.MODULE_NAME, procedureName);

View file

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

View file

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

View file

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

View file

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

View file

@ -17,24 +17,24 @@ class RollBackImporter:
if match is not None: if match is not None:
level = match.group(1) level = match.group(1)
if level != 'base': if level != 'base':
LogStream.logEvent("IMPORTING:", name, result) # LogStream.logDebug("IMPORTING:", name, result)
self.newModules[result.__name__] = 1 self.newModules[result.__name__] = 1
else: # else:
LogStream.logDebug("IGNORING BASE:", name, result) # LogStream.logDebug("IGNORING BASE:", name, result)
else: # else:
LogStream.logDebug("IGNORING NON-LOCALIZED:", name, result) # LogStream.logDebug("IGNORING NON-LOCALIZED:", name, result)
else: # else:
LogStream.logDebug("IGNORING BUILTIN:", name, result) # LogStream.logDebug("IGNORING BUILTIN:", name, result)
return result return result
def rollback(self): def rollback(self):
for modname in self.newModules.keys(): for modname in self.newModules.keys():
if not self.previousModules.has_key(modname): if not self.previousModules.has_key(modname):
# Force reload when modname next imported # Force reload when modname next imported
LogStream.logEvent("UNLOADING:", modname, sys.modules[modname]) # LogStream.logDebug("UNLOADING:", modname, sys.modules[modname])
del(sys.modules[modname]) del(sys.modules[modname])
else: # else:
LogStream.logDebug("SKIPPING PRELOADED:", modname) # LogStream.logDebug("SKIPPING PRELOADED:", modname)
self.newModules = {} 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-Version: 1.12.1174.qualifier
Bundle-Vendor: RAYTHEON Bundle-Vendor: RAYTHEON
Bundle-RequiredExecutionEnvironment: JavaSE-1.6 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, Export-Package: com.raytheon.uf.common.python,
com.raytheon.uf.common.python.controller,
com.raytheon.uf.common.python.multiprocessing, com.raytheon.uf.common.python.multiprocessing,
com.raytheon.uf.common.python.thread com.raytheon.uf.common.python.thread

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information. * further licensing information.
**/ **/
package com.raytheon.viz.gfe; package com.raytheon.uf.common.python;
import java.io.File; import java.io.File;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -37,8 +37,8 @@ import jep.JepException;
* *
* Date Ticket# Engineer Description * 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> * </pre>
* *
* @author wldougher * @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);
}
}