From c9f2ab3e97ec289ee8c1bcfe4531c84f77ee7fa8 Mon Sep 17 00:00:00 2001 From: Douglas Gillespie <50671166+douggillespie@users.noreply.github.com> Date: Mon, 1 Aug 2022 11:13:24 +0100 Subject: [PATCH] puch to main (#44) * Variable sound output level Mods to SoundPlayback module to allow additional parameters. Implemented system for NI cards to allow changes to selected output voltage range meaning output can be boosted to level higher than current default. * Code to support nogui operations when no screens present on headless system * Fix problem of nogui headless operation trying to access screen size. * Click detector display fixes 1. ICI not displaying correctly 2. Component sizes in display dialog on hres monitors * Work on batch processing, after testing of options to autostart, autoexit and set wav file folder, database and binary store. * Update MHTClickTrainAlgorithm.java Fix unsynchronised access to a datablock in click train detector which was causing index errors. * Revamp of offline process messaging and control Includes some databsae logging of completed tasks * Offline task logging Bit more work, including notes and database storage of task reprocessing. Guess this could all become 'proper' PAMGuard data and be shown in a table on the display but that not priority enough. * Dialog packing Fix a couple of dialogs which don't back well on HDPI monitors --- pom.xml | 4 +- src/Acquisition/FileInputSystem.java | 12 +- src/Acquisition/FolderInputSystem.java | 6 +- src/PamController/PamControlledUnit.java | 43 +-- src/PamController/PamController.java | 65 +++- src/PamController/PamControllerInterface.java | 12 +- src/PamController/PamSettingManager.java | 10 - src/PamModel/PamModel.java | 10 +- src/PamView/NullGuiController.java | 1 + src/PamView/PamGui.java | 5 +- src/PamView/PamView.java | 10 - .../BinaryStorageDialog.java | 2 +- .../BinaryStorageDialogPanel.java | 1 + src/clickDetector/ClickToolBar.java | 3 +- .../offlineFuncs/ClicksOffline.java | 2 +- .../mht/MHTClickTrainAlgorithm.java | 22 +- .../offline/CTProcessDialog.java | 3 +- src/generalDatabase/sqlite/SqliteSystem.java | 3 +- .../Group3DLocaliserControl.java | 2 +- src/offlineProcessing/OLProcessDialog.java | 191 ++++++++--- src/offlineProcessing/OfflineTask.java | 80 ++++- src/offlineProcessing/OfflineTaskGroup.java | 208 +++++++++--- src/offlineProcessing/OfflineTaskManager.java | 111 ++++++- src/offlineProcessing/TaskActivity.java | 7 + src/offlineProcessing/TaskGroupParams.java | 7 +- src/offlineProcessing/TaskLogging.java | 84 ----- src/offlineProcessing/TaskMonitor.java | 67 ++-- src/offlineProcessing/TaskMonitorData.java | 201 ++++++------ src/offlineProcessing/TaskStatus.java | 19 ++ src/offlineProcessing/TaskStatusData.java | 9 + .../OfflineProcessingControlledUnit.java | 5 +- .../OfflineProcessingProcess.java | 3 +- .../OfflineTaskRegister.java | 3 +- .../offlineProcessingPlugin.java | 2 +- .../logging/OldTaskData.java | 53 ++++ .../logging/TaskLogging.java | 300 ++++++++++++++++++ .../logging/TaskLoggingData.java | 26 ++ .../logging/TaskLoggingDataBlock.java | 17 + src/pamViewFX/PamGuiManagerFX.java | 5 +- src/pamguard/Pamguard.java | 23 +- 40 files changed, 1249 insertions(+), 388 deletions(-) create mode 100644 src/offlineProcessing/TaskActivity.java delete mode 100644 src/offlineProcessing/TaskLogging.java create mode 100644 src/offlineProcessing/TaskStatus.java create mode 100644 src/offlineProcessing/TaskStatusData.java rename src/offlineProcessing/{ => legacyremotestuff}/OfflineProcessingControlledUnit.java (94%) rename src/offlineProcessing/{ => legacyremotestuff}/OfflineProcessingProcess.java (91%) rename src/offlineProcessing/{ => legacyremotestuff}/OfflineTaskRegister.java (73%) rename src/offlineProcessing/{ => legacyremotestuff}/offlineProcessingPlugin.java (98%) create mode 100644 src/offlineProcessing/logging/OldTaskData.java create mode 100644 src/offlineProcessing/logging/TaskLogging.java create mode 100644 src/offlineProcessing/logging/TaskLoggingData.java create mode 100644 src/offlineProcessing/logging/TaskLoggingDataBlock.java diff --git a/pom.xml b/pom.xml index 8a92ccc5..e187f178 100644 --- a/pom.xml +++ b/pom.xml @@ -274,7 +274,7 @@ https://artifacts.unidata.ucar.edu/repository/unidata-all/ - + diff --git a/src/Acquisition/FileInputSystem.java b/src/Acquisition/FileInputSystem.java index 5fbea317..fc12d573 100644 --- a/src/Acquisition/FileInputSystem.java +++ b/src/Acquisition/FileInputSystem.java @@ -61,6 +61,7 @@ import PamView.dialog.PamLabel; import PamView.dialog.warn.WarnOnce; import PamView.panel.PamPanel; import PamView.panel.PamProgressBar; +import pamguard.GlobalArguments; import warnings.PamWarning; /** @@ -1075,8 +1076,17 @@ public class FileInputSystem extends DaqSystem implements ActionListener, PamSe @Override public void daqHasEnded() { - // TODO Auto-generated method stub + fileListComplete(); + } + /** + * Called when all files to be processed have been processed. + */ + protected void fileListComplete() { + if (GlobalArguments.getParam(PamController.AUTOEXIT) != null) { + System.out.println("All sound files processed, PAMGuard can close on " + PamController.AUTOEXIT); + PamController.getInstance().batchProcessingComplete(); + } } JPanel statusPanel; diff --git a/src/Acquisition/FolderInputSystem.java b/src/Acquisition/FolderInputSystem.java index 227ff2d1..96bab40f 100644 --- a/src/Acquisition/FolderInputSystem.java +++ b/src/Acquisition/FolderInputSystem.java @@ -79,7 +79,7 @@ public class FolderInputSystem extends FileInputSystem implements PamSettings{ private FolderInputParameters folderInputParameters; - public static final String GlobalWavFolderArg = "wavfilefolder"; + public static final String GlobalWavFolderArg = "-wavfilefolder"; /** @@ -652,6 +652,10 @@ public class FolderInputSystem extends FileInputSystem implements PamSettings{ } calculateETA(); setFolderProgress(); + + if (currentFile > 0 && currentFile >= allFiles.size()) { + fileListComplete(); + } // System.out.println("FolderinputSytem: daqHasEnded"); } diff --git a/src/PamController/PamControlledUnit.java b/src/PamController/PamControlledUnit.java index 17bb7112..808ddccd 100644 --- a/src/PamController/PamControlledUnit.java +++ b/src/PamController/PamControlledUnit.java @@ -141,7 +141,7 @@ public abstract class PamControlledUnit implements SettingsNameProvider { private ModuleStatusManager moduleStatusManager; - private ArrayList offlineTasks = new ArrayList<>(); +// private ArrayList offlineTasks = new ArrayList<>(); /** * Instance number of this module. This is simply a count of @@ -829,26 +829,27 @@ public abstract class PamControlledUnit implements SettingsNameProvider { return worstStatus; } - /** - * Get a list of available offline tasks for this module. This is mostly used for tasks that - * might apply to many different types of data such as a localiser. e.g. the click detector knows - * that it has bearing and click id tasks, but it doens't know that there is a localiser that can - * also operate on the clicks, so it's important the localiser registers it's class and has it set - * to the right input data so that the task group in the click detector can find it. - * @return the offlineTasks - */ - public ArrayList getOfflineTasks() { - return offlineTasks; - } - - /** - * Add an offline task, which will become available to other modules should a - * TaskGroup request all available tasks from the system. - * @param offlineTask the offlineTask to add - */ - public void addOfflineTask(OfflineTask offlineTask) { - this.offlineTasks.add(offlineTask); - } +// /** +// * Get a list of available offline tasks for this module. This is mostly used for tasks that +// * might apply to many different types of data such as a localiser. e.g. the click detector knows +// * that it has bearing and click id tasks, but it doens't know that there is a localiser that can +// * also operate on the clicks, so it's important the localiser registers it's class and has it set +// * to the right input data so that the task group in the click detector can find it. +// * @return the offlineTasks +// */ +// public ArrayList getOfflineTasks() { + // moved to Global OfflineTaskManager class which does everything ! +// return offlineTasks; +// } +// +// /** +// * Add an offline task, which will become available to other modules should a +// * TaskGroup request all available tasks from the system. +// * @param offlineTask the offlineTask to add +// */ +// public void addOfflineTask(OfflineTask offlineTask) { +// this.offlineTasks.add(offlineTask); +// } public BackupInformation getBackupInformation() { return null; diff --git a/src/PamController/PamController.java b/src/PamController/PamController.java index 1f680f4d..227dbdaf 100644 --- a/src/PamController/PamController.java +++ b/src/PamController/PamController.java @@ -43,6 +43,7 @@ import Acquisition.AcquisitionProcess; import pamScrollSystem.AbstractScrollManager; import pamViewFX.PamGuiManagerFX; import pamViewFX.pamTask.PamTaskUpdate; +import pamguard.GlobalArguments; import pamguard.Pamguard; import soundPlayback.PlaybackControl; import warnings.PamWarning; @@ -51,6 +52,7 @@ import zipUnpacker.ZipUnpacker; import fftManager.FFTDataBlock; import fftManager.FFTDataUnit; import generalDatabase.DBControlUnit; +import javafx.application.Platform; import javafx.stage.Stage; import Array.ArrayManager; import PamController.command.NetworkController; @@ -128,6 +130,11 @@ public class PamController implements PamControllerInterface, PamSettings { public static final int RUN_NETWORKRECEIVER = 5; private int runMode = RUN_NORMAL; + + // flag used in main() to indicate that processing should start immediately. + public static final String AUTOSTART = "-autostart"; + // flag used in main() to indicate that pamguard should exit as soon as processing ends. + public static final String AUTOEXIT = "-autoexit"; /** * The pam model. @@ -300,10 +307,33 @@ public class PamController implements PamControllerInterface, PamSettings { public static void create(int runMode) { if (uniqueController == null) { PamController pamcontroller = new PamController(runMode, null); - // I don't see any reason not have have this running with the GUI. + /* + * I don't see any reason not have have this running with the GUI. + * It launches in a new thread, so it should be fine to have + * additional commands afterwards. + */ TerminalController tc = new TerminalController(pamcontroller); tc.getTerminalCommands(); } + + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + uniqueController.creationComplete(); + } + }); + } + + /** + * Not to sound God like, but this will be called on the AWT dispatch thread shortly + * after all modules are created, PAMGuard should be fully setup and all modules will + * have recieved INITIALISATION_COMPLETE and should be good to run + */ + private void creationComplete() { + if (GlobalArguments.getParam(PamController.AUTOSTART) != null) { + startLater(); // may as well give AWT time to loop it's queue once more + } } /** @@ -526,6 +556,7 @@ public class PamController implements PamControllerInterface, PamSettings { clearSelectorsAndSymbols(); + /** * Debug code for starting PG as soon as it's initialised. */ @@ -660,11 +691,24 @@ public class PamController implements PamControllerInterface, PamSettings { @Override public void pamClose() { + getUidManager().runShutDownOps(); + for (int i = 0; i < pamControlledUnits.size(); i++) { pamControlledUnits.get(i).pamClose(); } } + /** + * Shut down Pamguard + */ + public void shutDownPamguard() { + // force close the javaFX thread (because it won't close by itself - see Platform.setImplicitExit(false) in constructor + Platform.exit(); + + // terminate the JVM + System.exit(0); + } + /** * Go through all data blocks in all modules and tell them to save. * This has been built into PamProcess and PamDataBlock since we want @@ -1297,6 +1341,25 @@ public class PamController implements PamControllerInterface, PamSettings { pamControlledUnits.get(iU).pamHasStopped(); } guiFrameManager.pamEnded(); + + // no good having this here since it get's called at the end of every file. +// if (GlobalArguments.getParam(PamController.AUTOEXIT) != null) { +//// can exit here, since we've auto started, can auto exit. +// if (canClose()) { +// pamClose(); +// shutDownPamguard(); +// } +// } + } + + public void batchProcessingComplete( ) { + if (GlobalArguments.getParam(PamController.AUTOEXIT) != null) { + // can exit here, since we've auto started, can auto exit. + if (canClose()) { + pamClose(); + shutDownPamguard(); + } + } } diff --git a/src/PamController/PamControllerInterface.java b/src/PamController/PamControllerInterface.java index 03abda1b..3f6dd192 100644 --- a/src/PamController/PamControllerInterface.java +++ b/src/PamController/PamControllerInterface.java @@ -307,7 +307,10 @@ public interface PamControllerInterface { public static final int REORDER_CONTROLLEDUNITS = 8; /** * Automatically sent when PAMGAURD has finished loading it's - * initial settings file and created the GUI + * initial settings file and created the GUI. It's a good time for modules + * to subscribe to their data sources, but they shouldn't do much else since + * these go around in order, so when this arrives in the first module, other + * modules may not yet be setup. */ public static final int INITIALIZATION_COMPLETE = 9; /** @@ -404,6 +407,13 @@ public interface PamControllerInterface { * The medium has been updated. */ public static final int GLOBAL_MEDIUM_UPDATE = 24; + + /** + * Sent shortly after the main PAMGUard setup has been completed, but this point + * all modules will have received INITIALIZATION_COMPLETE and should be ready to + * go. + */ + public static final int READY_TO_RUN = 25; diff --git a/src/PamController/PamSettingManager.java b/src/PamController/PamSettingManager.java index 61a2e30e..e0abc8e8 100644 --- a/src/PamController/PamSettingManager.java +++ b/src/PamController/PamSettingManager.java @@ -33,13 +33,8 @@ import java.io.IOException; import java.io.InvalidClassException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.io.OutputStreamWriter; -import java.io.OutputStream; -import java.io.Writer; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Iterator; -import java.util.List; import javax.swing.JFileChooser; import javax.swing.JFrame; @@ -47,11 +42,6 @@ import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.swing.plaf.FontUIResource; -import GPS.GPSParameters; -import GPS.UpdateClockDialog; -import binaryFileStorage.BinaryStoreSettings; -import offlineProcessing.OfflineProcessingControlledUnit; -import offlineProcessing.OfflineProcessingProcess; import pamViewFX.fxNodes.utilsFX.PamUtilsFX; import pamViewFX.fxSettingsPanes.SettingsFileDialogFX; diff --git a/src/PamModel/PamModel.java b/src/PamModel/PamModel.java index d14cbb02..84da16e5 100644 --- a/src/PamModel/PamModel.java +++ b/src/PamModel/PamModel.java @@ -392,11 +392,11 @@ final public class PamModel implements PamModelInterface, PamSettings { // mi.setModulesMenuGroup(utilitiesGroup); // mi.setHidden(SMRUEnable.isEnable() == false); - mi = PamModuleInfo.registerControlledUnit("offlineProcessing.OfflineProcessingControlledUnit", "Offline Processing"); - mi.setModulesMenuGroup(utilitiesGroup); - mi.setMinNumber(0); - mi.setMaxNumber(1); - mi.setHidden(SMRUEnable.isEnable() == false); +// mi = PamModuleInfo.registerControlledUnit("offlineProcessing.OfflineProcessingControlledUnit", "Offline Processing"); +// mi.setModulesMenuGroup(utilitiesGroup); +// mi.setMinNumber(0); +// mi.setMaxNumber(1); +// mi.setHidden(SMRUEnable.isEnable() == false); mi = PamModuleInfo.registerControlledUnit(TurbineOperationControl.class.getName(), TurbineOperationControl.unitType); diff --git a/src/PamView/NullGuiController.java b/src/PamView/NullGuiController.java index 6c1ad3d1..9bab00b9 100644 --- a/src/PamView/NullGuiController.java +++ b/src/PamView/NullGuiController.java @@ -32,6 +32,7 @@ public class NullGuiController implements PAMControllerGUI { @Override public void pamEnded() { // TODO Auto-generated method stub + } diff --git a/src/PamView/PamGui.java b/src/PamView/PamGui.java index e5d754f8..a502e0d8 100644 --- a/src/PamView/PamGui.java +++ b/src/PamView/PamGui.java @@ -1659,7 +1659,8 @@ public class PamGui extends PamView implements WindowListener, PamSettings { } // deal with anything that needs sorting out in the realm of UID's. - pamController.getUidManager().runShutDownOps(); + // move this to pamController.pamClose() +// pamController.getUidManager().runShutDownOps(); // if the user doesn't want to save the config file, make sure they know // that they'll lose any changes to the settings @@ -1685,7 +1686,7 @@ public class PamGui extends PamView implements WindowListener, PamSettings { pamControllerInterface.pamClose(); // shut down the JavaFX thread and the JVM - this.shutDownPamguard(); + pamController.shutDownPamguard(); return true; } diff --git a/src/PamView/PamView.java b/src/PamView/PamView.java index def9b468..f742de52 100644 --- a/src/PamView/PamView.java +++ b/src/PamView/PamView.java @@ -86,15 +86,5 @@ abstract public class PamView implements PamViewInterface { this.frameNumber = frameNumber; } - /** - * Shut down Pamguard - */ - public void shutDownPamguard() { - // force close the javaFX thread (because it won't close by itself - see Platform.setImplicitExit(false) in constructor - Platform.exit(); - - // terminate the JVM - System.exit(0); - } } diff --git a/src/binaryFileStorage/BinaryStorageDialog.java b/src/binaryFileStorage/BinaryStorageDialog.java index 85ec7f12..fa69afeb 100644 --- a/src/binaryFileStorage/BinaryStorageDialog.java +++ b/src/binaryFileStorage/BinaryStorageDialog.java @@ -21,7 +21,7 @@ public class BinaryStorageDialog extends PamDialog { String help = "utilities.BinaryStore.docs.binarystore_overview"; setHelpPoint(help); - binaryStorageDialogPanel = new BinaryStorageDialogPanel(parentFrame, binaryStore.getClass() == SecondaryBinaryStore.class); + binaryStorageDialogPanel = new BinaryStorageDialogPanel(this, binaryStore.getClass() == SecondaryBinaryStore.class); setDialogComponent(binaryStorageDialogPanel.getPanel()); } diff --git a/src/binaryFileStorage/BinaryStorageDialogPanel.java b/src/binaryFileStorage/BinaryStorageDialogPanel.java index 56ac8118..1fdbbcc6 100644 --- a/src/binaryFileStorage/BinaryStorageDialogPanel.java +++ b/src/binaryFileStorage/BinaryStorageDialogPanel.java @@ -191,6 +191,7 @@ public class BinaryStorageDialogPanel { noiseStoreType.setSelectedItem(binaryStoreSettings.getNoiseStoreType()); enableControls(); + owner.pack(); } /** diff --git a/src/clickDetector/ClickToolBar.java b/src/clickDetector/ClickToolBar.java index 14e8b773..0a77021d 100644 --- a/src/clickDetector/ClickToolBar.java +++ b/src/clickDetector/ClickToolBar.java @@ -10,6 +10,7 @@ import javax.swing.JLabel; import javax.swing.JRadioButton; import javax.swing.JToolBar; +@Deprecated // - not used public class ClickToolBar implements ActionListener{ private JToolBar toolBar; @@ -18,7 +19,7 @@ public class ClickToolBar implements ActionListener{ private ClickTabPanelControl clickTabPanelControl; - public ClickToolBar(ClickTabPanelControl clickTabPanelControl) { + private ClickToolBar(ClickTabPanelControl clickTabPanelControl) { this.clickTabPanelControl = clickTabPanelControl; toolBar = new JToolBar(); diff --git a/src/clickDetector/offlineFuncs/ClicksOffline.java b/src/clickDetector/offlineFuncs/ClicksOffline.java index d76d578e..4ee5ad25 100644 --- a/src/clickDetector/offlineFuncs/ClicksOffline.java +++ b/src/clickDetector/offlineFuncs/ClicksOffline.java @@ -599,7 +599,7 @@ public class ClicksOffline { * need click id and initial localisation information. */ // offlineTaskGroup.addTasks(clickControl.getOfflineTasks()); - OfflineTaskManager.addAvailableTasks(offlineTaskGroup, clickControl.getClickDataBlock()); + OfflineTaskManager.getManager().addAvailableTasks(offlineTaskGroup, clickControl.getClickDataBlock()); OfflineSuperDetFilter sdf = OfflineSuperDetFilter.makeSuperDetFilter(clickControl.getClickDataBlock(), clickControl.getUnitName()+"SuperDetFilter"); offlineTaskGroup.setSuperDetectionFilter(sdf); // offlineTaskGroup.addTask(new ClickTrainClass(clickControl)); // bad idea ! diff --git a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java index a838bca4..43b58860 100644 --- a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java +++ b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java @@ -12,6 +12,7 @@ import PamUtils.PamCalendar; import PamguardMVC.PamDataUnit; import PamguardMVC.debug.Debug; import clickTrainDetector.ClickTrainControl; +import clickTrainDetector.ClickTrainDataBlock; import clickTrainDetector.TempCTDataUnit; import clickTrainDetector.CTDataUnit; import clickTrainDetector.clickTrainAlgorithms.CTAlgorithmInfo; @@ -287,16 +288,19 @@ public class MHTClickTrainAlgorithm implements ClickTrainAlgorithm, PamSettings */ private synchronized void grabUnconfirmedTrains(MHTAlgorithm mhtAlgorithm) { - ListIterator iterator = clickTrainControl.getClickTrainProcess().getUnconfirmedCTDataBlock().getListIterator(0); - - //clear the data block - TempCTDataUnit tempCTUnit; - while (iterator.hasNext()) { - tempCTUnit = iterator.next(); - tempCTUnit.removeAllSubDetections(); - tempCTUnit.clearSubdetectionsRemoved(); + ClickTrainDataBlock unconfirmedBlock = clickTrainControl.getClickTrainProcess().getUnconfirmedCTDataBlock(); + synchronized (unconfirmedBlock.getSynchLock()) { + ListIterator iterator = unconfirmedBlock.getListIterator(0); + + //clear the data block + TempCTDataUnit tempCTUnit; + while (iterator.hasNext()) { + tempCTUnit = iterator.next(); + tempCTUnit.removeAllSubDetections(); + tempCTUnit.clearSubdetectionsRemoved(); + } + unconfirmedBlock.clearAll(); } - clickTrainControl.getClickTrainProcess().getUnconfirmedCTDataBlock().clearAll(); if (mhtAlgorithm.mhtKernal.getActiveTracks()==null) return; diff --git a/src/clickTrainDetector/offline/CTProcessDialog.java b/src/clickTrainDetector/offline/CTProcessDialog.java index 5f301e87..0f8e07cf 100644 --- a/src/clickTrainDetector/offline/CTProcessDialog.java +++ b/src/clickTrainDetector/offline/CTProcessDialog.java @@ -6,6 +6,7 @@ import offlineProcessing.OLProcessDialog; import offlineProcessing.OfflineTask; import offlineProcessing.OfflineTaskGroup; import offlineProcessing.TaskMonitor; +import offlineProcessing.TaskStatus; /** * A click train offline dialog which ensure that the click train offline @@ -33,7 +34,7 @@ public class CTProcessDialog extends OLProcessDialog { * @param task - the task group in whihc enable controls has been called from */ public void enableControls(OfflineTask task) { - boolean nr = getCurrentStatus() != TaskMonitor.TASK_RUNNING; + boolean nr = getCurrentStatus() != TaskStatus.RUNNING; int nTasks = getTaskGroup().getNTasks(); OfflineTask aTask; int selectedTasks = 0; diff --git a/src/generalDatabase/sqlite/SqliteSystem.java b/src/generalDatabase/sqlite/SqliteSystem.java index 2bb92d33..b41d71b8 100644 --- a/src/generalDatabase/sqlite/SqliteSystem.java +++ b/src/generalDatabase/sqlite/SqliteSystem.java @@ -122,7 +122,8 @@ public class SqliteSystem extends DBSystem implements PamSettings { File newFile = new File(databaseName); // if the file doesn't exit, consider creating it. if (newFile.exists() == false) { - newFile = createNewDatabase(databaseName, null, true); + boolean ask = GlobalArguments.getParam(DBControl.GlobalDatabaseNameArg) == null; + newFile = createNewDatabase(databaseName, null, ask); if (newFile == null) { System.out.println("Unable to create "+newFile); return; diff --git a/src/group3dlocaliser/Group3DLocaliserControl.java b/src/group3dlocaliser/Group3DLocaliserControl.java index af8b4209..1e2baa04 100644 --- a/src/group3dlocaliser/Group3DLocaliserControl.java +++ b/src/group3dlocaliser/Group3DLocaliserControl.java @@ -56,7 +56,7 @@ public class Group3DLocaliserControl extends PamControlledUnit implements PamSet * only used in viewer, but no hard in creating it. */ g3DOfflineTask = new Group3DOfflineTask(this); - addOfflineTask(g3DOfflineTask); +// addOfflineTask(g3DOfflineTask); } @Override diff --git a/src/offlineProcessing/OLProcessDialog.java b/src/offlineProcessing/OLProcessDialog.java index fc8cd730..9302b10b 100644 --- a/src/offlineProcessing/OLProcessDialog.java +++ b/src/offlineProcessing/OLProcessDialog.java @@ -27,12 +27,16 @@ import javax.swing.border.TitledBorder; import PamUtils.PamCalendar; import PamUtils.TxtFileUtils; import PamView.CancelObserver; +import PamView.DBTextArea; import PamView.dialog.PamDialog; import PamView.dialog.PamFileBrowser; import PamView.dialog.PamGridBagContraints; +import PamView.panel.PamAlignmentPanel; import PamView.panel.PamPanel; import PamView.panel.PamProgressBar; import PamguardMVC.PamDataBlock; +import offlineProcessing.logging.OldTaskData; +import offlineProcessing.logging.TaskLogging; import offlineProcessing.superdet.OfflineSuperDetFilter; /** @@ -54,9 +58,11 @@ public class OLProcessDialog extends PamDialog { private JCheckBox[] taskCheckBox; private JButton[] settingsButton; private JLabel status, currFile; - private JProgressBar globalProgress, fileProgress; + private JProgressBar globalProgress; // file by file progress 1: nFiles + private JProgressBar loadedProgress; // progress throgh loaded data private JCheckBox deleteOldData; private JLabel dataInfo; + private DBTextArea noteText; /** * Pane which can be used to add extra controls for different 'dataSelection' types. */ @@ -85,7 +91,7 @@ public class OLProcessDialog extends PamDialog { public static ImageIcon settings = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png")); - int currentStatus = TaskMonitor.TASK_IDLE; + TaskStatus currentStatus = TaskStatus.IDLE; public OLProcessDialog(Window parentFrame, OfflineTaskGroup taskGroup, String title) { @@ -96,7 +102,8 @@ public class OLProcessDialog extends PamDialog { JPanel mainPanel = new JPanel(); mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - JPanel dataSelectPanel = new JPanel(new BorderLayout()); + JPanel dataSelectPanel = new PamAlignmentPanel(BorderLayout.WEST); + dataSelectPanel.setLayout(new BorderLayout()); dataSelectPanel.setBorder(new TitledBorder("Data Options")); dataSelectPanel.add(BorderLayout.WEST, new JLabel("Data ")); dataInfo = new JLabel(" ", SwingConstants.CENTER); // create this first to avoid null pointer exception @@ -124,7 +131,8 @@ public class OLProcessDialog extends PamDialog { dataSelectPanel.add(BorderLayout.SOUTH, southPanel); - JPanel tasksPanel = new JPanel(new GridBagLayout()); + JPanel tasksPanel = new PamAlignmentPanel(BorderLayout.WEST); + tasksPanel.setLayout(new GridBagLayout()); tasksPanel.setBorder(new TitledBorder("Tasks")); int nTasks = taskGroup.getNTasks(); taskCheckBox = new JCheckBox[nTasks]; @@ -144,23 +152,33 @@ public class OLProcessDialog extends PamDialog { } c.gridy++; } + + JPanel notePanel = new JPanel(new BorderLayout()); + notePanel.setBorder(new TitledBorder("Notes")); + noteText = new DBTextArea(2, 40, TaskLogging.TASK_NOTE_LENGTH); + noteText.getComponent().setToolTipText("Notes to add to database record of complete tasks"); + notePanel.add(BorderLayout.CENTER, noteText.getComponent()); - JPanel progressPanel = new JPanel(new GridBagLayout()); +// JPanel progressPanel = new JPanel(new GridBagLayout()); + JPanel progressPanel = new PamAlignmentPanel(BorderLayout.WEST); + progressPanel.setLayout(new GridBagLayout()); progressPanel.setBorder(new TitledBorder("Progress")); c = new PamGridBagContraints(); + c.gridwidth = 3; addComponent(progressPanel, status = new JLabel(" "), c); - c.gridx++; + c.gridy++; addComponent(progressPanel, currFile = new JLabel(" "), c); c.gridx = 0; c.gridy++; + c.gridwidth = 1; addComponent(progressPanel, new JLabel("File ", SwingConstants.RIGHT), c); c.gridx++; - addComponent(progressPanel, fileProgress = new PamProgressBar(), c); + addComponent(progressPanel, loadedProgress = new PamProgressBar(0, 100), c); c.gridx = 0; c.gridy++; addComponent(progressPanel, new JLabel("All Data ", SwingConstants.RIGHT), c); c.gridx++; - addComponent(progressPanel, globalProgress = new PamProgressBar(), c); + addComponent(progressPanel, globalProgress = new PamProgressBar(00, 100), c); mainPanel.add(dataSelectPanel); @@ -170,6 +188,7 @@ public class OLProcessDialog extends PamDialog { } mainPanel.add(tasksPanel); + mainPanel.add(notePanel); mainPanel.add(progressPanel); getOkButton().setText("Start"); @@ -214,7 +233,10 @@ public class OLProcessDialog extends PamDialog { for (int i = 0; i < nTasks; i++) { aTask = taskGroup.getTask(i); taskCheckBox[i].setSelected(taskGroupParams.getTaskSelection(i)); + } + noteText.setText(taskGroupParams.taskNote); + setTaskToolTips(); // deleteOldData.setSelected(offlineClassifierParams.deleteOld); } @@ -224,7 +246,7 @@ public class OLProcessDialog extends PamDialog { @Override public boolean cancelPressed() { - if (currentStatus==TaskMonitor.TASK_RUNNING) { + if (currentStatus==TaskStatus.RUNNING) { cancelButtonPressed(); return false; } @@ -239,7 +261,7 @@ public class OLProcessDialog extends PamDialog { return; } if (taskGroup.runTasks()) { - currentStatus = TaskMonitor.TASK_RUNNING; + currentStatus = TaskStatus.RUNNING; getCancelButton().setText("Stop!"); } } @@ -257,7 +279,7 @@ public class OLProcessDialog extends PamDialog { * @param task - the task group in whihc enable controls has been called from */ public void enableControls(OfflineTask task) { - boolean nr = currentStatus != TaskMonitor.TASK_RUNNING; + boolean nr = currentStatus != TaskStatus.RUNNING; int nTasks = taskGroup.getNTasks(); OfflineTask aTask; int selectedTasks = 0; @@ -279,9 +301,9 @@ public class OLProcessDialog extends PamDialog { @Override public void cancelButtonPressed() { - if (currentStatus == TaskMonitor.TASK_RUNNING) { + if (currentStatus == TaskStatus.RUNNING) { taskGroup.killTasks(); - currentStatus=TaskMonitor.TASK_INTERRRUPTED; + currentStatus=TaskStatus.INTERRUPTED; enableControls(); getCancelButton().setText("Close"); @@ -325,8 +347,33 @@ public class OLProcessDialog extends PamDialog { } } + String note = noteText.getText(); + if (note == null || note.length() == 0) { + return PamDialog.showWarning(super.getOwner(), "Task note", "you must enter a note about what you are doing"); + } + taskGroupParams.taskNote = note; + return true; } + + public void setTaskToolTips() { + int nTasks = taskGroup.getNTasks(); + + OfflineTask aTask; + for (int i = 0; i < nTasks; i++) { + aTask = taskGroup.getTask(i); + OldTaskData taskData = TaskLogging.getTaskLogging().readLastTaskData(taskGroup, aTask); + if (taskData == null) { + taskCheckBox[i].setToolTipText("Task not run"); + } + else { + String tip = "Last run: " + taskData.toString() ; + tip = tip.replace("\n", "
"); + taskCheckBox[i].setToolTipText(tip); + } + } + + } public void newDataSelection() { int sel = dataSelection.getSelectedIndex(); @@ -563,7 +610,7 @@ public class OLProcessDialog extends PamDialog { @Override public void windowClosing(WindowEvent arg0) { - if (currentStatus == TaskMonitor.TASK_RUNNING) { + if (currentStatus == TaskStatus.RUNNING) { return; } setVisible(false); @@ -639,47 +686,105 @@ public class OLProcessDialog extends PamDialog { */ class OLMonitor implements TaskMonitor { - int doneFiles = 0; - - int numFiles = 0; - @Override - public void setFileName(String fileName) { - // currFile.setText(fileName); - if (taskGroup.getTaskGroupParams().dataChoice == TaskGroupParams.PROCESS_LOADED) { - currFile.setText("Loaded data"); + public void setTaskStatus(TaskMonitorData taskMonitorData) { + status.setText(taskMonitorData.taskStatus.toString() + ", " + taskMonitorData.taskActivity.toString()); + if (taskMonitorData.fileOrStatus == null || taskMonitorData.fileOrStatus.length() == 0) { + currFile.setText(" "); } - currFile.setText(String.format("File %d of %d", doneFiles, numFiles)); + else { + currFile.setText(taskMonitorData.fileOrStatus); + } + switch (taskMonitorData.taskActivity) { + case LINKING: + case LOADING: +// globalProgress.setMaximum(taskMonitorData.progMaximum); + globalProgress.setValue(taskMonitorData.progValue*100/taskMonitorData.progMaximum); + loadedProgress.setIndeterminate(true); + break; + case PROCESSING: + int prog = taskMonitorData.progValue*100/taskMonitorData.progMaximum; +// System.out.println("Set loaded progress to " + prog); + loadedProgress.setIndeterminate(false); + loadedProgress.setValue(prog); + break; + case IDLE: +// globalProgress.setValue(100); + loadedProgress.setIndeterminate(false); + break; + case SAVING: + default: + break; + } + switch (taskMonitorData.taskStatus) { + case COMPLETE: + globalProgress.setValue(100); + loadedProgress.setValue(100); + break; + case CRASHED: + break; + case IDLE: + break; + case INTERRUPTED: + break; + case RUNNING: + break; + case STARTING: + globalProgress.setValue(0); + loadedProgress.setValue(0); + break; + default: + break; + + } + setStatus(taskMonitorData.taskStatus); } - @Override - public void setNumFiles(int nFiles) { - globalProgress.setMaximum(numFiles = nFiles); - } - - @Override - public void setProgress(int global, double loaded) { - doneFiles = global; - globalProgress.setValue(global); - fileProgress.setValue((int) (loaded*100)); - } - - @Override - public void setStatus(int taskStatus) { - status.setText(TaskMonitorData.getStatusString(taskStatus)); +// int doneFiles = 0; +// +// int numFiles = 0; +// +// @Override +// public void setFileName(String fileName) { +// // currFile.setText(fileName); +// if (taskGroup.getTaskGroupParams().dataChoice == TaskGroupParams.PROCESS_LOADED) { +// currFile.setText("Loaded data"); +// } +// currFile.setText(String.format("File %d of %d", doneFiles, numFiles)); +// } +// +// @Override +// public void setNumFiles(int nFiles) { +// globalProgress.setMaximum(numFiles = nFiles); +// } +// +// @Override +// public void setProgress(int global, double loaded) { +// doneFiles = global; +// globalProgress.setValue(global); +// fileProgress.setValue((int) (loaded*100)); +// } +// +// @Override + public void setStatus(TaskStatus taskStatus) { +// status.setText(TaskMonitorData.getStatusString(taskStatus)); currentStatus=taskStatus; enableControls(); switch(taskStatus) { - case TaskMonitor.TASK_IDLE: - case TaskMonitor.TASK_COMPLETE: + case COMPLETE: + case CRASHED: + case IDLE: + case INTERRUPTED: getCancelButton().setText("Close"); + setTaskToolTips(); break; - case TaskMonitor.TASK_RUNNING: + case RUNNING: + case STARTING: getCancelButton().setText("Stop!"); break; default: - getCancelButton().setText("Close"); break; + } } } @@ -688,7 +793,7 @@ public class OLProcessDialog extends PamDialog { * Get the current status of the dialog. * @return the current status. */ - public int getCurrentStatus() { + public TaskStatus getCurrentStatus() { return currentStatus; } diff --git a/src/offlineProcessing/OfflineTask.java b/src/offlineProcessing/OfflineTask.java index a5ca3ac1..15dd1f38 100644 --- a/src/offlineProcessing/OfflineTask.java +++ b/src/offlineProcessing/OfflineTask.java @@ -12,11 +12,13 @@ import generalDatabase.clauses.PAMSelectClause; import java.util.ArrayList; import java.util.ListIterator; +import PamController.PamControlledUnit; import PamController.PamViewParameters; import dataMap.OfflineDataMapPoint; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; +import PamguardMVC.PamProcess; import PamguardMVC.superdet.SuperDetection; /** @@ -45,21 +47,51 @@ public abstract class OfflineTask { */ private PamDataBlock parentDataBlock; - /** - * Default constructor. Should no longer be used, but kept in case there are subclasses - * of OfflineTask in other plugins.
- * please use constructor 'public OfflineTask(PamDataBlock parentDataBlock)' instead - */ - @Deprecated - public OfflineTask() { - super(); - } +// /** +// * Default constructor. Should no longer be used, but kept in case there are subclasses +// * of OfflineTask in other plugins.
+// * please use constructor 'public OfflineTask(PamDataBlock parentDataBlock)' instead +// */ +// @Deprecated +// public OfflineTask() { +// super(); +// } /** * @param parentDataBlock */ public OfflineTask(PamDataBlock parentDataBlock) { super(); this.parentDataBlock = parentDataBlock; + /* + * every task is now going to be centrally registered in the offline task manager, but only + * if it has a PAMControlledUnit. Tasks can be identified in the database from the unit id + * information and the task name. + * There may be a few teething problems with this if a task is created in the constructor of + * a PamProcess ? though it should by then know it's controlled unit I think. + */ + PamControlledUnit parentControl = getTaskControlledUnit(); + if (parentControl == null) { + System.out.printf("Offline task %d with datablock %s is not associated with a PAMGuard module\n", getName(), parentDataBlock); + } + else { + OfflineTaskManager.getManager().registerTask(this); + } + + } + + /** + * Get the PAMControlled unit associated with a task. + * @return PAMControlled unit associated with a task. + */ + public PamControlledUnit getTaskControlledUnit() { + if (parentDataBlock == null) { + return null; + } + PamProcess parentProcess = parentDataBlock.getParentProcess(); + if (parentProcess == null) { + return null; + } + return parentProcess.getPamControlledUnit(); } /** @@ -96,6 +128,36 @@ public abstract class OfflineTask { * @return a name for the task, to be displayed in the dialog. */ abstract public String getName(); + + /** + * Get a unit type for the task. This is the unit type of + * the parent PAMGuard module. + * @return module name + */ + public String getUnitType() { + PamControlledUnit parentControl = getTaskControlledUnit(); + if (parentControl == null) { + return "Unknown ModuleName"; + } + else { + return parentControl.getUnitType(); + } + } + + /** + * Get a unit name for the task. This is the unit name of + * the parent PAMGuard module. + * @return module name + */ + public String getUnitName() { + PamControlledUnit parentControl = getTaskControlledUnit(); + if (parentControl == null) { + return "Unknown ModuleName"; + } + else { + return parentControl.getUnitName(); + } + } /** * task has settings which can be called diff --git a/src/offlineProcessing/OfflineTaskGroup.java b/src/offlineProcessing/OfflineTaskGroup.java index 4400f435..e99fc61b 100644 --- a/src/offlineProcessing/OfflineTaskGroup.java +++ b/src/offlineProcessing/OfflineTaskGroup.java @@ -12,6 +12,7 @@ import binaryFileStorage.DataUnitFileInformation; import dataMap.OfflineDataMap; import dataMap.OfflineDataMapPoint; import generalDatabase.DBControlUnit; +import offlineProcessing.logging.TaskLogging; import offlineProcessing.superdet.OfflineSuperDetFilter; import pamScrollSystem.DataTimeLimits; import pamScrollSystem.ViewLoadObserver; @@ -64,9 +65,10 @@ public class OfflineTaskGroup implements PamSettings { private DataTimeLimits dataTimeLimits; + private volatile TaskStatus completionStatus = TaskStatus.IDLE; /** * PamControlledunit required in constructor since some bookkeeping will - * be goign on in the background which will need the unit type and name. + * be going on in the background which will need the unit type and name. * @param pamControlledUnit host controlled unit. * @param settingsName Name to be used in PamSettings for storing some basic information * (which tasks are selected) @@ -150,11 +152,104 @@ public class OfflineTaskGroup implements PamSettings { */ public boolean runTasks() { setSummaryLists(); + + checkTaskTimes(); + + TaskMonitorData monData = new TaskMonitorData(TaskStatus.STARTING, TaskActivity.IDLE, 0, 0, null, 0); + if (taskMonitor != null) { + taskMonitor.setTaskStatus(monData); + } + logTaskStatus(monData); + worker = new TaskGroupWorker(); worker.execute(); return true; } + /** + * Check the start and end times of tasks before they are run. while not + * needed for things like process loaded, this is needed for the database + * record of what's been done. + */ + private void checkTaskTimes() { + if (primaryDataBlock == null) { + return; + } + long mapStart = 0; + long mapEnd = 0; + long loadedStart = 0; + long loadedEnd = 0; + OfflineDataMap dataMap = primaryDataBlock.getPrimaryDataMap(); + if (dataMap != null) { + mapStart = dataMap.getFirstDataTime(); + mapEnd = dataMap.getLastDataTime(); + } + loadedStart = primaryDataBlock.getCurrentViewDataStart(); + loadedEnd = primaryDataBlock.getCurrentViewDataEnd(); + + switch (taskGroupParams.dataChoice) { + case TaskGroupParams.PROCESS_ALL: + taskGroupParams.startRedoDataTime = mapStart; + taskGroupParams.endRedoDataTime = mapEnd; + break; + case TaskGroupParams.PROCESS_LOADED: + taskGroupParams.startRedoDataTime = loadedStart; + taskGroupParams.endRedoDataTime = loadedEnd; + break; + case TaskGroupParams.PROCESS_NEW: + // need to get last processed time from the database for every task + // then worry about what to do if they are different. + taskGroupParams.startRedoDataTime = getPreviousEndTime(); + taskGroupParams.endRedoDataTime = mapEnd; + break; + case TaskGroupParams.PROCESS_SPECIFICPERIOD: + // should have been set already, but... + break; + case TaskGroupParams.PROCESS_TME_CHUNKS: // whatever this is ? + break; + } + + } + + /** + * Look in the database to get the previous end time for all tasks. if + * it doesn't exist, then take the map start time. + * @return + */ + private long getPreviousEndTime() { + long previousEnd = 0; + OfflineDataMap dataMap = primaryDataBlock.getPrimaryDataMap(); + if (dataMap != null) { + previousEnd = dataMap.getFirstDataTime(); + } + // then scan the database to try to find if everything is later ... + long taskMinLatest = Long.MAX_VALUE; + for (OfflineTask aTask : offlineTasks) { + if (aTask.isDoRun() == false) { + continue; + } + Long taskLatest = getPreviousEndTime(aTask); + if (taskLatest != null) { + taskMinLatest = Math.min(taskMinLatest, taskLatest); + } + } + if (taskMinLatest != Long.MAX_VALUE) { + previousEnd = taskMinLatest; + } + + return previousEnd; + } + + /** + * Get the time of the end of the last run of data for this task. + * @param aTask Offline task + * @return end time of data in last record in database or NULL if no database records. + */ + private Long getPreviousEndTime(OfflineTask aTask) { + // TODO Auto-generated method stub + return null; + } + public void killTasks() { if (worker == null) { return; @@ -285,7 +380,6 @@ public class OfflineTaskGroup implements PamSettings { volatile boolean instantKill = false; - private int completionStatus = TaskMonitor.TASK_IDLE; private CPUMonitor cpuMonitor = new CPUMonitor(); @@ -303,7 +397,7 @@ public class OfflineTaskGroup implements PamSettings { @Override protected Integer doInBackground() { - completionStatus = TaskMonitor.TASK_RUNNING; + completionStatus = TaskStatus.RUNNING; try { prepareTasks(); switch (taskGroupParams.dataChoice) { @@ -324,15 +418,15 @@ public class OfflineTaskGroup implements PamSettings { break; } if (instantKill) { - completionStatus = TaskMonitor.TASK_INTERRRUPTED; + completionStatus = TaskStatus.INTERRUPTED; } else { - completionStatus = TaskMonitor.TASK_COMPLETE; + completionStatus = TaskStatus.COMPLETE; } } catch (Exception e) { e.printStackTrace(); - completionStatus = TaskMonitor.TASK_CRASHED; + completionStatus = TaskStatus.CRASHED; } completeTasks(); return null; @@ -375,14 +469,15 @@ public class OfflineTaskGroup implements PamSettings { OfflineDataMap dataMap = primaryDataBlock.getPrimaryDataMap(); int nMapPoints = dataMap.getNumMapPoints(startTime, endTime); int iMapPoint = 0; - publish(new TaskMonitorData(TaskMonitor.TASK_RUNNING, nMapPoints)); - publish(new TaskMonitorData(0, 0.0)); + publish(new TaskMonitorData(TaskStatus.RUNNING, TaskActivity.PROCESSING, nMapPoints, 0, "", + taskGroupParams.startRedoDataTime)); OfflineDataStore dataSource = dataMap.getOfflineDataSource(); Iterator mapIterator = dataMap.getListIterator(); OfflineDataMapPoint mapPoint; // System.out.println("NUMBER OF MAP POINTS: " + mapIterator.hasNext() // + "Start time: " + PamCalendar.formatDateTime(startTime) + "End time: " + PamCalendar.formatDateTime(endTime)); boolean reallyDoIt = false; + int iPoint = 0; while (mapIterator.hasNext()) { mapPoint = mapIterator.next(); reallyDoIt = true; @@ -394,12 +489,17 @@ public class OfflineTaskGroup implements PamSettings { Debug.out.printf("Skipping map point %s since no matching data\n", mapPoint.toString()); reallyDoIt = false;; } - publish(new TaskMonitorData(mapPoint.getName())); primaryDataBlock.clearAll(); + long lastTime = taskGroupParams.startRedoDataTime; + if (reallyDoIt) { + Runtime.getRuntime().gc(); //garbage collection + publish(new TaskMonitorData(TaskStatus.RUNNING , TaskActivity.LOADING, nMapPoints, iPoint++, mapPoint.getName(), + lastTime)); + primaryDataBlock.loadViewerData(new OfflineDataLoadInfo(mapPoint.getStartTime(), mapPoint.getEndTime()), null); primaryDataBlock.sortData(); @@ -424,17 +524,23 @@ public class OfflineTaskGroup implements PamSettings { if (superDetectionFilter != null) { superDetectionFilter.checkSubDetectionLinks(); } + publish(new TaskMonitorData(TaskStatus.RUNNING , TaskActivity.PROCESSING, nMapPoints, 0, mapPoint.getName(), + lastTime)); + processData(iMapPoint, mapPoint, mapPoint.getStartTime(), mapPoint.getEndTime()); + + lastTime = mapPoint.getEndTime(); + publish(new TaskMonitorData(TaskStatus.RUNNING , TaskActivity.SAVING, nMapPoints, 0, mapPoint.getName(), + lastTime)); } iMapPoint++; - publish(new TaskMonitorData(iMapPoint+1, 0.0)); +// publish(new TaskMonitorData(taskGroupParams.dataChoice, taskGroupParams.startRedoDataTime, taskGroupParams.endRedoDataTime, nMapPoints, 0, +// TaskMonitor.TASK_COMPLETE, TaskMonitor.TASK_COMPLETE, lastTime)); if (instantKill) { break; } } // } - publish(new TaskMonitorData(TaskMonitor.TASK_IDLE)); - publish(new TaskMonitorData(TaskMonitor.TASK_COMPLETE)); primaryDataBlock.loadViewerData(new OfflineDataLoadInfo(currentStart, currentEnd), null); } @@ -456,15 +562,16 @@ public class OfflineTaskGroup implements PamSettings { } private void processLoadedData() { - publish(new TaskMonitorData(TaskMonitor.TASK_RUNNING, 1)); + publish(new TaskMonitorData(TaskStatus.RUNNING, TaskActivity.PROCESSING, 1, 0, "Loaded Data", + taskGroupParams.startRedoDataTime)); if (dataTimeLimits == null) { processData(0, null, 0, Long.MAX_VALUE); } else { processData(0, null, dataTimeLimits.getMinimumMillis(), dataTimeLimits.getMaximumMillis()); } - publish(new TaskMonitorData(TaskMonitor.TASK_IDLE)); - publish(new TaskMonitorData(TaskMonitor.TASK_COMPLETE)); +// publish(new TaskMonitorData(TaskGroupParams.PROCESS_LOADED, taskGroupParams.startRedoDataTime, taskGroupParams.endRedoDataTime, 1, 0, "Loaded Data", +// TaskMonitor.TASK_COMPLETE, TaskMonitor.ACTIVITY_PROCESSING, taskGroupParams.endRedoDataTime)); } /** @@ -506,6 +613,13 @@ public class OfflineTaskGroup implements PamSettings { OfflineTask aTask; boolean unitChanged; DataUnitFileInformation fileInfo; + String dataName; + if (mapPoint != null) { + dataName = mapPoint.getName(); + } + else { + dataName = "Loaded Data"; + } /** * Make sure that any data from required data blocks is loaded. First check the * start and end times of the primary data units we actually WANT to process @@ -612,7 +726,8 @@ public class OfflineTaskGroup implements PamSettings { } unitsChanged++; if (totalUnits%nSay == 0) { - publish(new TaskMonitorData(globalProgress+1, (double) totalUnits / (double) nDatas)); + publish(new TaskMonitorData(TaskStatus.RUNNING, TaskActivity.PROCESSING, nToProcess, totalUnits, dataName, + dataUnit.getTimeMilliseconds())); } } for (int iTask = 0; iTask < nTasks; iTask++) { @@ -623,12 +738,13 @@ public class OfflineTaskGroup implements PamSettings { aTask.loadedDataComplete(); } // } + publish(new TaskMonitorData(TaskStatus.RUNNING, TaskActivity.SAVING, nToProcess, totalUnits, dataName, + processEndTime)); for (int i = 0; i < affectedDataBlocks.size(); i++) { //System.out.println("SAVE VIEWER DATA FOR: " + affectedDataBlocks.get(i) ); aDataBlock = affectedDataBlocks.get(i); aDataBlock.saveViewerData(); } - publish(new TaskMonitorData(globalProgress+1, (double) totalUnits / (double) nDatas)); Debug.out.printf("Processd %d out of %d data units at " + mapPoint + "\n", unitsChanged, totalUnits); commitDatabase(); } @@ -707,9 +823,9 @@ public class OfflineTaskGroup implements PamSettings { @Override public void sayProgress(int state, long loadStart, long loadEnd, long lastTime, int nLoaded) { - TaskMonitorData tmd = new TaskMonitorData(TaskMonitorData.LOADING_DATA); - tmd.dataType = TaskMonitorData.LOADING_DATA; - publish(tmd); +// TaskMonitorData tmd = new TaskMonitorData(TaskMonitorData.LOADING_DATA); +// tmd.dataType = TaskMonitorData.LOADING_DATA; +// publish(tmd); } @@ -725,29 +841,47 @@ public class OfflineTaskGroup implements PamSettings { if (taskMonitor == null) { return; } - int dataType = monData.dataType; - if ((dataType & TaskMonitorData.SET_STATUS) != 0) { - taskMonitor.setStatus(monData.status); - } - if ((dataType & TaskMonitorData.SET_NFILES) != 0) { - taskMonitor.setNumFiles(monData.nFiles); - } - if ((dataType & TaskMonitorData.SET_PROGRESS) != 0) { - taskMonitor.setProgress(monData.globalProgress, monData.loadedProgress); - // taskMonitor.setProgress(monData.globalProgress, .5); - } - if ((dataType & TaskMonitorData.SET_FILENAME) != 0) { - taskMonitor.setFileName(monData.fileName); - } - if (dataType == TaskMonitorData.LOADING_DATA) { - taskMonitor.setStatus(monData.status); - } + taskMonitor.setTaskStatus(monData); +// int dataType = monData.dataType; +// if ((dataType & TaskMonitorData.SET_STATUS) != 0) { +// taskMonitor.setStatus(monData.status); +// } +// if ((dataType & TaskMonitorData.SET_NFILES) != 0) { +// taskMonitor.setNumFiles(monData.nFiles); +// } +// if ((dataType & TaskMonitorData.SET_PROGRESS) != 0) { +// taskMonitor.setProgress(monData.globalProgress, monData.loadedProgress); +// // taskMonitor.setProgress(monData.globalProgress, .5); +// } +// if ((dataType & TaskMonitorData.SET_FILENAME) != 0) { +// taskMonitor.setFileName(monData.fileName); +// } +// if (dataType == TaskMonitorData.LOADING_DATA) { +// taskMonitor.setStatus(monData.status); +// } } + private void logTaskStatus(TaskMonitorData monitorData) { + for (OfflineTask aTask : offlineTasks) { + if (aTask.isDoRun() == false) { + continue; + } + + TaskLogging.getTaskLogging().logTask(this, aTask, monitorData); + + } + } + /** * some bookkeeping - write information about task completion to the database. */ public void tasksDone() { + // tell the logging that we're done. + TaskMonitorData monData = new TaskMonitorData(completionStatus, TaskActivity.IDLE, 1, 1, "", + taskGroupParams.endRedoDataTime); + logTaskStatus(monData); // log first, since the dialog will update it's tool tips based on databse read. + newMonitorData(monData); + long currentStart = primaryDataBlock.getCurrentViewDataStart(); long currentEnd = primaryDataBlock.getCurrentViewDataEnd(); //System.out.println("TASKS COMPLETE:"); diff --git a/src/offlineProcessing/OfflineTaskManager.java b/src/offlineProcessing/OfflineTaskManager.java index 6990bb1b..a88bfd1a 100644 --- a/src/offlineProcessing/OfflineTaskManager.java +++ b/src/offlineProcessing/OfflineTaskManager.java @@ -13,24 +13,36 @@ import PamguardMVC.PamDataBlock; */ public class OfflineTaskManager { + private static OfflineTaskManager singleInstance = null; + + private ArrayList globalTaskList = new ArrayList(); + + public static OfflineTaskManager getManager() { + if (singleInstance == null) { + singleInstance = new OfflineTaskManager(); + } + return singleInstance; + } + /** * Get a list of ALL offline tasks registered with all modules * in all of PAMGUard.

* N.B. Many tasks won't be registered. * @return list of all offline tasks */ - public static ArrayList getAllOfflineTasks() { - ArrayList allTasks = new ArrayList<>(); - PamController pamController = PamController.getInstance(); - int n = pamController.getNumControlledUnits(); - for (int i = 0; i < n; i++) { - PamControlledUnit pcu = pamController.getControlledUnit(i); - ArrayList unitTasks = pcu.getOfflineTasks(); - if (unitTasks != null) { - allTasks.addAll(unitTasks); - } - } - return allTasks; + public ArrayList getAllOfflineTasks() { +// ArrayList allTasks = new ArrayList<>(); +// PamController pamController = PamController.getInstance(); +// int n = pamController.getNumControlledUnits(); +// for (int i = 0; i < n; i++) { +// PamControlledUnit pcu = pamController.getControlledUnit(i); +// ArrayList unitTasks = pcu.getOfflineTasks(); +// if (unitTasks != null) { +// allTasks.addAll(unitTasks); +// } +// } +// return allTasks; + return globalTaskList; } /** @@ -38,7 +50,7 @@ public class OfflineTaskManager { * @param taskParentDataBlock parent data block for tasks * @return list of available tasks. */ - public static ArrayList getOfflineTasks(PamDataBlock taskParentDataBlock) { + public ArrayList getOfflineTasks(PamDataBlock taskParentDataBlock) { ArrayList allTasks = getAllOfflineTasks(); ArrayList wantedTasks = new ArrayList<>(); for (OfflineTask task : allTasks) { @@ -50,16 +62,85 @@ public class OfflineTaskManager { return wantedTasks; } + /** + * Get a list of all tasks in the system which associate with the given PAMGuard module + * @param pamControlledUnit parent PAMGuard module + * @return list of available tasks. + */ + public ArrayList getOfflineTasks(PamControlledUnit pamControlledUnit) { + ArrayList allTasks = getAllOfflineTasks(); + ArrayList wantedTasks = new ArrayList<>(); + for (OfflineTask task : allTasks) { + if (task == null) continue; + if (task.getTaskControlledUnit() == pamControlledUnit) { + wantedTasks.add(task); + } + } + return wantedTasks; + } + /** * Add all available tasks from the system which use the given datablock - * as input. Note that tasks already in the goup will NOT be added a second time. + * as primary input. * @param taskGroup Task group to add tasks to * @param taskParentDataBlock parent data block * @return number of tasks added */ - public static int addAvailableTasks(OfflineTaskGroup taskGroup, PamDataBlock taskParentDataBlock) { + public int addAvailableTasks(OfflineTaskGroup taskGroup, PamDataBlock taskParentDataBlock) { ArrayList tasks = getOfflineTasks(taskParentDataBlock); return taskGroup.addTasks(tasks); } + /** + * Register a task in the global list. It's possible some tasks might get + * recreated, in which case when registered they will replace the previous one + * This will cause trouble if two separate tasks have the same name, but that should + * not be possible. + * @param offlineTask + */ + public void registerTask(OfflineTask offlineTask) { + // if it exists, replace it. + OfflineTask existingTask = findOfflineTask(offlineTask); + if (existingTask != null) { + int ind = globalTaskList.indexOf(existingTask); + globalTaskList.set(ind, offlineTask); + } + else { + globalTaskList.add(offlineTask); + } + } + + /** + * find a task with the same module type, module name and task name. This should + * be enough to uniquely identify every task. + * @param offlineTask + * @return matching task or null. + */ + public OfflineTask findOfflineTask(OfflineTask offlineTask) { + return findOfflineTask(offlineTask.getUnitType(), offlineTask.getUnitName(), offlineTask.getName()); + } + + /** + * Find a registered task based on it's module type, module name and task name. This should + * be enough to uniquely identify every task. + * @param unitType + * @param unitName + * @param taskName + * @return matching task or null. + */ + public OfflineTask findOfflineTask(String unitType, String unitName, String taskName) { + // could possibly also do a check on class type ???? + for (OfflineTask aTask : globalTaskList) { + if (aTask.getUnitType().equals(unitType) == false) { + continue; + } + if (aTask.getUnitName().equals(unitName) == false) { + continue; + } + if (aTask.getName().equals(taskName)) { + return aTask; + } + } + return null; + } } diff --git a/src/offlineProcessing/TaskActivity.java b/src/offlineProcessing/TaskActivity.java new file mode 100644 index 00000000..63bfde5b --- /dev/null +++ b/src/offlineProcessing/TaskActivity.java @@ -0,0 +1,7 @@ +package offlineProcessing; + +public enum TaskActivity { + + IDLE, PROCESSING, LOADING, LINKING, SAVING; + +} diff --git a/src/offlineProcessing/TaskGroupParams.java b/src/offlineProcessing/TaskGroupParams.java index c1d7dd46..25497c24 100644 --- a/src/offlineProcessing/TaskGroupParams.java +++ b/src/offlineProcessing/TaskGroupParams.java @@ -33,7 +33,7 @@ public class TaskGroupParams implements Cloneable, Serializable, ManagedParamete static public final int PROCESS_NEW = 2; /** - * Time of the last bit of data to be processed. + * Time of the last section of data to be processed. */ public long lastDataTime; @@ -91,6 +91,11 @@ public class TaskGroupParams implements Cloneable, Serializable, ManagedParamete */ public ArrayList timeChunks; + /** + * Note which will get written to the database of completed tasks. + */ + public String taskNote; + /** * Set the selection state of a particular task. * @param iTask task number (counting from 0) diff --git a/src/offlineProcessing/TaskLogging.java b/src/offlineProcessing/TaskLogging.java deleted file mode 100644 index 1fc3c1ce..00000000 --- a/src/offlineProcessing/TaskLogging.java +++ /dev/null @@ -1,84 +0,0 @@ -package offlineProcessing; - -import java.sql.Connection; -import java.sql.Types; - -import PamController.PamControlledUnit; -import PamUtils.PamCalendar; -import generalDatabase.DBControlUnit; -import generalDatabase.EmptyTableDefinition; -import generalDatabase.PamConnection; -import generalDatabase.PamTableItem; -import generalDatabase.SQLTypes; - -/** - * Handles logging of tasks to the database. - * - * @author Doug Gillespie - * - */ -public class TaskLogging { - - private static TaskLogging taskLogging; - private EmptyTableDefinition tableDef; - private PamTableItem localTime, moduleType, moduleName, taskName, taskStart, taskStartMillis, taskEnd, taskEndMillis, - completionCode; - - private PamConnection con; - - private TaskLogging() { - tableDef = new EmptyTableDefinition("OfflineTasks"); - tableDef.addTableItem(localTime = new PamTableItem("PCLocalTime", Types.TIMESTAMP)); - tableDef.addTableItem(moduleType = new PamTableItem("Module Type", Types.CHAR, 50)); - tableDef.addTableItem(moduleName = new PamTableItem("Module Name", Types.CHAR, 50)); - tableDef.addTableItem(taskName = new PamTableItem("Task Name", Types.CHAR, 50)); - tableDef.addTableItem(taskStart = new PamTableItem("TaskStart", Types.TIMESTAMP)); - tableDef.addTableItem(taskStartMillis = new PamTableItem("TaskStartMillis", Types.INTEGER)); - tableDef.addTableItem(taskEnd = new PamTableItem("TaskEnd", Types.TIMESTAMP)); - tableDef.addTableItem(taskEndMillis = new PamTableItem("TaskEndMillis", Types.INTEGER)); - tableDef.addTableItem(completionCode = new PamTableItem("CompletionCode", Types.CHAR, 20)); - - /** - * Note that completionCode Strings can be got from - * TaskMonitorData.getStatusString - */ - } - - public static TaskLogging getTaskLogging() { - if (taskLogging == null) { - taskLogging = new TaskLogging(); - } - taskLogging.checkConnection(); - return taskLogging; - } - - private void checkConnection() { - // TODO Auto-generated method stub - PamConnection currentCon = DBControlUnit.findConnection(); - if (currentCon == con) { - return; - } - /** - * Need to check tables, etc. - */ - currentCon = con; - DBControlUnit.findDatabaseControl().getDbProcess().checkTable(tableDef); - } - - public boolean logTask(PamControlledUnit pcu, SQLTypes sqlTypes, OfflineTask task, long startTime, - long endTime, int completionStatus) { - localTime.setValue(sqlTypes.getTimeStamp(System.currentTimeMillis())); - moduleType.setValue(pcu.getUnitType()); - moduleName.setValue(pcu.getUnitType()); - taskName.setValue(task.getName()); - taskStart.setValue(sqlTypes.getTimeStamp(startTime)); - taskEnd.setValue(sqlTypes.getTimeStamp(endTime)); - taskStartMillis.setValue(startTime%1000); - taskEndMillis.setValue(endTime%1000); - completionCode.setValue(TaskMonitorData.getStatusString(completionStatus)); - - return false; - - } - -} diff --git a/src/offlineProcessing/TaskMonitor.java b/src/offlineProcessing/TaskMonitor.java index 623d0802..d2bf2200 100644 --- a/src/offlineProcessing/TaskMonitor.java +++ b/src/offlineProcessing/TaskMonitor.java @@ -9,36 +9,43 @@ package offlineProcessing; * */ public interface TaskMonitor { - - static public final int TASK_IDLE = 0; - static public final int TASK_RUNNING = 1; - static public final int TASK_INTERRRUPTED = 2; - static public final int TASK_COMPLETE = 3; - static public final int TASK_CRASHED = 4; +// +// static public final int TASK_IDLE = 0; +// static public final int TASK_STARTING = 1; // before it started. +// static public final int TASK_RUNNING = 2; +// static public final int TASK_INTERRRUPTED = 3; +// static public final int TASK_COMPLETE = 4; +// static public final int TASK_CRASHED = 5; - /** - * Set the task status. - * @param taskStatus - */ - public void setStatus(int taskStatus); +// public static final int ACTIVITY_PROCESSING = 10; +// public static final int ACTIVITY_LOADING = 11; +// public static final int ACTIVITY_LINKING = 12; +// public static final int ACTIVITY_SAVING = 13; - /** - * Set the total number of files to process - * (will be one if only loaded data are being processed). - * @param nFiles - */ - public void setNumFiles(int nFiles); - /** - * Set the overall task progress - *

- * @param global - global progress, i.e. number of files completed (0 - nFiles) - * @param loaded - progress though data currently loaded (0 - 1.) - */ - public void setProgress(int global, double loaded); - - /** - * Set the current file name. - * @param fileName - */ - public void setFileName(String fileName); + public void setTaskStatus(TaskMonitorData taskMonitorData); +// /** +// * Set the task status. +// * @param taskStatus +// */ +// public void setStatus(int taskStatus); +// +// /** +// * Set the total number of files to process +// * (will be one if only loaded data are being processed). +// * @param nFiles +// */ +// public void setNumFiles(int nFiles); +// /** +// * Set the overall task progress +// *

+// * @param global - global progress, i.e. number of files completed (0 - nFiles) +// * @param loaded - progress though data currently loaded (0 - 1.) +// */ +// public void setProgress(int global, double loaded); +// +// /** +// * Set the current file name. +// * @param fileName +// */ +// public void setFileName(String fileName); } diff --git a/src/offlineProcessing/TaskMonitorData.java b/src/offlineProcessing/TaskMonitorData.java index e32acc24..d290917e 100644 --- a/src/offlineProcessing/TaskMonitorData.java +++ b/src/offlineProcessing/TaskMonitorData.java @@ -8,105 +8,128 @@ package offlineProcessing; */ public class TaskMonitorData { - static public final int SET_NFILES = 0x1; - static public final int SET_FILENAME = 0x2; - static public final int SET_STATUS = 0x4; - static public final int SET_PROGRESS = 0x8; - static public final int LOADING_DATA = 0x10; - static public final int LINKING_DATA = 0x20; +// static public final int SET_NFILES = 0x1; +// static public final int SET_FILENAME = 0x2; +// static public final int SET_STATUS = 0x4; +// static public final int SET_PROGRESS = 0x8; +// static public final int LOADING_DATA = 0x10; +// static public final int LINKING_DATA = 0x20; - int dataType; + public int progMaximum; // used for both files and units. - int globalProgress; + public int progValue; - int nFiles; + public String fileOrStatus; // will be a file name or the words "Current data" or null - /** - * Progress through loaded data - * Values < 0 represent unknown (i.e. currently loading data). - * so progress bars should be set to indeterminate. - */ - double loadedProgress; + public TaskStatus taskStatus; - int status; + public TaskActivity taskActivity; + + public long lastDataDate; - String fileName; - /** - * Constructor used to set the status - * @param status status - */ - TaskMonitorData(int status) { - this.status = status; - dataType = SET_STATUS; - } - - /** - * Constructor used to set both the status and - * the total number of files. - * @param status status - * @param nFiles number of files - */ - TaskMonitorData(int status, int nFiles) { - this.status = status; - this.nFiles = nFiles; - dataType = SET_STATUS | SET_NFILES; - } - - /** - * Constructor used to set the current file name - * @param fileName file Name - */ - TaskMonitorData(String fileName) { - this.fileName = fileName; - dataType = SET_FILENAME; - } - - /** - * Constructor used to set the analysis progress. - * @param globalProgress - * @param loadedProgress - */ - TaskMonitorData(int globalProgress, double loadedProgress) { - this.globalProgress = globalProgress; - this.loadedProgress = loadedProgress; - dataType = SET_PROGRESS; + public TaskMonitorData(TaskStatus taskStatus, TaskActivity taskActivity, int totalFiles, int currentFile, + String fileOrStatus, long lastDataDate) { + super(); + this.progMaximum = totalFiles; + this.progValue = currentFile; + this.fileOrStatus = fileOrStatus; + this.taskStatus = taskStatus; + this.taskActivity = taskActivity; + this.lastDataDate = lastDataDate; } + +// int dataType; +// +// int globalProgress; +// +// int nFiles; +// +// /** +// * Progress through loaded data +// * Values < 0 represent unknown (i.e. currently loading data). +// * so progress bars should be set to indeterminate. +// */ +// double loadedProgress; +// +// int status; +// +// String fileName; +// +// +// /** +// * Constructor used to set the status +// * @param status status +// */ +// TaskMonitorData(int status) { +// this.status = status; +// dataType = SET_STATUS; +// } +// +// /** +// * Constructor used to set both the status and +// * the total number of files. +// * @param status status +// * @param nFiles number of files +// */ +// TaskMonitorData(int status, int nFiles) { +// this.status = status; +// this.nFiles = nFiles; +// dataType = SET_STATUS | SET_NFILES; +// } +// +// /** +// * Constructor used to set the current file name +// * @param fileName file Name +// */ +// TaskMonitorData(String fileName) { +// this.fileName = fileName; +// dataType = SET_FILENAME; +// } +// +// /** +// * Constructor used to set the analysis progress. +// * @param globalProgress +// * @param loadedProgress +// */ +// TaskMonitorData(int globalProgress, double loadedProgress) { +// this.globalProgress = globalProgress; +// this.loadedProgress = loadedProgress; +// dataType = SET_PROGRESS; +// } - /** - * - * @param status Task status - * @return some string or other to represent the status. - */ - public static String getStatusString(int status) { - switch(status) { - case TaskMonitor.TASK_IDLE: - return "Idle"; - case TaskMonitor.TASK_COMPLETE: - return "Done"; - case TaskMonitor.TASK_INTERRRUPTED: - return "Interrupted"; - case TaskMonitor.TASK_RUNNING: - return "Running"; - case TaskMonitor.TASK_CRASHED: - return "Crashed"; - } - return "Unknown"; - } +// /** +// * +// * @param status Task status +// * @return some string or other to represent the status. +// */ +// public static String getStatusString(int status) { +// switch(status) { +// case TaskMonitor.TASK_COMPLETE: +// return "Done"; +// case TaskMonitor.TASK_INTERRRUPTED: +// return "Interrupted"; +// case TaskMonitor.TASK_RUNNING: +// return "Running"; +// case TaskMonitor.TASK_CRASHED: +// return "Crashed"; +// } +// return "Unknown"; +// } - /** - * Turn a status string back into a code. - * @param statusString - * @return - */ - public static int getStatusCode(String statusString) { - for (int i = 0; i < 5; i++) { - if (statusString.equals(getStatusString(i))) { - return i; - } - } - return -1; - } +// /** +// * Turn a status string back into a code. +// * @param statusString +// * @return +// */ +// public static int getStatusCode(String statusString) { +// for (int i = 0; i < 5; i++) { +// if (statusString.equals(getStatusString(i))) { +// return i; +// } +// } +// return -1; +// } } diff --git a/src/offlineProcessing/TaskStatus.java b/src/offlineProcessing/TaskStatus.java new file mode 100644 index 00000000..556a3b2e --- /dev/null +++ b/src/offlineProcessing/TaskStatus.java @@ -0,0 +1,19 @@ +package offlineProcessing; + +public enum TaskStatus { + // +// static public final int TASK_IDLE = 0; +// static public final int TASK_STARTING = 1; // before it started. +// static public final int TASK_RUNNING = 2; +// static public final int TASK_INTERRRUPTED = 3; +// static public final int TASK_COMPLETE = 4; +// static public final int TASK_CRASHED = 5; + IDLE, STARTING, RUNNING, INTERRUPTED, COMPLETE, CRASHED; + + @Override + public String toString() { + return super.toString(); + } + + +} diff --git a/src/offlineProcessing/TaskStatusData.java b/src/offlineProcessing/TaskStatusData.java new file mode 100644 index 00000000..7770ad20 --- /dev/null +++ b/src/offlineProcessing/TaskStatusData.java @@ -0,0 +1,9 @@ +package offlineProcessing; + +public class TaskStatusData { + + public TaskStatusData() { + // TODO Auto-generated constructor stub + } + +} diff --git a/src/offlineProcessing/OfflineProcessingControlledUnit.java b/src/offlineProcessing/legacyremotestuff/OfflineProcessingControlledUnit.java similarity index 94% rename from src/offlineProcessing/OfflineProcessingControlledUnit.java rename to src/offlineProcessing/legacyremotestuff/OfflineProcessingControlledUnit.java index 888409a2..ce41e19b 100644 --- a/src/offlineProcessing/OfflineProcessingControlledUnit.java +++ b/src/offlineProcessing/legacyremotestuff/OfflineProcessingControlledUnit.java @@ -1,12 +1,12 @@ /** * */ -package offlineProcessing; +package offlineProcessing.legacyremotestuff; import java.util.ArrayList; import dataMap.DataMapPanel; - +import offlineProcessing.OfflineTaskGroup; import PamController.PamControlledUnit; import PamController.PamController; import PamController.PamControllerInterface; @@ -16,6 +16,7 @@ import PamController.PamSettingManager; * @author GrahamWeatherup *only run in Viewer mode to run all Offline Tasks */ +@Deprecated // too simplistic, won't be using this. public class OfflineProcessingControlledUnit extends PamControlledUnit{ // static OfflineProcessingControlledUnit singleInstance; diff --git a/src/offlineProcessing/OfflineProcessingProcess.java b/src/offlineProcessing/legacyremotestuff/OfflineProcessingProcess.java similarity index 91% rename from src/offlineProcessing/OfflineProcessingProcess.java rename to src/offlineProcessing/legacyremotestuff/OfflineProcessingProcess.java index a15156f5..3e12bf16 100644 --- a/src/offlineProcessing/OfflineProcessingProcess.java +++ b/src/offlineProcessing/legacyremotestuff/OfflineProcessingProcess.java @@ -1,11 +1,12 @@ /** * */ -package offlineProcessing; +package offlineProcessing.legacyremotestuff; import PamController.PamControlledUnit; import PamguardMVC.PamDataBlock; import PamguardMVC.PamProcess; +import offlineProcessing.OfflineTask; /** * @author GrahamWeatherup diff --git a/src/offlineProcessing/OfflineTaskRegister.java b/src/offlineProcessing/legacyremotestuff/OfflineTaskRegister.java similarity index 73% rename from src/offlineProcessing/OfflineTaskRegister.java rename to src/offlineProcessing/legacyremotestuff/OfflineTaskRegister.java index 5a13cd6e..74b5a504 100644 --- a/src/offlineProcessing/OfflineTaskRegister.java +++ b/src/offlineProcessing/legacyremotestuff/OfflineTaskRegister.java @@ -1,4 +1,4 @@ -package offlineProcessing; +package offlineProcessing.legacyremotestuff; /** @@ -8,6 +8,7 @@ package offlineProcessing; * @author Jamie Macaulay * */ +@Deprecated // there is nothing in here which shouldn't be in OfflineTaskManager public class OfflineTaskRegister { /** diff --git a/src/offlineProcessing/offlineProcessingPlugin.java b/src/offlineProcessing/legacyremotestuff/offlineProcessingPlugin.java similarity index 98% rename from src/offlineProcessing/offlineProcessingPlugin.java rename to src/offlineProcessing/legacyremotestuff/offlineProcessingPlugin.java index 8b77c0d4..033d804b 100644 --- a/src/offlineProcessing/offlineProcessingPlugin.java +++ b/src/offlineProcessing/legacyremotestuff/offlineProcessingPlugin.java @@ -22,7 +22,7 @@ -package offlineProcessing; +package offlineProcessing.legacyremotestuff; import PamModel.PamDependency; import PamModel.PamPluginInterface; diff --git a/src/offlineProcessing/logging/OldTaskData.java b/src/offlineProcessing/logging/OldTaskData.java new file mode 100644 index 00000000..ec30c09c --- /dev/null +++ b/src/offlineProcessing/logging/OldTaskData.java @@ -0,0 +1,53 @@ +package offlineProcessing.logging; + +import PamUtils.PamCalendar; +import offlineProcessing.TaskActivity; +import offlineProcessing.TaskMonitorData; +import offlineProcessing.TaskStatus; + +public class OldTaskData extends TaskMonitorData { + + public long firstDataDate; + + public long processingStart, processingEnd; + + private String taskNote; + + /** + * + * @param taskStatus completion status of task + * @param firstDataDate first data date + * @param lastDataDate last data date + * @param procStart date run started + * @param procEnd date run ended. + * @param taskNote + */ + public OldTaskData(TaskStatus taskStatus, long firstDataDate, + long lastDataDate, long procStart, long procEnd, String taskNote) { + super(taskStatus, TaskActivity.IDLE, 0, 0, null, lastDataDate); + this.firstDataDate = firstDataDate; + this.processingStart = procStart; + this.processingEnd = procEnd; + this.taskNote = taskNote; + } + + @Override + public String toString() { + String endStatus; + if (this.taskStatus == null) { + endStatus = "Unknown completion code. Possible crash"; + } + else { + endStatus = this.taskStatus.toString(); + } + String str = String.format("Processed from %s to %s on %s. %s", PamCalendar.formatDateTime(firstDataDate), + PamCalendar.formatDateTime(lastDataDate), PamCalendar.formatDateTime(this.processingStart), endStatus); + if (taskNote != null) { + str = str + "\n" + taskNote; +// str = "" + str + "\br" + taskNote + "<\\html>"; + } + return str; + } + + +} diff --git a/src/offlineProcessing/logging/TaskLogging.java b/src/offlineProcessing/logging/TaskLogging.java new file mode 100644 index 00000000..1193e05f --- /dev/null +++ b/src/offlineProcessing/logging/TaskLogging.java @@ -0,0 +1,300 @@ +package offlineProcessing.logging; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.HashMap; + +import PamController.PamControlledUnit; +import PamUtils.PamCalendar; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import generalDatabase.DBControlUnit; +import generalDatabase.EmptyTableDefinition; +import generalDatabase.PamConnection; +import generalDatabase.PamTableItem; +import generalDatabase.SQLLogging; +import generalDatabase.SQLTypes; +import generalDatabase.pamCursor.CursorFinder; +import generalDatabase.pamCursor.PamCursor; +import offlineProcessing.OfflineTask; +import offlineProcessing.OfflineTaskGroup; +import offlineProcessing.TaskActivity; +import offlineProcessing.TaskGroupParams; +import offlineProcessing.TaskMonitorData; +import offlineProcessing.TaskStatus; + +/** + * Handles logging of tasks to the database. + * + * @author Doug Gillespie + * + */ +public class TaskLogging { + + + private static TaskLogging taskLogging; + + public static final int TASK_NOTE_LENGTH = 80; + + private EmptyTableDefinition tableDef; + private PamTableItem utc, moduleType, moduleName, taskName, dataStart, dataEnd, runEnd, + completionCode, note; + + /** + * Storage mostly to keep id's of last database index for each task. + */ + private HashMap loggingData = new HashMap(); + + /* + * May want several different write and update cursors for this. e.g. when a task starts + * we want to write the UTC and id comlumns and the dataStart, but probably not the dataEnd and + * the runEnd columns. Then when we update (if we update) we'll occasionally update the dataEnd + * time, then only will in the runEnd and completionCode when the task has finished. + */ + private EmptyTableDefinition startTableDef, updateTableDef, completeTableDef; + + private PamConnection con; + + private static final String tableName = "OfflineTasks"; + +// private StartLogging startLogging; + private CursorFinder startCursorFinder, completeCursorFinder; + + private TaskLoggingDataBlock taskLoggingDataBlock; + + private TaskLogging() { + // table for everything (mostly used for reading) + tableDef = new EmptyTableDefinition(tableName); + tableDef.addTableItem(utc = new PamTableItem("UTC", Types.TIMESTAMP)); + tableDef.addTableItem(moduleType = new PamTableItem("Module Type", Types.CHAR, 50)); + tableDef.addTableItem(moduleName = new PamTableItem("Module Name", Types.CHAR, 50)); + tableDef.addTableItem(taskName = new PamTableItem("Task Name", Types.CHAR, 50)); + tableDef.addTableItem(dataStart = new PamTableItem("DataStart", Types.TIMESTAMP)); + tableDef.addTableItem(dataEnd = new PamTableItem("DataEnd", Types.TIMESTAMP)); + tableDef.addTableItem(runEnd = new PamTableItem("RunEnd", Types.TIMESTAMP)); + tableDef.addTableItem(completionCode = new PamTableItem("CompletionCode", Types.CHAR, 20)); + tableDef.addTableItem(note = new PamTableItem("Notes", Types.CHAR, TASK_NOTE_LENGTH)); + + taskLoggingDataBlock = new TaskLoggingDataBlock(); + + /** + * Note that completionCode Strings can be got from + * TaskMonitorData.getStatusString + */ + // table for startup write + startTableDef = new EmptyTableDefinition(tableName); + startTableDef.addTableItem(utc); + startTableDef.addTableItem(moduleType); + startTableDef.addTableItem(moduleName); + startTableDef.addTableItem(taskName); + startTableDef.addTableItem(dataStart); + startTableDef.addTableItem(note); +// startLogging = new StartLogging(taskLoggingDataBlock, startTableDef); + startCursorFinder = new CursorFinder(); + + + // table for startup write + updateTableDef = new EmptyTableDefinition(tableName); + updateTableDef.addTableItem(dataEnd); + + // table for startup write + completeTableDef = new EmptyTableDefinition(tableName); + completeTableDef.addTableItem(dataEnd); + completeTableDef.addTableItem(runEnd); + completeTableDef.addTableItem(completionCode); + completeCursorFinder = new CursorFinder(); + + + } + + public static TaskLogging getTaskLogging() { + if (taskLogging == null) { + taskLogging = new TaskLogging(); + } + taskLogging.checkConnection(); + return taskLogging; + } + + private boolean checkConnection() { + // TODO Auto-generated method stub + PamConnection currentCon = DBControlUnit.findConnection(); + if (currentCon != con) { + /** + * Need to check tables, etc. + */ + con = currentCon; + DBControlUnit.findDatabaseControl().getDbProcess().checkTable(tableDef); + } + return currentCon != null; + } + + public boolean logTask(OfflineTaskGroup taskGroup, OfflineTask task, TaskMonitorData monitorData) { + if (!checkConnection()) { + return false; + } + switch (monitorData.taskStatus) { +// case IDLE: + case STARTING: + return logStart(taskGroup, task, monitorData); + case RUNNING: + return logUpdate(taskGroup, task, monitorData); + case COMPLETE: + case CRASHED: + case INTERRUPTED: + return logComplete(taskGroup, task, monitorData); + default: + break; + + } + + + return true; + } + + /** + * Move all data from the cursor, even though not all objects may get used by the individual cursors. + * @param taskGroup + * @param task + * @param monitorData + */ + private void fillTableData(OfflineTaskGroup taskGroup, OfflineTask task, TaskMonitorData monitorData) { + TaskGroupParams groupParams = taskGroup.getTaskGroupParams(); + SQLTypes sqlTypes = con.getSqlTypes(); + utc.setValue(sqlTypes.getTimeStamp(System.currentTimeMillis())); + moduleType.setValue(task.getUnitType()); + moduleName.setValue(task.getUnitName()); + taskName.setValue(task.getName()); + dataStart.setValue(sqlTypes.getTimeStamp(groupParams.startRedoDataTime)); + dataEnd.setValue(sqlTypes.getTimeStamp(monitorData.lastDataDate)); + runEnd.setValue(sqlTypes.getTimeStamp(System.currentTimeMillis())); + completionCode.setValue(monitorData.taskStatus.toString()); + note.setValue(groupParams.taskNote); + } + + /** + * Get TaskMonitorData from the database cursor. + * @param taskGroup + * @param task + * @return + */ + private OldTaskData readTableData() { + SQLTypes sqlTypes = con.getSqlTypes(); + long utc = SQLTypes.millisFromTimeStamp(this.utc.getValue()); + String modType = moduleType.getDeblankedStringValue(); + String modName = moduleName.getDeblankedStringValue(); + String tskName = taskName.getDeblankedStringValue(); + long dStart = SQLTypes.millisFromTimeStamp(dataStart.getValue()); + long dEnd = SQLTypes.millisFromTimeStamp(dataEnd.getValue()); + long procEnd = SQLTypes.millisFromTimeStamp(runEnd.getValue()); + String compStatus = completionCode.getDeblankedStringValue(); + TaskStatus status = null; + try { + status = TaskStatus.valueOf(TaskStatus.class, compStatus); + } + catch (IllegalArgumentException e) { + System.out.printf("Uknown completion code \"%s\" for task %s ended at %s\n", compStatus, tskName, PamCalendar.formatDateTime(dEnd)); + } + String taskNote = note.getDeblankedStringValue(); + OldTaskData monData = new OldTaskData(status, dStart, dEnd, utc, procEnd, taskNote); + return monData; + } + + /** + * Get the last data for an offline task. + * @param taskGroup + * @param task + * @return + */ + public OldTaskData readLastTaskData(OfflineTaskGroup taskGroup, OfflineTask task) { + if (!checkConnection()) { + return null; + } + OldTaskData taskMonitorData = null; + String clause; + if (taskGroup == null) { + // only query on the task name (not good if there is more than one module with the same tasks) + clause = String.format(" WHERE TRIM(%s)='%s' ORDER BY Id DESC", taskName.getName(), task.getName()); + } + else { + clause = String.format(" WHERE TRIM(%s)='%s' AND TRIM(%s)='%s' AND TRIM(%s)='%s' ORDER BY Id DESC", + moduleType.getName(), task.getUnitType(), + moduleName.getName(), task.getUnitName(), + taskName.getName(), task.getName()); + } + String selStr = tableDef.getSQLSelectString(con.getSqlTypes()) + clause; + try { + Statement selStmt = con.getConnection().createStatement(); + ResultSet results = selStmt.executeQuery(selStr); + if (results.next()) { + for (int i = 0; i < tableDef.getTableItemCount(); i++) { + PamTableItem tableItem = tableDef.getTableItem(i); + tableItem.setValue(results.getObject(i+1)); + } + taskMonitorData = readTableData(); + } + selStmt.close(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return taskMonitorData; + } + + private boolean logStart(OfflineTaskGroup taskGroup, OfflineTask task, TaskMonitorData monitorData) { + fillTableData(taskGroup, task, monitorData); + PamCursor startCursor = startCursorFinder.getCursor(con, startTableDef); + int dbInd = startCursor.immediateInsert(con); + if (dbInd > 0) { + loggingData.put(task, new TaskLoggingData(task, dbInd, monitorData)); + return true; + } + else { + return false; + } + } + + private boolean logUpdate(OfflineTaskGroup taskGroup, OfflineTask task, TaskMonitorData monitorData) { + // TODO Auto-generated method stub + return true; + } + + private boolean logComplete(OfflineTaskGroup taskGroup, OfflineTask task, TaskMonitorData monitorData) { + fillTableData(taskGroup, task, monitorData); + PamCursor startCursor = completeCursorFinder.getCursor(con, completeTableDef); + TaskLoggingData taskLogData = loggingData.get(task); + if (taskLogData == null) { + System.out.println("No logging data to update for offline task " + task.getName()); + return false; + } + completeTableDef.getIndexItem().setValue(taskLogData.databaseIndex); + boolean updateOk = startCursor.immediateUpdate(con); + if (updateOk) { + taskLogData.monitorData = monitorData; + return true; + } + else { + return false; + } + } + +// private class StartLogging extends SQLLogging { +// +// protected StartLogging(TaskLoggingDataBlock pamDataBlock, EmptyTableDefinition startTableDef) { +// super(pamDataBlock); +// setTableDefinition(startTableDef); +// } +// +// @Override +// public void setTableData(SQLTypes sqlTypes, PamDataUnit pamDataUnit) { +// // TODO Auto-generated method stub +// +// } +// +// } + +} diff --git a/src/offlineProcessing/logging/TaskLoggingData.java b/src/offlineProcessing/logging/TaskLoggingData.java new file mode 100644 index 00000000..24d22c40 --- /dev/null +++ b/src/offlineProcessing/logging/TaskLoggingData.java @@ -0,0 +1,26 @@ +package offlineProcessing.logging; + +import PamguardMVC.PamDataUnit; +import offlineProcessing.OfflineTask; +import offlineProcessing.TaskMonitorData; + +/** + * Wee class for holding the latest data on each task, most importantly the + * database index which is needed for updates. + * @author dg50 + * + */ +public class TaskLoggingData extends PamDataUnit { + + protected OfflineTask task; + protected int databaseIndex; + protected TaskMonitorData monitorData; + + public TaskLoggingData(OfflineTask task, int databaseIndex, TaskMonitorData monitorData) { + super(System.currentTimeMillis()); + this.task = task; + this.databaseIndex = databaseIndex; + this.monitorData = monitorData; + } + +} diff --git a/src/offlineProcessing/logging/TaskLoggingDataBlock.java b/src/offlineProcessing/logging/TaskLoggingDataBlock.java new file mode 100644 index 00000000..9740137f --- /dev/null +++ b/src/offlineProcessing/logging/TaskLoggingDataBlock.java @@ -0,0 +1,17 @@ +package offlineProcessing.logging; + +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamProcess; + +/** + * Dummy datablock to use with some dummy SQLLogging classes in TaskLogging. + * @author dg50 + * + */ +public class TaskLoggingDataBlock extends PamDataBlock { + + public TaskLoggingDataBlock() { + super(TaskLoggingData.class, "Logging data", null, 0); + } + +} diff --git a/src/pamViewFX/PamGuiManagerFX.java b/src/pamViewFX/PamGuiManagerFX.java index 59768e90..37512661 100644 --- a/src/pamViewFX/PamGuiManagerFX.java +++ b/src/pamViewFX/PamGuiManagerFX.java @@ -880,8 +880,9 @@ public class PamGuiManagerFX implements PAMControllerGUI, PamSettings { pamController.saveViewerData(); } - // deal with anything that needs sorting out in the realm of UID's. - pamController.getUidManager().runShutDownOps(); +// // deal with anything that needs sorting out in the realm of UID's. + // move this to pamController.pamClose() +// pamController.getUidManager().runShutDownOps(); // if the user doesn't want to save the config file, make sure they know // that they'll lose any changes to the settings diff --git a/src/pamguard/Pamguard.java b/src/pamguard/Pamguard.java index 31ccc8a0..f1f7aaa1 100644 --- a/src/pamguard/Pamguard.java +++ b/src/pamguard/Pamguard.java @@ -23,6 +23,7 @@ package pamguard; import javax.swing.SwingUtilities; import javax.swing.UIManager; +import Acquisition.AcquisitionControl; import Acquisition.FolderInputSystem; import PamController.PamController; import PamController.PamGUIManager; @@ -229,6 +230,14 @@ public class Pamguard { // source folder for wav files (or other supported sound files) GlobalArguments.setParam(FolderInputSystem.GlobalWavFolderArg, args[iArg++]); } + else if (anArg.equalsIgnoreCase(PamController.AUTOSTART)) { + // auto start processing. + GlobalArguments.setParam(PamController.AUTOSTART, PamController.AUTOSTART); + } + else if (anArg.equalsIgnoreCase(PamController.AUTOEXIT)) { + // auto exit at end of processing. + GlobalArguments.setParam(PamController.AUTOEXIT, PamController.AUTOEXIT); + } else if (anArg.equalsIgnoreCase("-help")) { System.out.println("--PamGuard Help"); System.out.println("\n--For standard GUI deployment run without any options.\n"); @@ -329,10 +338,16 @@ public class Pamguard { Thread.setDefaultUncaughtExceptionHandler(new PamExceptionHandler()); System.setProperty("sun.awt.exception.handler", PamExceptionHandler.class.getName()); - //Amongst other stuff the call to PamController.create() - //will build and show the GUI and the user can't - //do much else until that's done so let's have all - //that kicked off from with the EDT CJB 2009-06-16 + /* + * Amongst other stuff the call to PamController.create() + * will build and show the GUI and the user can't + * do much else until that's done so let's have all + * that kicked off from with the EDT CJB 2009-06-16 + * Either of these will call .create, just one is in a different + * thread, so it's at the end of the create function that other automatic + * processes should be started. + * + */ if (PamGUIManager.isSwing()) { SwingUtilities.invokeLater(createPamguard);