Skip to content
Snippets Groups Projects
Commit 68e501aa authored by Brutzman, Don's avatar Brutzman, Don
Browse files

move classes from MV3500 examples development into opendis7 java utilities package

parent 86a71f82
No related branches found
No related tags found
No related merge requests found
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package edu.nps.moves.dis7.utilities;
import edu.nps.moves.dis7.enumerations.VariableRecordType;
import edu.nps.moves.dis7.pdus.CommentPdu;
import edu.nps.moves.dis7.pdus.EntityID;
import edu.nps.moves.dis7.pdus.Pdu;
import edu.nps.moves.dis7.utilities.DisThreadedNetworkInterface;
import edu.nps.moves.dis7.utilities.DisTime;
import edu.nps.moves.dis7.utilities.PduFactory;
import edu.nps.moves.dis7.utilities.stream.PduRecorder;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
// import jdk.internal.vm.annotation.IntrinsicCandidate;
/**
* DisChannel integrates multiple utility capabilities to handle most networking and entity-management tasks.
* Provides a simplified interface wrapping DisThreadedNetworkInterface, PduRecorder and SimulationManager
* for programs connecting to OpenDis7 communications.
* TODO future work will confirm that multiple different DisChannel connections can be used simultaneously by a parent program.
* @author brutzman
*/
public class DisChannel
{
private String descriptor = this.getClass().getSimpleName();
/**
* Output prefix to help with logging by identifying this class.
*/
// might have different DisChannel objects created on different channels, so TRACE_PREFIX is non-static
private String TRACE_PREFIX = "[" + descriptor + "] ";
private static String thisHostName = "localhost";
private static final String NETWORK_ADDRESS_DEFAULT = "239.1.2.3";
private static final int NETWORK_PORT_DEFAULT = 3000;
private static final String DEFAULT_PDULOG_OUTPUT_DIRECTORY = "./pduLog";
protected boolean verboseComments = true;
String networkAddress = NETWORK_ADDRESS_DEFAULT;
int networkPort = NETWORK_PORT_DEFAULT;
static DisTime.TimestampStyle timestampStyle = DisTime.TimestampStyle.IEEE_ABSOLUTE;
/** Creates DIS Protocol Data Unit (PDU) classes for simulation entities */
private static PduFactory pduFactory;
// class variables
private DisThreadedNetworkInterface disNetworkInterface;
DisThreadedNetworkInterface.PduListener pduListener;
Pdu receivedPdu;
private PduRecorder pduRecorder;
/* VariableRecordType enumerations have potential use with CommentPdu logs */
/* TODO contrast to EntityType */
public final VariableRecordType descriptionCommentType = VariableRecordType.DESCRIPTION;
public final VariableRecordType narrativeCommentType = VariableRecordType.COMPLETE_EVENT_REPORT;
public final VariableRecordType statusCommentType = VariableRecordType.APPLICATION_STATUS;
public final VariableRecordType currentTimeStepCommentType = VariableRecordType.APPLICATION_TIMESTEP;
/** SimulationManager class handles DIS joining, announcing and leaving tasks.
* It is instantiated here as an object */
SimulationManager simulationManager = new SimulationManager();
/** Base constructor */
public DisChannel()
{
// base constructor is not invoked automatically by other constructors
// https://stackoverflow.com/questions/581873/best-way-to-handle-multiple-constructors-in-java
initialize();
}
/** Constructor with new descriptor
* @param newDescriptor descriptor for this instance */
public DisChannel(String newDescriptor)
{
descriptor = newDescriptor;
initialize();
}
/** Initialize this class */
private void initialize()
{
DisTime.setTimestampStyle(timestampStyle); // DISTime is a singleton shared class
pduFactory = new PduFactory(timestampStyle);
try
{
thisHostName = InetAddress.getLocalHost().getHostName();
printlnTRACE("thisHostName=" + thisHostName);
}
catch (UnknownHostException uhe)
{
printlnTRACE(thisHostName + " is not connected to network: " + uhe.getMessage());
}
}
/** add entity using SimulationManager
* @param newEntity new entity to add for announcement by SimulationManager */
public void addEntity(EntityID newEntity)
{
// TODO send simulation management PDUs
simulationManager.addEntity(newEntity);
}
/** Join DIS channel using SimulationManager */
public void join()
{
// TODO simulation management PDUs for startup, planning to design special class support
// simulationManager.addEntity();
simulationManager.setDescriptor(descriptor);
simulationManager.addHost(getThisHostName());
simulationManager.setDisThreadedNetworkInterface(disNetworkInterface);
simulationManager.simulationJoin();
simulationManager.simulationStart();
// TODO consider boolean response indicating if join was successful
}
/** Leave DIS channel using SimulationManager */
public void leave()
{
// TODO send simulation management PDUs
simulationManager.simulationStop();
simulationManager.simulationLeave();
// TODO consider boolean response indicating if leave was successful
}
/**
* get current networkAddress as a string
* @return the networkAddress
*/
public String getNetworkAddress() {
return networkAddress;
}
/**
* set current networkAddress using a string
* @param newNetworkAddress the networkAddress to set
*/
public final void setNetworkAddress(String newNetworkAddress) {
this.networkAddress = newNetworkAddress;
}
/**
* get current networkPort
* @return the networkPort
*/
public int getNetworkPort() {
return networkPort;
}
/**
* set current networkPort
* @param newNetworkPort the networkPort to set
*/
public final void setNetworkPort(int newNetworkPort) {
this.networkPort = newNetworkPort;
}
/**
* Get timestampStyle used by PduFactory
* @return current timestampStyle
*/
public DisTime.TimestampStyle getTimestampStyle() {
return timestampStyle;
}
/**
* Set timestampStyle used by PduFactory
* @param newTimestampStyle the timestampStyle to set
*/
public void setTimestampStyle(DisTime.TimestampStyle newTimestampStyle) {
timestampStyle = newTimestampStyle;
DisTime.setTimestampStyle(newTimestampStyle);
}
/**
* Initialize network interface, choosing best available network interface
*/
public void setUpNetworkInterface()
{
if (disNetworkInterface != null)
{
printlnTRACE("*** Warning: setUpNetworkInterface() has already created disNetworkInterface, second invocation ignored");
return;
}
disNetworkInterface = new DisThreadedNetworkInterface(getNetworkAddress(), getNetworkPort());
getDisNetworkInterface().setDescriptor(descriptor);
printlnTRACE("Network confirmation:" + " address=" + getDisNetworkInterface().getAddress() + // disNetworkInterface.getMulticastGroup() +
" port=" + getDisNetworkInterface().getPort()); // + disNetworkInterface.getDisPort());
pduListener = new DisThreadedNetworkInterface.PduListener() {
/** Callback handler for listener */
@Override
public void incomingPdu(Pdu newPdu) {
receivedPdu = newPdu;
}
};
getDisNetworkInterface().addListener(pduListener);
String pduLogOutputDirectory = DEFAULT_PDULOG_OUTPUT_DIRECTORY;
printlnTRACE("Beginning pdu save to directory " + pduLogOutputDirectory);
pduRecorder = new PduRecorder(pduLogOutputDirectory, getNetworkAddress(), getNetworkPort()); // assumes save
pduRecorder.setEncodingPduLog(PduRecorder.ENCODING_PLAINTEXT);
pduRecorder.setVerbose(true); // either sending, receiving or both
pduRecorder.start(); // begin running
}
/** All done, release network resources */
public void tearDownNetworkInterface() {
getPduRecorder().stop(); // handles disNetworkInterface.close(), tears down threads and sockets
}
/**
* Send a single Protocol Data Unit (PDU) of any type
* @param pdu the pdu to send
*/
protected void sendSinglePdu(Pdu pdu)
{
if (getDisNetworkInterface() == null)
setUpNetworkInterface(); // ensure connected
try
{
getDisNetworkInterface().send(pdu);
Thread.sleep(100); // TODO consider refactoring the wait logic and moving externally
}
catch (InterruptedException ex)
{
System.err.println(this.getClass().getSimpleName() + " Error sending PDU: " + ex.getLocalizedMessage());
System.exit(1);
}
}
/**
* Send Comment PDU
* @see <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html">Passing Information to a Method or a Constructor</a> Arbitrary Number of Arguments
* @param commentType enumeration value describing purpose of the narrative comment
* @param comments String array of narrative comments
*/
public void sendCommentPdu(VariableRecordType commentType,
// vararg... variable-length set of String comments can optionally follow
String... comments)
{
if ((comments != null) && (comments.length > 0))
{
ArrayList<String> newCommentsList = new ArrayList<>();
for (String comment : comments)
{
if (!comment.isEmpty())
{
newCommentsList.add(comment); // OK found something to send
}
}
if (!newCommentsList.isEmpty())
{
if (getDisNetworkInterface() == null)
setUpNetworkInterface(); // ensure connected
if (commentType == null)
commentType = VariableRecordType.OTHER; // fallback value; TODO consider pushing into pduFactory
// now build the commentPdu from these string inputs, thus constructing a narrative entry
@SuppressWarnings("CollectionsToArray")
CommentPdu commentPdu = getPduFactory().makeCommentPdu(commentType, newCommentsList.toArray(new String[0])); // comments);
sendSinglePdu(commentPdu);
if (isVerboseComments())
{
printlnTRACE("*** [CommentPdu narrative sent: " + commentType.name() + "] " + newCommentsList.toString());
System.out.flush();
}
}
}
}
/**
* test for verboseComments mode
* @return whether verboseComments mode is enabled
*/
public boolean isVerboseComments() {
return verboseComments;
}
/**
* set verboseComments mode
* @param newVerboseComments whether verboseComments mode is enabled
*/
public void setVerboseComments(boolean newVerboseComments) {
this.verboseComments = newVerboseComments;
}
/**
* @return the TRACE_PREFIX
*/
public String getTRACE_PREFIX() {
return TRACE_PREFIX;
}
/**
* @param newTRACE_PREFIX the TRACE_PREFIX to set
*/
public final void setTRACE_PREFIX(String newTRACE_PREFIX) {
if (newTRACE_PREFIX == null)
newTRACE_PREFIX = "";
if (newTRACE_PREFIX.isBlank())
TRACE_PREFIX = "[" + DisThreadedNetworkInterface.class.getSimpleName() + "] ";
else if (newTRACE_PREFIX.contains(this.getClass().getSimpleName()))
TRACE_PREFIX = "[" + newTRACE_PREFIX + "] ";
else TRACE_PREFIX = "[" + this.getClass().getSimpleName() + " " + newTRACE_PREFIX + "] ";
}
/**
* Print message with TRACE_PREFIX prepended
* @param message String to print
*/
public void printTRACE(String message) {
System.out.print(TRACE_PREFIX + message);
}
/**
* Print message with TRACE_PREFIX prepended
* @param message String to print
*/
public void printlnTRACE(String message) {
System.out.println(TRACE_PREFIX + message);
}
/**
* @return the pduFactory, simplifying program imports and configuration
*/
public PduFactory getPduFactory() {
if (pduFactory == null)
pduFactory = new PduFactory(timestampStyle);
return pduFactory;
}
/**
* @return the disNetworkInterface
*/
public DisThreadedNetworkInterface getDisNetworkInterface() {
return disNetworkInterface;
}
/**
* @return the thisHostName
*/
public static String getThisHostName() {
return thisHostName;
}
/**
* @param aThisHostName the thisHostName to set
*/
public static void setThisHostName(String aThisHostName) {
thisHostName = aThisHostName;
}
/**
* @return the pduRecorder
*/
public PduRecorder getPduRecorder() {
return pduRecorder;
}
/**
* 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 for this interface
*/
public void setDescriptor(String newDescriptor) {
// might have different DisChannel objects created on different channels, so descriptor is non-static
if (newDescriptor == null)
newDescriptor = "";
this.descriptor = newDescriptor;
setTRACE_PREFIX(descriptor);
if (disNetworkInterface != null)
disNetworkInterface.setDescriptor(descriptor);
if (simulationManager != null)
simulationManager.setDescriptor(descriptor);
}
}
This diff is collapsed.
ant -f C:\\x-nps-gitlab\\NetworkedGraphicsMV3500\\examples -Dnb.internal.action.name=run.single -Djavac.includes=OpenDis7Examples/SimulationManager.java -Drun.class=OpenDis7Examples.SimulationManager run-single
init:
Deleting: C:\x-nps-gitlab\NetworkedGraphicsMV3500\examples\build\built-jar.properties
deps-jar:
Updating property file: C:\x-nps-gitlab\NetworkedGraphicsMV3500\examples\build\built-jar.properties
Compiling 1 source file to C:\x-nps-gitlab\NetworkedGraphicsMV3500\examples\build\classes
compile-single:
run-single:
*** SimulationManager main() self test started...
[DisThreadedNetworkInterface] using network interface PANGP Virtual Ethernet Adapter
[DisThreadedNetworkInterface main() self test] datagramSocket.joinGroup address=239.1.2.3 port=3000 isConnected()=false createDatagramSocket() complete.
[DisThreadedNetworkInterface main() self test] createThreads() receiveThread.isAlive()=true
[DisThreadedNetworkInterface main() self test] createThreads() sendingThread.isAlive()=true
*** setKillSentinelAndInterrupts() killed=true sendingThread.isInterrupted()=true receiveThread.isInterrupted()=true
[DisThreadedNetworkInterface main() self test] close(): pdus2send.size()=0 baos.size()=0 dos.size()=0
[DisThreadedNetworkInterface main() self test] datagramSocket.leaveGroup address=239.1.2.3 port=3000 isClosed()=true close() complete.
*** killThread() status: sendingThread.isAlive()=false sendingThread.isInterrupted()=true
*** killThread() status: receiveThread.isAlive()=false receiveThread.isInterrupted()=true
*** Thread close status: sendingThread.isAlive()=false receiveThread.isAlive()=false
*** SimulationManager main() self test complete.
BUILD SUCCESSFUL (total time: 2 seconds)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment