Mods to enable getting and setting parameters for individual modules via

xml i/o via udp commands.
This commit is contained in:
Douglas Gillespie 2022-03-15 14:22:48 +00:00
parent c539943680
commit 7ee8bdbe2c
19 changed files with 356 additions and 87 deletions

View File

@ -2262,6 +2262,37 @@ public class PamSettingManager {
return null; return null;
} }
/**
* Find a list of unit settings by type and name. If both are specified, then it's going to
* (hopefully only return one setting. Otherwise, with null or wildcard names we may get many.
* @param unitType unit type, can be wildcard * or null
* @param unitName unit name, can be wildcard * or null
* @return Array list of settings.
*/
public ArrayList<PamSettings> findPamSettings(String unitType, String unitName) {
if (owners == null) {
return null;
}
ArrayList<PamSettings> foundSettings = new ArrayList<>();
if (unitType != null && unitType.equals("*")) {
unitType = null;
}
if (unitName != null && unitName.equals("*")) {
unitName = null;
}
for (PamSettings owner:owners) {
if (unitType != null && !unitType.equals(owner.getUnitType())) {
continue;
}
if (unitName != null && !unitName.equals(owner.getUnitName())) {
continue;
}
foundSettings.add(owner);
}
return foundSettings;
}
/** /**
* Show a dialog to allow the user to select a .psf file path. * Show a dialog to allow the user to select a .psf file path.

View File

@ -1,6 +1,10 @@
package PamController.command; package PamController.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.function.IntFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import PamController.PamControlledUnit; import PamController.PamControlledUnit;
import PamController.PamController; import PamController.PamController;
@ -31,6 +35,8 @@ public abstract class CommandManager extends PamControlledUnit {
commandsList.add(new ExitCommand()); commandsList.add(new ExitCommand());
commandsList.add(new KillCommand()); commandsList.add(new KillCommand());
commandsList.add(new HelpCommand(this)); commandsList.add(new HelpCommand(this));
commandsList.add(new GetXMLSettings());
commandsList.add(new SetXMLSettings());
} }
@ -54,60 +60,67 @@ public abstract class CommandManager extends PamControlledUnit {
* the program (in which case this thread will * the program (in which case this thread will
* exit and close the port). True otherwise. * exit and close the port). True otherwise.
*/ */
public boolean interpretCommand(String command) { public boolean interpretCommand(String commandString) {
//System.out.println(String.format("New UDP Command %s", command)); //System.out.println(String.format("New UDP Command %s", command));
if (commandString == null) {
return false;
}
String[] commandWords = commandString.split(" "); //splitCommandLine(commandString);
if (commandWords == null || commandWords.length < 1) {
return false;
}
String first = commandWords[0].toLowerCase();
command = command.toLowerCase(); String command = commandWords[0].toLowerCase();
// strip of the first two letters if they begin pg ... // strip of the first two letters if they begin pg ...
if (command.substring(0,2).equals("pg")) { if (command.length() > 2 && command.substring(0,2).equals("pg")) {
command = command.substring(2); command = command.substring(2);
} }
ExtCommand extCommand = findCommand(command); ExtCommand extCommand = findCommand(command);
if (extCommand == null) { if (extCommand == null) {
sendData("Cmd \"" + command + "\" Not Recognised."); sendData("Cmd \"" + commandString + "\" Not Recognised.");
return false; return false;
} }
if (extCommand.canExecute() == false) { if (extCommand.canExecute() == false) {
sendData("Cmd \"" + command + "\" Cannot Execute."); sendData("Cmd \"" + command + "\" Cannot Execute.");
sendData(" Cmd return string = " + extCommand.getReturnString()); // sendData(" Cmd return string = " + extCommand.getReturnString());
return false; return false;
} }
extCommand.execute(); String output = extCommand.executeCommand(commandString);
sendData(extCommand.getReturnString()); sendData(output);
//
// if (command.equals("pgstart")) {
// sendData("PgAck " + "pgstart");
// pamController.pamStart();
// }
// else if (command.equals("pgstop")) {
// sendData("PgAck " + "pgstop");
// pamController.pamStop();
// }
// else if (command.equals("pgping")) {
// sendData("PgAck " + "pgping");
// }
// else if (command.equals("pgstatus")) {
// sendData("PgAck Status " + pamController.getPamStatus());
// }
// else if (command.equals("pgsetrec")) {
// sendData("PgAck pgsetrec");
//
// //triggerRecording(String name, int seconds);
// }
// else if (command.equals("pgexit")) {
// sendData("Exiting PAMGUARD");
// System.exit(0);
// return false;
// }
// else{
// sendData("PgAck " + "Cmd Not Recognised.");
// }
return true; return true;
} }
/**
* Slightly nasty split since some module names will be in quotes if they are names with spaces
* so the split needs to a) take out multiple words surrounded by "" and then split what's left
* by word. Or split by work and rejoin anything with "" ?
* @param command
* @return
*/
public static String[] splitCommandLine(String command) {
// https://stackoverflow.com/questions/7804335/split-string-on-spaces-in-java-except-if-between-quotes-i-e-treat-hello-wor
if (command == null) {
return null;
}
Matcher m = Pattern.compile("([^\"]\\S*|\".+?\")\\s*").matcher(command);
List<String> bits = new ArrayList<>();
while (m.find()) {
String bit = m.group(1);
bit = bit.trim();
bit = bit.replace("\"", "");
bits.add(bit);
}
int n = bits.size();
String[] sbits = new String[n];
for (int i = 0; i < bits.size(); i++) {
sbits[i] = (String) bits.get(i);
}
return sbits;
}
/** /**
* Reply to data called from InterpredData * Reply to data called from InterpredData
* @param dataString * @param dataString

View File

@ -15,11 +15,11 @@ public class ExitCommand extends ExtCommand {
} }
@Override @Override
public boolean execute() { public String execute(String command) {
PamController.getInstance().pamStop(); PamController.getInstance().pamStop();
PamSettingManager.getInstance().saveFinalSettings(); PamSettingManager.getInstance().saveFinalSettings();
System.exit(0); System.exit(0);
return true; return getName();
} }
@Override @Override

View File

@ -37,14 +37,14 @@ public abstract class ExtCommand {
* @return true if the command executed OK, or if it was sent off * @return true if the command executed OK, or if it was sent off
* to execute in a later thread. * to execute in a later thread.
*/ */
public final boolean executeCommand() { public final String executeCommand(String commandString) {
if (immediate) { if (immediate) {
return execute(); return execute(commandString);
} }
SwingUtilities.invokeLater(new ExecuteLater()); SwingUtilities.invokeLater(new ExecuteLater(commandString));
return true; return "Command sent";
} }
/** /**
@ -54,28 +54,35 @@ public abstract class ExtCommand {
*/ */
private class ExecuteLater implements Runnable { private class ExecuteLater implements Runnable {
private String command;
public ExecuteLater(String command) {
this.command = command;
}
@Override @Override
public void run() { public void run() {
execute(); execute(command);
} }
} }
/** /**
* Execute the command * Execute the command
* @param commandWords
* @return true if command executed correctly. * @return true if command executed correctly.
*/ */
public abstract boolean execute(); public abstract String execute(String command);
/** // /**
* Get the return string from the command. // * Get the return string from the command.
* <p>By default this is just the command name, but many // * <p>By default this is just the command name, but many
* commands will need to send back extensive information. // * commands will need to send back extensive information.
* @return command output information // * @return command output information
*/ // */
public String getReturnString() { // public String getReturnString() {
return name; // return name;
} // }
/** /**
* @return the name of the command * @return the name of the command

View File

@ -0,0 +1,51 @@
package PamController.command;
import java.util.ArrayList;
import org.w3c.dom.Document;
import PamController.PamControlledUnitSettings;
import PamController.PamSettingManager;
import PamController.PamSettings;
import PamController.settings.output.xml.PamguardXMLWriter;
/**
* Get XML settings from one or more modules. Note that the first two commands are
* the names that are used in PamSettings which are usually the same as module names
* but this gives a little more flexibility.
* @author dg50
*
*/
public class GetXMLSettings extends ExtCommand {
public GetXMLSettings() {
super("getxmlsettings", true);
}
@Override
public String execute(String command) {
String[] commandWords = CommandManager.splitCommandLine(command);
if (commandWords.length < 3) {
return "Unspecified modules for settings";
}
PamSettingManager settingsManager = PamSettingManager.getInstance();
String unitType = commandWords[1];
String unitName = commandWords[2];
ArrayList<PamSettings> foundSettings = settingsManager.findPamSettings(unitType, unitName);
if (foundSettings == null || foundSettings.size() == 0) {
return "No settings";
}
PamguardXMLWriter xmlWriter = PamguardXMLWriter.getXMLWriter();
Document doc = xmlWriter.writeModules(foundSettings);
String txt = xmlWriter.getAsString(doc);
return txt;
}
@Override
public String getHint() {
return "Get XML settings for a named module";
}
}

