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

move classes to opendis7-java library

parent f5f59031
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 OpenDis7Examples;
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);
}
}
/*
Copyright (c) 1995-2022 held by the author(s). All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the names of the Naval Postgraduate School (NPS)
Modeling Virtual Environments and Simulation (MOVES) Institute
https://www.nps.edu and https://www.nps.edu/web/moves
nor the names of its contributors may be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
// TODO move into opendis7 distribution tree
package OpenDis7Examples;
import edu.nps.moves.dis7.pdus.CreateEntityPdu;
import edu.nps.moves.dis7.pdus.EntityID;
import edu.nps.moves.dis7.pdus.RemoveEntityPdu;
import edu.nps.moves.dis7.utilities.DisThreadedNetworkInterface;
import edu.nps.moves.dis7.utilities.DisTime;
import java.util.ArrayList;
/**
* Manage overall Simulation Management (SIMAN) choreography for a DIS channel participant.
* TODO once operation is working satisfactorily, this class will be moved into the opendis7-java distribution utilities.
* @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/specifications/README.md" target="_blank">Networked Graphics MV3500, Specification Documents, IEEE and SISO</a>
* @see <a href="https://ieeexplore.ieee.org/document/6387564" target="_blank">1278.1-2012. IEEE Standard for Distributed Interactive Simulation (DIS) - Application Protocols</a> 5.6.3 The simulation management computer
* @see <a href="https://ieeexplore.ieee.org/document/587529" target="_blank">1278.3-1996. IEEE Recommended Practice for Distributed Interactive Simulation - Exercise Management and Feedback</a>
* @see IEEE 1278.1 DIS Application Protocols, 4.6.3.a.5 Timestamp, General Requirements, page 43
* @see IEEE 1278.1 DIS Application Protocols, 4.6.3.c.1 Timestamp, Relative Timestamps, page 44
* @see IEEE 1278.1 DIS Application Protocols, 5.6 Simulation management, page 89
* @author brutzman
*/
public class SimulationManager
{
private DisThreadedNetworkInterface disThreadedNetworkInterface;
private static ArrayList<RecordType> entityRecordList = new ArrayList<>();
private static ArrayList<RecordType> hostRecordList = new ArrayList<>();
private static ArrayList<RecordType> applicationRecordList = new ArrayList<>();
private String descriptor = new String();
private static int hostID = 0;
private String TRACE_PREFIX = "[" + (SimulationManager.class.getSimpleName()) + "] ";
/**
* Object constructor with descriptor
* @param newDescriptor simple descriptor name for this class
*/
public SimulationManager (String newDescriptor)
{
if (newDescriptor != null)
descriptor = newDescriptor.trim();
else descriptor = "";
}
/**
* Object constructor
*/
public SimulationManager ()
{
this("");
}
/**
* Start the simulation according to specifications
*/
public void simulationStart()
{
// TODO
}
/**
* Pause the simulation according to specifications
*/
public void simulationPause()
{
// TODO
}
/**
* Resume the simulation according to specifications
*/
public void simulationResume()
{
// TODO
}
/**
* Stop the simulation according to specifications
*/
public void simulationStop()
{
// TODO
}
/**
* An entity can Join the simulation according to specifications
*/
public void simulationJoin()
{
CreateEntityPdu createEntityPdu = new CreateEntityPdu();
createEntityPdu.setExerciseID(123); // TODO
// createEntityPdu.setPduStatus(); // TODO
if (hasDisThreadedNetworkInterface())
{
for (RecordType entity : entityRecordList)
{
// TODO set record parameters
createEntityPdu.setExerciseID(entity.getId());
createEntityPdu.setTimestamp(DisTime.getCurrentDisTimestamp());
disThreadedNetworkInterface.send(createEntityPdu);
}
}
else
{
System.err.println(TRACE_PREFIX + "addEntity() unable to send CreateEntityPdu since no disThreadedNetworkInterface found");
// TODO consider queue for unsent entities
}
}
/**
* An entity can Leave the simulation according to specifications
*/
public void simulationLeave()
{
// TODO
}
/**
* Simple simulation record type
*/
public class RecordType
{
private int id = -1;
private String name = new String();
private String alias = new String();
private String description = new String();
private String reference = new String();
private boolean isHostType = false;
/**
* Constructor for new record
* @param id identifying number
* @param name common name
* @param description longer description
* @param reference formal reference for this record, if any
*/
public RecordType (int id, String name, String description, String reference)
{
this.id = id;
this.name = name;
this.description = description;
this.reference = reference;
// TODO create alias: if IP address then check for hostname, and vice versa
}
/**
* Utility constructor for new record, description and reference remain blank
* @param id identifying number
* @param name common name
*/
public RecordType (int id, String name)
{
this.id = id;
this.name = name;
this.description = "";
this.reference = "";
// TODO create alias: if IP address then check for hostname, and vice versa
}
/**
* Utility constructor for new record, description and reference remain blank
* @param id identifying number
* @param name common name
* @param isHostType whether or not this record is for a host
*/
public RecordType (int id, String name, boolean isHostType)
{
this.id = id;
this.name = name;
this.description = "";
this.reference = "";
this.isHostType = isHostType;
// TODO create alias: if IP address then check for hostname, and vice versa
}
/**
* Simple representation of record
* @return id,name,"description"
*/
@Override
public String toString()
{
return "id" + "," + name + ",\"" + description + "\"";
}
/**
* get record id
* @return the id
*/
public int getId() {
return id;
}
/**
* set record id
* @param newID the id to set
* @return same object to permit progressive setters
*/
public RecordType setId(int newID) {
this.id = newID;
return this;
}
/**
* get record name
* @return the name
*/
public String getName() {
return name;
}
/**
* set record name
* @param newName the name to set
* @return same object to permit progressive setters
*/
public RecordType setName(String newName) {
this.name = newName;
return this;
}
/**
* get record description
* @return the description
*/
public String getDescription() {
return description;
}
/**
* set record description
* @param newDescription the description to set
* @return same object to permit progressive setters
*/
public RecordType setDescription(String newDescription) {
this.description = newDescription;
return this;
}
/**
* get record reference
* @return the reference
*/
public String getReference() {
return reference;
}
/**
* set record reference
* @param newReference the reference to set
* @return same object to permit progressive setters
*/
public RecordType setReference(String newReference) {
this.reference = newReference;
return this;
}
/**
* get record alias name
* @return the alias
*/
public String getAlias() {
return alias;
}
/**
* set record alias name
* @param alias the alias to set
* @return same object to permit progressive setters
*/
public RecordType setAlias(String alias) {
this.alias = alias;
return this;
}
/**
* Does record represent a network address
* @return whether record is a network address
*/
public boolean isNetworkAddress() {
return isHostType;
}
/**
* Set whether record represents a network address
* @param isAddress the isAddress to set
*/
public void setNetworkAddress(boolean isAddress) {
this.isHostType = isAddress;
}
}
/**
* Get a single entityRecord from list
* @param index which record to retrieve
* @return the record matching this index
*/
public RecordType getEntityRecordByIndex(int index)
{
if (entityRecordList.isEmpty())
{
System.err.println ("*** getEntityRecordByIndex list is empty, unable to get index=" + index);
return null;
}
else if (entityRecordList.size() <= index)
{
System.err.println ("*** getEntityRecordByIndex list has size=" + entityRecordList.size() + ", unable to get index=" + index);
return null;
}
else if (index < 0)
{
System.err.println ("*** getEntityRecordByIndex cannot retrieve illegal index=" + index);
return null;
}
else return entityRecordList.get(index);
}
/**
* Get a single hostRecord from list
* @param index which record to retrieve
* @return the record matching this index
*/
public RecordType getHostRecordByIndex(int index)
{
if (hostRecordList.isEmpty())
{
System.err.println ("*** getHostRecordByIndex list is empty, unable to get index=" + index);
return null;
}
else if (hostRecordList.size() <= index)
{
System.err.println ("*** getHostRecordByIndex list has size=" + hostRecordList.size() + ", unable to get index=" + index);
return null;
}
else if (index < 0)
{
System.err.println ("*** getHostRecordByIndex cannot retrieve illegal index=" + index);
return null;
}
else return hostRecordList.get(index);
}
/**
* Get a single applicationRecord from list
* @param index which record to retrieve
* @return the record matching this index
*/
public RecordType getApplicationRecordByIndex(int index)
{
if (applicationRecordList.isEmpty())
{
System.err.println ("*** getApplicationRecordByIndex list is empty, unable to get index=" + index);
return null;
}
else if (applicationRecordList.size() <= index)
{
System.err.println ("*** getApplicationRecordByIndex list has size=" + applicationRecordList.size() + ", unable to get index=" + index);
return null;
}
else if (index < 0)
{
System.err.println ("*** getApplicationRecordByIndex cannot retrieve illegal index=" + index);
return null;
}
else return applicationRecordList.get(index);
}
/**
* Get a single entityRecord from list matching ID
* @param valueOfInterest id for record to retrieve
* @return the record matching this ID
*/
public RecordType getEntityRecordByID(int valueOfInterest)
{
for (RecordType entity : entityRecordList)
{
if (entity.getId() == valueOfInterest)
return entity;
}
System.err.println ("*** getEntityRecordByID cannot find id=" + valueOfInterest);
return null;
}
/**
* Get a single hostRecord from list matching ID
* @param valueOfInterest id for record to retrieve
* @return the record matching this ID
*/
public RecordType getHostRecordByID(int valueOfInterest)
{
for (RecordType host : hostRecordList)
{
if (host.getId() == valueOfInterest)
return host;
}
System.err.println ("*** getHostRecordByID cannot find id=" + valueOfInterest);
return null;
}
/**
* Get a single applicationRecord from list matching ID
* @param valueOfInterest id for record to retrieve
* @return the record matching this ID
*/
public RecordType getApplicationRecordByID(int valueOfInterest)
{
for (RecordType application : applicationRecordList)
{
if (application.getId() == valueOfInterest)
return application;
}
System.err.println ("*** getApplicationRecordByID cannot find id=" + valueOfInterest);
return null;
}
/**
* Provide entire entityRecordList
* @return the entityRecordList
*/
public ArrayList<RecordType> getEntityRecordList() {
return entityRecordList;
}
/**
* Provide entire hostRecordList
* @return the hostRecordList
*/
public ArrayList<RecordType> getHostRecordList() {
return hostRecordList;
}
/**
* Provide entire applicationRecordList
* @return the applicationRecordList
*/
public ArrayList<RecordType> getApplicationRecordList() {
return applicationRecordList;
}
/**
* Provide access to current disThreadedNetworkInterface
* @return the disThreadedNetworkInterface
*/
protected DisThreadedNetworkInterface getDisThreadedNetworkInterface() {
return disThreadedNetworkInterface;
}
/**
* Set the disThreadedNetworkInterface singleton to match other classes
* @param disThreadedNetworkInterface the disThreadedNetworkInterface to set
* @return same object to permit progressive setters
*/
public SimulationManager setDisThreadedNetworkInterface(DisThreadedNetworkInterface disThreadedNetworkInterface) {
this.disThreadedNetworkInterface = disThreadedNetworkInterface;
return this;
}
/**
* Check for disThreadedNetworkInterface
* @return whether singleton disThreadedNetworkInterface has been instantiated
*/
protected boolean hasDisThreadedNetworkInterface()
{
return (this.disThreadedNetworkInterface != null);
}
/**
* Create disThreadedNetworkInterface
*/
protected void createDisThreadedNetworkInterface()
{
this.disThreadedNetworkInterface = new DisThreadedNetworkInterface(descriptor);
}
/**
* Constructor for disThreadedNetworkInterface with descriptor,
* using default multicast address and port
* @param newDescriptor simple descriptor name for this interface
*/
protected void createDisThreadedNetworkInterface(String newDescriptor)
{
this.disThreadedNetworkInterface = new DisThreadedNetworkInterface(newDescriptor);
}
/**
* Constructor for disThreadedNetworkInterface using specified multicast address and port
* @param address the multicast group or unicast address to utilize
* @param port the multicast port to utilize
*/
protected void createDisThreadedNetworkInterface(String address, int port)
{
this.disThreadedNetworkInterface = new DisThreadedNetworkInterface(address, port, descriptor);
}
/**
* Constructor for disThreadedNetworkInterface using specified multicast address and port, plus descriptor.
* @param address the multicast group or unicast address to utilize
* @param port the multicast port to utilize
* @param newDescriptor simple descriptor name for this interface
*/
protected void createDisThreadedNetworkInterface(String address, int port, String newDescriptor)
{
this.disThreadedNetworkInterface = new DisThreadedNetworkInterface(address, port, newDescriptor);
}
/**
* Get simple descriptor (such as parent class name) for this SimulationManager, used in trace statements
* @return simple descriptor name
*/
public String getDescriptor()
{
return descriptor;
}
/**
* Set new simple descriptor (such as parent class name) for this SimulationManager, used in trace statements
* @param newDescriptor simple descriptor name for this interface
* @return same object to permit progressive setters */
public SimulationManager setDescriptor(String newDescriptor)
{
if (newDescriptor != null)
this.descriptor = newDescriptor.trim();
TRACE_PREFIX = "[" + DisThreadedNetworkInterface.class.getSimpleName() + " " + descriptor + "] ";
return this;
}
/**
* Reset descriptor
* @return same object to permit progressive setters */
public SimulationManager clearDescriptor()
{
setDescriptor("");
return this;
}
/**
* clear all lists
* @return same object to permit progressive setters */
public SimulationManager clearAll()
{
entityRecordList.clear();
hostRecordList.clear();
applicationRecordList.clear();
clearDescriptor();
return this;
}
/**
* Add entity to simulation list, if this is first occurrence
* @param newEntityID new entity to add
* @return same object to permit progressive setters */
public SimulationManager addEntity(EntityID newEntityID)
{
RecordType newEntity = new RecordType(newEntityID.getEntityID(), // short
"TODOname",
"TODO description",
"TODO reference");
entityRecordList.add(newEntity);
return this;
}
/**
* Add entity to simulation list and announce using CreateEntityPdu
* @param newEntity new entity to add
* @return same object to permit progressive setters */
public SimulationManager addEntity(RecordType newEntity)
{
if (!entityRecordList.contains(newEntity))
{
// TODO check record type
entityRecordList.add(newEntity);
if (hasDisThreadedNetworkInterface())
{
CreateEntityPdu createEntityPdu = new CreateEntityPdu();
// TODO set record parameters
getDisThreadedNetworkInterface().send(createEntityPdu);
}
else
{
System.err.println(TRACE_PREFIX + "addEntity() unable to send CreateEntityPdu since no disThreadedNetworkInterface found");
// TODO consider queue for unsent entities
}
}
return this;
}
/**
* Remove entity from simulation list, if found
* @param oldEntity old entity to remove
* @return same object to permit progressive setters */
public SimulationManager removeEntity(RecordType oldEntity)
{
if (!entityRecordList.contains(oldEntity))
{
// TODO check record type
entityRecordList.remove(oldEntity);
if (hasDisThreadedNetworkInterface())
{
RemoveEntityPdu removeEntityPdu = new RemoveEntityPdu();
// TODO set record parameters
getDisThreadedNetworkInterface().send(removeEntityPdu);
}
else
{
System.err.println(TRACE_PREFIX + "removeEntity() unable to send RemoveEntityPdu since no disThreadedNetworkInterface found");
// TODO consider queue for unsent entities
}
}
return this;
}
/**
* Add host to simulation list, if this is first occurrence
* @param newHost new host to add
* @return same object to permit progressive setters */
public SimulationManager addHost(String newHost)
{
boolean nameFound = false;
boolean aliasFound = false;
for (RecordType nextRecord : hostRecordList)
{
if ( nextRecord.name.equalsIgnoreCase(newHost.trim()))
nameFound = true;
if (nextRecord.alias.equalsIgnoreCase(newHost.trim()))
aliasFound = true;
if ((nameFound || aliasFound) && !nextRecord.isHostType)
nextRecord.isHostType = true; // make sure
}
if (!nameFound && !aliasFound)
{
RecordType newRecord = new RecordType(hostID, newHost, true);
// TODO set alias to IP number
hostRecordList.add(newRecord);
hostID++;
// no PDU sent
}
return this;
}
/**
* Remove host from simulation list, if found
* @param oldHost old host to remove
* @return same object to permit progressive setters */
public SimulationManager removeHost(String oldHost)
{
boolean nameFound = false;
boolean aliasFound = false;
for (RecordType nextRecord : hostRecordList)
{
if ( nextRecord.name.equalsIgnoreCase(oldHost.trim()))
nameFound = true;
if (nextRecord.alias.equalsIgnoreCase(oldHost.trim()))
aliasFound = true;
if ((nameFound || aliasFound) && !nextRecord.isHostType)
nextRecord.isHostType = true; // make sure
if (nameFound || aliasFound)
{
hostRecordList.remove(nextRecord);
// no PDU sent
break;
}
}
return this;
}
/** Self test to check basic operation, invoked by main() */
public void selfTest()
{
createDisThreadedNetworkInterface();
// TODO
disThreadedNetworkInterface.close(); // tears down threads and sockets
}
/**
* Main method for testing.
* @see <a href="https://docs.oracle.com/javase/tutorial/getStarted/application/index.html">Java Tutorials: A Closer Look at the "Hello World!" Application</a>
* @param args [address, port, descriptor] command-line arguments are an array of optional String parameters that are passed from execution environment during invocation
*/
public static void main(String[] args)
{
System.out.println("*** SimulationManager main() self test started...");
SimulationManager simulationManager = new SimulationManager("main() self test");
simulationManager.setDescriptor("main() self test");
simulationManager.selfTest();
System.out.println("*** SimulationManager main() self test complete.");
}
}
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