From 4b24790648ceaa4281014388c516aab35b6a55f5 Mon Sep 17 00:00:00 2001 From: brutzman <brutzman@nps.edu> Date: Sat, 28 Aug 2021 22:17:08 -0700 Subject: [PATCH] refactor update, match MV3500 example --- .../dis7/utilities/stream/PduRecorder.java | 231 ++++++++++++++---- 1 file changed, 179 insertions(+), 52 deletions(-) diff --git a/src/edu/nps/moves/dis7/utilities/stream/PduRecorder.java b/src/edu/nps/moves/dis7/utilities/stream/PduRecorder.java index 7144e700f6..030d845dfa 100644 --- a/src/edu/nps/moves/dis7/utilities/stream/PduRecorder.java +++ b/src/edu/nps/moves/dis7/utilities/stream/PduRecorder.java @@ -28,12 +28,25 @@ import org.apache.commons.io.FilenameUtils; */ public class PduRecorder implements PduReceiver { + /** Default multicast group address <code>239.1.2.3</code> for send and receive connections. + * @see <a href="https://en.wikipedia.org/wiki/Multicast_address">https://en.wikipedia.org/wiki/Multicast_address</a> */ + public static String DEFAULT_DIS_ADDRESS = DisThreadedNetworkInterface.DEFAULT_DIS_ADDRESS; + + /** Default socket port <code>3000</code>, matches Wireshark DIS capture default + * @see <a href="https://en.wikipedia.org/wiki/Port_(computer_networking)">https://en.wikipedia.org/wiki/Port_(computer_networking)</a> */ + public static int DEFAULT_DIS_PORT = DisThreadedNetworkInterface.DEFAULT_DIS_PORT; + + private String disAddress = DEFAULT_DIS_ADDRESS; + private int disPort = DEFAULT_DIS_PORT; + /** Character sentinel indicating remainder of line is a comment */ public static final String COMMENT_MARKER = "#"; - static String outputDirectoryPath = "./pduLog"; - static String DEFAULT_FILE_PREFIX = "PduCaptureLog"; - static String DISLOG_FILE_EXTENSION = ".dislog"; + static final String OUTPUT_DIRECTORY_DEFAULT = "./pduLog"; + String outputDirectory = OUTPUT_DIRECTORY_DEFAULT; + Path outputDirectoryPath; + static String DEFAULT_FILE_PREFIX = "PduCaptureLog"; + static String DISLOG_FILE_EXTENSION = ".dislog"; static final String START_COMMENT_MARKER = COMMENT_MARKER + " Start, "; static final String FINISH_COMMENT_MARKER = COMMENT_MARKER + " Finish, "; @@ -48,10 +61,13 @@ public class PduRecorder implements PduReceiver static final String ENCODING_CDIS = "ENCODING_CDIS"; // future work based on new SISO standard private static String pduLogEncoding = ENCODING_PLAINTEXT; // TODO use Java enumerations, generalize/share across library + + private String TRACE_PREFIX = ("[pduRecorder " + getDescriptor()).trim() + "] "; + private String descriptor = new String(); private Writer logFileWriter; private File logFile; - private DisThreadedNetworkInterface disThreadedNetIF; + private DisThreadedNetworkInterface disThreadedNetworkInterface; private DisThreadedNetworkInterface.RawPduListener disRawPduListener; private Long startNanoTime = null; @@ -63,58 +79,54 @@ public class PduRecorder implements PduReceiver private boolean running = true; // starts recording by default /** - * Default constructor that uses default values for output directory, multicast address and port. - * + * Default constructor that uses default values for output directory, DIS address and port. + * Each instance must invoke start() to begin operations, pause() to suspend operations, + * resume() to continue operations, and stop() to terminate operations. * @throws IOException if something goes wrong during instantiation */ public PduRecorder() throws IOException { - this(outputDirectoryPath, DisThreadedNetworkInterface.DEFAULT_MULTICAST_ADDRESS, port); + this (OUTPUT_DIRECTORY_DEFAULT, DEFAULT_DIS_ADDRESS, DEFAULT_DIS_PORT); } /** - * Constructor to let the use specify an output directory. Uses default values - * for multicast address and port. + * Constructor to let the use specify an output directory. + * Uses default values for multicast address and port. + * Each instance must invoke start() to begin operations, pause() to suspend operations, + * resume() to continue operations, and stop() to terminate operations. * - * @param directoryPath the directory to write log files to + * @param initialOutputDirectory the directory to write log files to * @throws IOException if something goes wrong during instantiation */ - public PduRecorder(String directoryPath) throws IOException + public PduRecorder(String initialOutputDirectory) throws IOException { - this(directoryPath, DisThreadedNetworkInterface.DEFAULT_MULTICAST_ADDRESS, DisThreadedNetworkInterface.DEFAULT_DIS_PORT); + this(initialOutputDirectory, DEFAULT_DIS_ADDRESS, DEFAULT_DIS_PORT); } - /** Constructor to let the user specify all required parameters + /** Constructor to let the user specify all required parameters. + * Each instance must invoke start() to begin operations, pause() to suspend operations, + * resume() to continue operations, and stop() to terminate operations.. * - * @param outputDirectory local path for directory where the log files are written - * @param multicastAddress multicast group address to receive data from (TODO allow unicast UDP) - * @param port UDP port to listen for data + * @param initialOutputDirectory local path for directory where the log files are written + * @param initialAddress multicast group address to receive data from (TODO allow unicast UDP) + * @param initialPort UDP port to listen for data */ @SuppressWarnings("Convert2Lambda") - public PduRecorder(String outputDirectory, String multicastAddress, int port) + public PduRecorder(String initialOutputDirectory, String initialAddress, int initialPort) { try { - Path outputDirectoryPath = new File(outputDirectory).toPath(); - logFile = createUniquePduLogFile(outputDirectoryPath, DEFAULT_FILE_PREFIX + DISLOG_FILE_EXTENSION ); - logFileWriter = new PrintWriter(new BufferedWriter(new FileWriter(logFile))); + outputDirectoryPath = new File(initialOutputDirectory).toPath(); + this.descriptor = "PduRecorder"; // default + this.disAddress = initialAddress; + this.disPort = initialPort; + logFile = createUniquePduLogFile(outputDirectoryPath, DEFAULT_FILE_PREFIX + DISLOG_FILE_EXTENSION ); + logFileWriter = new PrintWriter(new BufferedWriter(new FileWriter(logFile))); } catch (IOException ex) { - System.err.println("Exception when creating log file in directory=" + outputDirectory + "\n" + + System.err.println("Exception when creating log file in directory=" + initialOutputDirectory + "\n" + " " + ex.getClass().getSimpleName() + ": " + ex.getLocalizedMessage()); } - - disThreadedNetIF = new DisThreadedNetworkInterface(multicastAddress, port); - - disRawPduListener = new DisThreadedNetworkInterface.RawPduListener() { - @Override - public void incomingPdu(DisThreadedNetworkInterface.ByteArrayBufferAndLength bAndL) { - receivePdu(bAndL.bufferByteArray, bAndL.length); - } - }; - - disThreadedNetIF.addRawListener(disRawPduListener); - System.out.println(getClass() + " listening to IP address " + multicastAddress + " on port " + port); } /** @@ -134,23 +146,65 @@ public class PduRecorder implements PduReceiver pduLogEncoding = newPduLogEncoding; } - /** Start or resume this instance */ - public void startResume() + /** Resume instance operation + * @see start() + * @see stop() + * @see pause() */ + public void resume() + { + if (disThreadedNetworkInterface == null) + { + System.out.println("** Warning, PduRecorder resume() failed to find running disThreadedNetworkInterface, repeating start()"); + start(); // start me up + } + else running = true; + } + + /** Start instance operation + * @see stop() + * @see pause() + * @see resume() + */ + public void start() { + if (disThreadedNetworkInterface == null) + { + disThreadedNetworkInterface = new DisThreadedNetworkInterface(getAddress(), getPort()); + disThreadedNetworkInterface.setDescriptor (getDescriptor()); // pass it along + + disRawPduListener = new DisThreadedNetworkInterface.RawPduListener() { + @Override + public void incomingPdu(DisThreadedNetworkInterface.ByteArrayBufferAndLength bAndL) { + receivePdu(bAndL.bufferByteArray, bAndL.length); + } + }; + disThreadedNetworkInterface.addRawListener(disRawPduListener); + System.out.println("[" + (getClass().getSimpleName() + " " + getDescriptor()).trim() + "] listening to IP address " + getAddress() + " on port " + getPort()); + } running = true; } - /** Stop or pause this instance */ - public void stopPause() + /** Pause operation of this instance + * @see start() + * @see stop() + * @see resume() + */ + public void pause() { running = false; } - /** End operation of this instance - * @return recorder logFile */ - public File end() + /** End operation of this instance, removing interfaces + * @return recorder logFile + * @see start() + * @see pause() + * @see resume() */ + public File stop() { running = false; - disThreadedNetIF.removeRawListener(disRawPduListener); - disThreadedNetIF.kill(); + if (disThreadedNetworkInterface != null) + { + disThreadedNetworkInterface.removeRawListener(disRawPduListener); + disThreadedNetworkInterface.finishOperations(); + } writeFooter(); try { @@ -163,8 +217,13 @@ public class PduRecorder implements PduReceiver } return logFile; } + byte[] oldBuffer; + /** receivePdu from DIS data stream + * @param newBuffer byte array for receiving data + * @param newLength length of byte array + */ @Override public void receivePdu(byte[] newBuffer, int newLength) { @@ -233,8 +292,8 @@ public class PduRecorder implements PduReceiver /** * @return an instance of this DisThreadedNetworkInterface */ - public DisThreadedNetworkInterface getDisThreadedNetIF() { - return disThreadedNetIF; + public DisThreadedNetworkInterface getDisThreadedNetworkInterface() { + return disThreadedNetworkInterface; } private void writeHeader() @@ -327,36 +386,104 @@ public class PduRecorder implements PduReceiver */ public static void main(String[] args) { - System.out.println("dis7.utilities.stream.PduRecorder main() performs self-test by sending full set of PDUs via port " + port); - port = 1; // avoid listening to other PDU streams during self test + System.out.println("dis7.utilities.stream.PduRecorder main() performs self-test by sending full set of PDUs"); PduFactory factory = new PduFactory(); //default appid, country, etc. PduRecorder pduRecorder; try { pduRecorder = new PduRecorder(); // default address, port, output directory path + pduRecorder.setDescriptor("PduRecorder main() self test"); +// pduRecorder.setPort(1); // option to avoid listening to other PDU streams during self test + pduRecorder.start(); } catch(IOException ex) { System.err.println("Exception creating recorder: " + ex.getLocalizedMessage()); + System.err.println(ex.getStackTrace()); return; } - System.out.println("dis7.utilities.stream.PduRecorder pduRecorder created... isRunning()=" + pduRecorder.isRunning()); + System.out.println("dis7.utilities.stream.PduRecorder pduRecorder started... isRunning()=" + pduRecorder.isRunning()); DisPduType allPDUTypesArray[] = DisPduType.values(); System.out.println("dis7.utilities.stream.PduRecorder allPDUTypesArray created, length=" + allPDUTypesArray.length + " ..."); - Arrays.stream(allPDUTypesArray).forEach(pduTypeValue-> { - if(pduTypeValue != DisPduType.OTHER) + System.out.flush(); // ensure all output sent + Arrays.stream(allPDUTypesArray).forEach((DisPduType pduTypeValue)-> + { + if (pduTypeValue != DisPduType.OTHER) { try { - pduRecorder.getDisThreadedNetIF().send(factory.createPdu(pduTypeValue)); + pduRecorder.getDisThreadedNetworkInterface().send(factory.createPdu(pduTypeValue)); + Thread.sleep (50L); // let send/receive threads and streams catch up } - catch(Exception ex) { + catch (InterruptedException ex) { System.err.println("Exception sending Pdu: "+ex.getLocalizedMessage()); } } + else + { + System.err.println("Found pduTypeValue=DisPduType.OTHER=" + pduTypeValue); + } }); + System.out.flush(); System.err.flush(); // ensure all output sent - pduRecorder.end(); + pduRecorder.stop(); System.out.println("dis7.utilities.stream.PduRecorder pduRecorder complete... isRunning()=" + pduRecorder.isRunning()); } + /** + * Get current multicast (or unicast) network address for send and receive connections. + * @see <a href="https://en.wikipedia.org/wiki/Multicast_address">https://en.wikipedia.org/wiki/Multicast_address</a> + * @return current multicast address value + */ + public String getAddress() + { + return this.disAddress; + } + /** + * Network address for send and receive connections. + * @see <a href="https://en.wikipedia.org/wiki/Multicast_address">https://en.wikipedia.org/wiki/Multicast_address</a> + * @param newAddress the new network address to set + */ + public void setAddress(String newAddress) { + this.disAddress = newAddress; + if (isRunning()) + System.out.println(TRACE_PREFIX + "*** warning, attempting to change network address while running..."); + // TODO warn if netIF already created + } + /** Get network port used, multicast or unicast. + * @see <a href="https://en.wikipedia.org/wiki/Port_(computer_networking)">https://en.wikipedia.org/wiki/Port_(computer_networking)</a> + * @return current port value + */ + public int getPort() + { + return this.disPort; + } + /** + /** Set network port used, multicast or unicast. + * @see <a href="https://en.wikipedia.org/wiki/Port_(computer_networking)">https://en.wikipedia.org/wiki/Port_(computer_networking)</a> + * @param newPortValue the disPort value to set + */ + public void setPort(int newPortValue) + { + this.disPort = newPortValue; + if (isRunning()) + System.out.println(TRACE_PREFIX + "*** warning, attempting to change network port while running..."); + // TODO warn if netIF already created + } + /** + * Get simple descriptor (such as parent class name) for this network interface, used in trace statements + * @return simple descriptor name + */ + public String getDescriptor() { + return descriptor; + } + + /** + * Set new simple descriptor (such as parent class name) for this network interface, used in trace statements + * @param newDescriptor simple descriptor name + */ + public void setDescriptor(String newDescriptor) + { + this.descriptor = newDescriptor; + TRACE_PREFIX = "[" + (DisThreadedNetworkInterface.class.getSimpleName() + " " + descriptor).trim() + "] "; + } } -- GitLab