View File

@ -12,7 +12,7 @@ public class HelpCommand extends ExtCommand {
} }
@Override @Override
public boolean execute() { public String execute(String commandString) {
ArrayList<ExtCommand> commands = commandManager.getCommandsList(); ArrayList<ExtCommand> commands = commandManager.getCommandsList();
String out = "Available commands are:\n"; String out = "Available commands are:\n";
for (ExtCommand command : commands) { for (ExtCommand command : commands) {
@ -26,13 +26,9 @@ public class HelpCommand extends ExtCommand {
} }
} }
commandManager.sendData(out); commandManager.sendData(out);
return true; return getName();
} }
@Override
public String getReturnString() {
return super.getReturnString();
}
@Override @Override
public String getHint() { public String getHint() {

View File

@ -13,9 +13,9 @@ public class KillCommand extends ExtCommand {
} }
@Override @Override
public boolean execute() { public String execute(String command) {
System.exit(0); System.exit(0);
return true; return getName();
} }
@Override @Override

View File

@ -38,7 +38,7 @@ public class NetworkController extends CommandManager {
private boolean initialisationComplete = false; private boolean initialisationComplete = false;
static private final int MAX_COMMAND_LENGTH = 256; static private final int MAX_COMMAND_LENGTH = 4096;
private byte[] byteBuffer = new byte[MAX_COMMAND_LENGTH]; private byte[] byteBuffer = new byte[MAX_COMMAND_LENGTH];
@ -127,6 +127,7 @@ public class NetworkController extends CommandManager {
packet.setPort(udpPacket.getPort()); packet.setPort(udpPacket.getPort());
try { try {
receiveSocket.send(packet); receiveSocket.send(packet);
// receiveSocket.
} catch (IOException e) { } catch (IOException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();

View File

@ -9,8 +9,8 @@ public class PingCommand extends ExtCommand {
} }
@Override @Override
public boolean execute() { public String execute(String command) {
return true; return getName();
} }
@Override @Override

View File

@ -0,0 +1,89 @@
package PamController.command;
import java.io.Serializable;
import java.io.StringReader;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import PamController.PamControlledUnitSettings;
import PamController.PamSettingManager;
import PamController.PamSettings;
import PamController.settings.output.xml.ModuleNode;
import PamController.settings.output.xml.PamguardXMLReader;
public class SetXMLSettings extends ExtCommand {
public SetXMLSettings() {
super("setxmlsettings", true);
// TODO Auto-generated constructor stub
}
@Override
public String execute(String command) {
/*
* Hopefully, we just need to remove the name of the command and trim and we've got perfect xml to play with.
*/
String xmlString = command.substring(getName().length());
xmlString = xmlString.trim();
PamSettingManager settingManager = PamSettingManager.getInstance();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document doc = null;
try {
DocumentBuilder builder = factory.newDocumentBuilder();
doc = builder.parse(new InputSource(new StringReader(xmlString)));
}
catch (Exception e)
{
e.printStackTrace();
return "invalid xml settings can't be pushed to modules";
}
PamguardXMLReader xmlReader = new PamguardXMLReader(doc);
ArrayList<ModuleNode> nodes = xmlReader.getModuleNodes();
for (int i = 0; i < nodes.size(); i++) {
ModuleNode aNode = nodes.get(i);
// now work out the name and type of the module and tell PamSettings to load
// these.
ArrayList<PamSettings> owner = settingManager.findPamSettings(aNode.getUnitType(), aNode.getUnitName());
if (owner == null || owner.size() == 0) {
return "no Java module for xml settings";
}
PamSettings own = owner.get(0);
// System.out.println("XML Node " + aNode.toString());
Object[] objData = xmlReader.unpackModuleNode(aNode);
// System.out.println(objData);
if (objData == null || objData.length == 0) {
return "no Java object(s) for xml settings";
}
for (int iOb = 0; iOb < objData.length; iOb++) {
/*
* Do a test to see if the object is the same type as the current settings.
*/
Object currSettings = own.getSettingsReference();
Object newSettings = objData[iOb];
if (newSettings == null) {
continue;
}
if (currSettings != null && currSettings.getClass() != newSettings.getClass()) {
return "Created java settings object is not the same as currently used: " + currSettings.getClass().getName();
}
PamControlledUnitSettings pcus = new PamControlledUnitSettings(aNode.getUnitType(), aNode.getUnitName(),
aNode.getjClass(), own.getSettingsVersion(), newSettings);
own.restoreSettings(pcus);
}
}
return "xml settings pushed to modules";
}
@Override
public String getHint() {
return "Set XML settings for a named module, (see getxmlsettings to retreive module settings to modify)";
}
}

View File

@ -13,8 +13,9 @@ public class StartCommand extends ExtCommand {
} }
@Override @Override
public boolean execute() { public String execute(String command) {
return PamController.getInstance().pamStart(); boolean ok = PamController.getInstance().pamStart();
return getReturnString();
} }
@Override @Override
@ -30,7 +31,6 @@ public class StartCommand extends ExtCommand {
} }
} }
@Override
public String getReturnString() { public String getReturnString() {
return returnString; return returnString;
} }

