diff --git a/cave/build/static/common/cave/etc/gfe/userPython/utilities/ProcedureInterface.py b/cave/build/static/common/cave/etc/gfe/userPython/utilities/ProcedureInterface.py index 5b26e561fd..773d73a916 100644 --- a/cave/build/static/common/cave/etc/gfe/userPython/utilities/ProcedureInterface.py +++ b/cave/build/static/common/cave/etc/gfe/userPython/utilities/ProcedureInterface.py @@ -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) - - - - - \ No newline at end of file diff --git a/cave/build/static/common/cave/etc/gfe/userPython/utilities/SmartToolInterface.py b/cave/build/static/common/cave/etc/gfe/userPython/utilities/SmartToolInterface.py index ee5e4a949c..0d22acdaff 100644 --- a/cave/build/static/common/cave/etc/gfe/userPython/utilities/SmartToolInterface.py +++ b/cave/build/static/common/cave/etc/gfe/userPython/utilities/SmartToolInterface.py @@ -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) diff --git a/cave/com.raytheon.viz.gfe/META-INF/MANIFEST.MF b/cave/com.raytheon.viz.gfe/META-INF/MANIFEST.MF index 54dd477613..af38430aa7 100644 --- a/cave/com.raytheon.viz.gfe/META-INF/MANIFEST.MF +++ b/cave/com.raytheon.viz.gfe/META-INF/MANIFEST.MF @@ -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, diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java index 3305246d2d..ea1e1334f4 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/BaseGfePyController.java @@ -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. * * * @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 pendingRemoves = new HashSet(); - - protected Set pendingAdds = new HashSet(); - - protected Set pendingReloads = new HashSet(); - /** * 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 getStarterMap(String moduleName) { - HashMap args = new HashMap(); - 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 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 instanceMap = getStarterMap(moduleName); instanceMap.put("dbss", dataMgr); execute("instantiate", INTERFACE, instanceMap); } - public boolean isInstantiated(String moduleName) throws JepException { - HashMap argMap = new HashMap(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 instanceMap = getStarterMap(moduleName); - instanceMap.put(PyConstants.METHOD_NAME, methodName); - List list = (List) 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 getVarDictWidgets(String moduleName) throws JepException { if (!isInstantiated(moduleName)) { - instantiatePythonTool(moduleName); + instantiatePythonScript(moduleName); } List 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 getStartupErrors() throws JepException { - return (List) execute("getStartupErrors", INTERFACE, null); - } - - protected void reloadModule(String name) throws JepException { - HashMap argMap = new HashMap(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 argMap = new HashMap(1); - argMap.put(PyConstants.MODULE_NAME, name); - execute("removeModule", INTERFACE, argMap); - } - - protected void addModule(String name) throws JepException { - HashMap argMap = new HashMap(1); - argMap.put(PyConstants.MODULE_NAME, name); - execute("addModule", INTERFACE, argMap); - } - } diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/vcparm/VCModuleController.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/vcparm/VCModuleController.java index 2a45629928..93890ee27c 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/vcparm/VCModuleController.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/vcparm/VCModuleController.java @@ -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. * * * @@ -97,21 +98,16 @@ public class VCModuleController extends BaseGfePyController { */ public List getMethodArgs(String moduleName, String method) throws JepException { - String[] argNames = getMethodArguments(moduleName, method); - List retVal = new ArrayList(argNames.length); - for (String arg : argNames) { - if (!arg.equals("self")) { - retVal.add(arg); - } - } - - return retVal; + List argNames = new ArrayList(getMethodArguments( + moduleName, method)); + argNames.remove("self"); + return argNames; } public Object executeMethod(String moduleName, String methodName, Map 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 instanceMap = getStarterMap(moduleName); execute("instantiate", INTERFACE, instanceMap); } diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureController.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureController.java index 9b48fff6f2..8c92a67310 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureController.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureController.java @@ -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. * * * @author njensen @@ -120,7 +121,7 @@ public class ProcedureController extends BaseGfePyController { public Object executeProcedure(String procedureName, Map args) throws JepException { if (!isInstantiated(procedureName)) { - instantiatePythonTool(procedureName); + instantiatePythonScript(procedureName); } args.put(PyConstants.METHOD_NAME, "execute"); args.put(PyConstants.MODULE_NAME, procedureName); diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureJob.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureJob.java index ab3d246e95..6a7a093b9d 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureJob.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/procedures/ProcedureJob.java @@ -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. * * * @@ -376,8 +377,8 @@ public class ProcedureJob extends AbstractQueueJob { Job progressJob = new AsyncProgressJob(procedureName, this); IStatus pjStatus = Status.CANCEL_STATUS; try { - String[] argNames = controller.getMethodArguments(procedureName, - "execute"); + List argNames = controller.getMethodArguments( + procedureName, "execute"); Map argMap = getArgValues(argNames, refSet, timeRange); controller.setVarDict(varDict); @@ -411,7 +412,7 @@ public class ProcedureJob extends AbstractQueueJob { * @return a map of argument names to objects * @throws GFEException */ - private Map getArgValues(String[] args, + private Map getArgValues(List args, ReferenceData refSet, TimeRange timeRange) throws GFEException { Map argValueMap = new HashMap(); // For each argument in args, append a value to the argValueList diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/EditActionProcessor.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/EditActionProcessor.java index 1eaa15dbc8..a9529d5dea 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/EditActionProcessor.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/EditActionProcessor.java @@ -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. * * * @@ -408,9 +408,8 @@ public class EditActionProcessor { @Override public void run() { try { - String[] args = dataMgr.getProcedureInterface() + List argList = dataMgr.getProcedureInterface() .getMethodArguments(name, "execute"); - List argList = Arrays.asList(args); if (!argList.contains("timeRange") && checkedList.contains("EmptyTimeRange")) { checkedList.remove("EmptyTimeRange"); diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/Tool.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/Tool.java index f5f1fbd529..e4c9bef34a 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/Tool.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/Tool.java @@ -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. * * * @@ -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 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 executeArgs = tool.getMethodArguments(toolName, "execute"); Object gridResult = null; Object[] argValues = getArgValues(executeArgs, gridTimeRange, toolTimeRange, editArea, dataMode); HashMap argMap = new HashMap(); - 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 prePostToolArgs = tool.getMethodArguments(toolName, methodName); Object[] prePostToolObjs = getArgValues(prePostToolArgs, gridTimeRange, toolTimeRange, editArea, dataMode); HashMap prePostToolMap = new HashMap(); - 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); } diff --git a/edexOsgi/build.edex/esb/data/utility/common_static/base/python/MasterInterface.py b/edexOsgi/build.edex/esb/data/utility/common_static/base/python/MasterInterface.py index 6ccc4c4210..8710a976dc 100644 --- a/edexOsgi/build.edex/esb/data/utility/common_static/base/python/MasterInterface.py +++ b/edexOsgi/build.edex/esb/data/utility/common_static/base/python/MasterInterface.py @@ -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 = [] diff --git a/edexOsgi/build.edex/esb/data/utility/edex_static/base/smartinit/RollBackImporter.py b/edexOsgi/build.edex/esb/data/utility/common_static/base/python/RollBackImporter.py similarity index 69% rename from edexOsgi/build.edex/esb/data/utility/edex_static/base/smartinit/RollBackImporter.py rename to edexOsgi/build.edex/esb/data/utility/common_static/base/python/RollBackImporter.py index 064013e694..eca97c7f58 100644 --- a/edexOsgi/build.edex/esb/data/utility/edex_static/base/smartinit/RollBackImporter.py +++ b/edexOsgi/build.edex/esb/data/utility/common_static/base/python/RollBackImporter.py @@ -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 = {} diff --git a/edexOsgi/build.edex/esb/data/utility/common_static/base/python/RollbackMasterInterface.py b/edexOsgi/build.edex/esb/data/utility/common_static/base/python/RollbackMasterInterface.py new file mode 100644 index 0000000000..98fef80653 --- /dev/null +++ b/edexOsgi/build.edex/esb/data/utility/common_static/base/python/RollbackMasterInterface.py @@ -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() + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.python/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.python/META-INF/MANIFEST.MF index 1f126961c1..09ef2666a9 100644 --- a/edexOsgi/com.raytheon.uf.common.python/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.python/META-INF/MANIFEST.MF @@ -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 diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/PythonErrorExtractor.java b/edexOsgi/com.raytheon.uf.common.python/src/com/raytheon/uf/common/python/PythonErrorExtractor.java similarity index 96% rename from cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/PythonErrorExtractor.java rename to edexOsgi/com.raytheon.uf.common.python/src/com/raytheon/uf/common/python/PythonErrorExtractor.java index 962c5a62dd..ea24517804 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/PythonErrorExtractor.java +++ b/edexOsgi/com.raytheon.uf.common.python/src/com/raytheon/uf/common/python/PythonErrorExtractor.java @@ -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. * * * @author wldougher diff --git a/edexOsgi/com.raytheon.uf.common.python/src/com/raytheon/uf/common/python/controller/IPythonScriptControllerFactory.java b/edexOsgi/com.raytheon.uf.common.python/src/com/raytheon/uf/common/python/controller/IPythonScriptControllerFactory.java new file mode 100644 index 0000000000..1cac48f07f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python/src/com/raytheon/uf/common/python/controller/IPythonScriptControllerFactory.java @@ -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. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 12, 2012            dgilling     Initial creation
+ * 
+ * 
+ * + * @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; +} diff --git a/edexOsgi/com.raytheon.uf.common.python/src/com/raytheon/uf/common/python/controller/PythonScriptController.java b/edexOsgi/com.raytheon.uf.common.python/src/com/raytheon/uf/common/python/controller/PythonScriptController.java new file mode 100644 index 0000000000..25bb350c4c --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.python/src/com/raytheon/uf/common/python/controller/PythonScriptController.java @@ -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. + *

+ * Script instances are "cached" within the interpreter, so this class + * implements the ILocalizationFileObserver interface so the cached instances + * can be properly updated as necessary. + * + *

+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Dec 12, 2012            dgilling     Initial creation
+ * 
+ * 
+ * + * @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 pendingRemoves = new HashSet(); + + protected Set pendingAdds = new HashSet(); + + protected Set pendingReloads = new HashSet(); + + /** + * 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 getStarterMap(String moduleName) { + Map args = new HashMap(); + 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 getStartupErrors() throws JepException { + return (List) 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 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 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 argMap = new HashMap(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 getMethodArguments(String moduleName, String methodName) + throws JepException { + Map instanceMap = getStarterMap(moduleName); + instanceMap.put(PyConstants.METHOD_NAME, methodName); + List list = (List) 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 argMap = new HashMap(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 argMap = new HashMap(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 argMap = new HashMap(1); + argMap.put(PyConstants.MODULE_NAME, name); + execute("addModule", INTERFACE, argMap); + } +}