View File

@ -18,11 +18,10 @@ public class StatusCommand extends ExtCommand {
} }
@Override @Override
public boolean execute() { public String execute(String command) {
return true; return getReturnString();
} }
@Override
public String getReturnString() { public String getReturnString() {
/* /*
* Need to work out if it's stalled or not by looking at the Daq systems. * Need to work out if it's stalled or not by looking at the Daq systems.

View File

@ -9,9 +9,9 @@ public class StopCommand extends ExtCommand {
} }
@Override @Override
public boolean execute() { public String execute(String command) {
PamController.getInstance().pamStop(); PamController.getInstance().pamStop();
return true; return getName();
} }

View File

@ -20,11 +20,10 @@ public class SummaryCommand extends ExtCommand {
} }
@Override @Override
public boolean execute() { public String execute(String command) {
return true; return getReturnString();
} }
@Override
public String getReturnString() { public String getReturnString() {
PamController pamController = PamController.getInstance(); PamController pamController = PamController.getInstance();
int nMod = pamController.getNumControlledUnits(); int nMod = pamController.getNumControlledUnits();

View File

@ -38,11 +38,15 @@ public class PamguardXMLReader {
unpackFile(fileName); unpackFile(fileName);
} }
public PamguardXMLReader(Document doc) {
NodeList childNodes = doc.getChildNodes();
moduleNodes = new ArrayList<>();
findModuleNodes(childNodes, moduleNodes);
}
private void unpackFile(String fileName) { private void unpackFile(String fileName) {
Document doc = XMLUtils.createDocument(fileName); Document doc = XMLUtils.createDocument(fileName);
String str = XMLUtils.getStringFromDocument(doc);
// System.out.println(str);
NodeList childNodes = doc.getChildNodes(); NodeList childNodes = doc.getChildNodes();
moduleNodes = new ArrayList<>(); moduleNodes = new ArrayList<>();
findModuleNodes(childNodes, moduleNodes); findModuleNodes(childNodes, moduleNodes);
@ -58,16 +62,18 @@ public class PamguardXMLReader {
* Unpack a module node, creating a class and settings * Unpack a module node, creating a class and settings
* it's data. * it's data.
*/ */
private Object unpackModuleNode(ModuleNode moduleNode) { public Object[] unpackModuleNode(ModuleNode moduleNode) {
if (moduleNode == null) { if (moduleNode == null) {
return null; return null;
} }
// first need to find the configuration node, then unpack that. // first need to find the configuration node, then unpack that.
ArrayList<Node> settingsNodes = findNodesByType(moduleNode.getNode(), "SETTINGS", null); ArrayList<Node> settingsNodes = findNodesByType(moduleNode.getNode(), "SETTINGS", null);
for (Node node : settingsNodes) { Object[] settings = new Object[settingsNodes.size()];
unpackSettingsNode(node); for (int i = 0; i < settingsNodes.size(); i++) {
Node node = settingsNodes.get(i);
settings[i] = unpackSettingsNode(node);
} }
return null; return settings;
} }
public Object unpackSettingsNode(Node settingsNode) { public Object unpackSettingsNode(Node settingsNode) {
@ -567,5 +573,12 @@ public class PamguardXMLReader {
return node.getNodeValue(); return node.getNodeValue();
} }
/**
* @return the moduleNodes
*/
public ArrayList<ModuleNode> getModuleNodes() {
return moduleNodes;
}
} }

View File

@ -229,6 +229,26 @@ public class PamguardXMLWriter implements PamSettings {
return true; return true;
} }
public Document writeModules(ArrayList<PamSettings> settings) {
Document doc = createDocument(System.currentTimeMillis());
Element modules = doc.createElement("MODULES");
Element root = doc.createElement("PAMGUARD");
doc.appendChild(root);
root.appendChild(getInfo(doc, System.currentTimeMillis()));
root.appendChild(modules);
Element moduleData;
for (PamSettings aSet:settings) {
PamSettings[] asArray = new PamSettings[1];
asArray[0] = aSet;
moduleData = writeUnitSettings(doc, modules, aSet, asArray);
if (moduleData != null) {
modules.appendChild(moduleData);
}
}
return doc;
}
private Element getInfo(Document doc, long time) { private Element getInfo(Document doc, long time) {
Element info = doc.createElement("INFO"); Element info = doc.createElement("INFO");
info.setAttribute("TIMESTAMP", PamCalendar.formatDateTime(time)); info.setAttribute("TIMESTAMP", PamCalendar.formatDateTime(time));

View File

@ -25,9 +25,10 @@ public class PamParameterDataGetter extends PrivatePamParameterData {
* @param field * @param field
* @param getter * @param getter
*/ */
public PamParameterDataGetter(Object parentObject, Field field, Method getter) { public PamParameterDataGetter(Object parentObject, Field field, Method getter, Method setter) {
super(parentObject, field); super(parentObject, field);
this.getter = getter; this.getter = getter;
this.setter = setter;
} }
/** /**
@ -36,9 +37,10 @@ public class PamParameterDataGetter extends PrivatePamParameterData {
* @param shortName * @param shortName
* @param toolTip * @param toolTip
*/ */
public PamParameterDataGetter(Object parentObject, Field field, Method getter, String shortName, String toolTip) { public PamParameterDataGetter(Object parentObject, Field field, Method getter, Method setter, String shortName, String toolTip) {
super(parentObject, field, shortName, toolTip); super(parentObject, field, shortName, toolTip);
this.getter = getter; this.getter = getter;
this.setter = setter;
} }

View File

@ -10,6 +10,8 @@ import java.util.Collection;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import binaryFileStorage.BinaryStoreSettings;
/** /**
* Description of the parameters within a class. Primarily holds a list * Description of the parameters within a class. Primarily holds a list
* of PamParameterDataInterface objects each describing one field in the * of PamParameterDataInterface objects each describing one field in the
@ -75,6 +77,9 @@ public class PamParameterSet {
if (special != null) { if (special != null) {
return special; return special;
} }
// if (parentObject.getClass() == BinaryStoreSettings.class) {
// System.out.println("binary store");
// }
// System.out.println("Auto generate param set for " + parentObject.toString()); // System.out.println("Auto generate param set for " + parentObject.toString());
ArrayList<Field> allFields = new ArrayList<>(); ArrayList<Field> allFields = new ArrayList<>();
PamParameterSet pps = new PamParameterSet(parentObject); PamParameterSet pps = new PamParameterSet(parentObject);
@ -110,8 +115,9 @@ public class PamParameterSet {
} }
else { else {
Method getter = findPublicGetter(parentObject, field); Method getter = findPublicGetter(parentObject, field);
Method setter = findPublicSetter(parentObject, field);
if (getter != null) { if (getter != null) {
pps.put(new PamParameterDataGetter(parentObject, field, getter)); pps.put(new PamParameterDataGetter(parentObject, field, getter, setter));
} }
else { else {
pps.hiddenFields.add(field); pps.hiddenFields.add(field);
@ -168,6 +174,48 @@ public class PamParameterSet {
return null; return null;
} }
/**
* Find a getter who's got one input parameter and void return and who's name starts with
* set and contains the name if the field.
* @param parentObject2
* @param field
*/
private static Method findPublicSetter(Object parentObject, Field field) {
Method[] methods = parentObject.getClass().getMethods();
if (methods == null) {
return null;
}
String fieldNameLower = field.getName().toLowerCase();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i]; /*
* Check that there are no input parameters.
*/
Class<?>[] params = method.getParameterTypes();
if (params != null && params.length != 1) {
continue;
}
if ((method.getModifiers() & Modifier.PUBLIC) == 0) {
continue;
}
// check for void return type.
// Class<?> returnType = method.getReturnType();
// if (returnType != Void.class) {
// continue;
// }
String name = method.getName();
name = name.toLowerCase();
int fieldInd = name.indexOf(fieldNameLower);
int methodLen = name.length();
int fieldLen = fieldNameLower.length();
if (name.startsWith("set") && fieldInd == 3 && methodLen == fieldLen+3) {
return method;
}
}
return null;
}
public static PamParameterSet checkSpecials(Object parentObject, int excludedModifiers) { public static PamParameterSet checkSpecials(Object parentObject, int excludedModifiers) {
if (parentObject.getClass() == Color.class) { if (parentObject.getClass() == Color.class) {
PamParameterSet pps = new PamParameterSet(parentObject); PamParameterSet pps = new PamParameterSet(parentObject);

View File

@ -679,12 +679,12 @@ public class PamDetectionOverlayGraphics extends PanelOverlayDraw {
/** /**
* Draw on spectrogram changed March 2010 so that the default time unit is * Draw on spectrogram changed March 2010 so that the default time unit is
* milliseconds (Jave time from 1970) rather than samples. This makes it posible * milliseconds (Java time from 1970) rather than samples. This makes it posible
* to work with data colected over multiple files when operating in viewer mode. * to work with data collected over multiple files when operating in viewer mode.
* @param g * @param g
* @param pamDataUnit * @param pamDataUnit
* @param generalProjector * @param generalProjector
* @return updated rectange * @return updated rectangle
*/ */
protected Rectangle drawOnSpectrogram(Graphics g, PamDataUnit pamDataUnit, GeneralProjector generalProjector) { protected Rectangle drawOnSpectrogram(Graphics g, PamDataUnit pamDataUnit, GeneralProjector generalProjector) {
// draw a rectangle with time and frequency bounds of detection. // draw a rectangle with time and frequency bounds of detection.