Skip to content
Snippets Groups Projects
Commit 1ad5a2ff authored by jojot's avatar jojot
Browse files

Homework2 Tam

parent 1b9ea499
No related branches found
No related tags found
No related merge requests found
/**
* Copyright (c) 2008-2022, MOVES Institute, Naval Postgraduate School (NPS). All rights reserved.
* This work is provided under a BSD open-source license, see project license.html and license.txt
* @author brutzman@nps.edu
*/
package MV3500Cohort2022MayJune.homework2.Tam;
import edu.nps.moves.dis7.entities.swe.platform.surface._001Poseidon;
import edu.nps.moves.dis7.entities.swe.platform.surface._002Triton;
import edu.nps.moves.dis7.enumerations.*;
import edu.nps.moves.dis7.pdus.*;
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.SimulationManager;
import edu.nps.moves.dis7.utilities.stream.PduRecorder;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
/** The purpose of this inheritable class is to provide an easily modifiable example simulation program
* that includes DIS-capable entities performing tasks of interest, and then reporting activity via PDUs
* to the network.
* Default program initialization includes PDU recording turned on by default.
* @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramLog.txt">ExampleSimulationProgramLog.txt</a>
*/
public class ExampleSimulationProgramTam
{
private boolean verboseComments = true;
static final String NETWORK_ADDRESS_DEFAULT = "239.1.2.3";
static final int NETWORK_PORT_DEFAULT = 3000;
String networkAddress = NETWORK_ADDRESS_DEFAULT;
int networkPort = NETWORK_PORT_DEFAULT;
String thisHostName = "localhost";
String DEFAULT_OUTPUT_DIRECTORY = "./pduLog";
/** seconds for real-time execution (not simulation time, which may or may not be the same) */
double currentTimeStep = 2.0; // seconds
/** initial simulation time */
double initialTime = 0.0;
/** current simulation time */
double simulationTime;
/**
* Output prefix to help with logging by identifying this class (can be overridden in subclass).
*/
protected static String TRACE_PREFIX;
/* Declare DIS Protocol Data Unit (PDU) classes for simulation entities */
DisTime.TimestampStyle timestampStyle = DisTime.TimestampStyle.IEEE_ABSOLUTE;
PduFactory pduFactory = new PduFactory(timestampStyle);
/** EntityID settings for entity 1 */
protected EntityID entityID_1 = new EntityID();
/** EntityID settings for entity 2 */
protected EntityID entityID_2 = new EntityID();
/** ESPDU for entity 1 */
protected EntityStatePdu entityStatePdu_1 = pduFactory.makeEntityStatePdu();
/** ESPDU for entity 2 */
protected EntityStatePdu entityStatePdu_2 = pduFactory.makeEntityStatePdu();
/** FirePdu for entity 1 first weapon (if any) */
protected FirePdu firePdu_1a = pduFactory.makeFirePdu();
/** FirePdu for entity 1 second weapon (if any) */
protected FirePdu firePdu_1b = pduFactory.makeFirePdu();
/** MunitionDescriptor for these weapons */
protected MunitionDescriptor munitionDescriptor1 = new MunitionDescriptor();
/** this class instantiated as an object */
SimulationManager simulationManager = new SimulationManager();
/** Get ready, get set... initialize simulation entities
*/
public void initializeSimulationEntities()
{
// Your model setup: define participants. who's who in this zoo?
// Assuming you keep track of entity objects... here is some support for for Entity 1.
// PDU objects are already created, now set their values.
entityID_1.setSiteID(1).setApplicationID(2).setEntityID(3); // made-up example ID;
entityID_2.setSiteID(1).setApplicationID(2).setEntityID(4); // made-up example ID;
// TODO someday, use enumerations; is there a unique site triplet for MOVES Institute?
entityStatePdu_1.setEntityID(entityID_1);
entityStatePdu_1.setForceId(ForceID.FRIENDLY);
entityStatePdu_1.setEntityType(new _001Poseidon()); // note import statement above
entityStatePdu_1.setMarking("Entity #1");
entityStatePdu_1.getMarkingString(); // check
entityStatePdu_2.setEntityID(entityID_2);
entityStatePdu_2.setForceId(ForceID.OPPOSING);
entityStatePdu_2.setEntityType(new _002Triton()); // note import statement above
entityStatePdu_2.setMarking("Entity #2");
// TODO how should we customize this munition? what is it for your simulation?
munitionDescriptor1.setQuantity(1);
firePdu_1a.setDescriptor(munitionDescriptor1).setRange(1000.0f);
// TODO simulation management PDUs for startup, planning to design special class support
// simulationManager.addEntity();
simulationManager.setDescriptor("ExampleSimulationProgram");
simulationManager.addHost(thisHostName);
simulationManager.setDisThreadedNetworkInterface(disNetworkInterface);
}
/**
* This runSimulationLoops() method is for you, a customizable programmer-modifiable
* code block for defining and running a new simulation of interest.
*
* Welcome! Other parts of this program handle bookkeeping and plumbing tasks so that
* you can focus on your model entities and activities.
* Expandable support includes DIS EntityStatePdu, FirePdu and CommentPdu all available for
* modification and sending in a simulation loop.
* Continuous improvement efforts seek to make this program as easy and straightforward
* as possible for DIS simulationists to use and adapt.
* All of the other methods are setup, teardown and configuration that you may find
* interesting, even helpful, but don't really have to worry about.
*/
@SuppressWarnings("SleepWhileInLoop") // yes we do that
public void runSimulationLoops ()
{
try
{
final int SIMULATION_MAX_LOOP_COUNT = 10; // be deliberate out there! also avoid infinite loops.
int simulationLoopCount = 0; // variable, initialized at 0
boolean simulationComplete = false; // sentinel variable as termination condition, are we done yet?
// TODO reset Clock Time to today's date and timestamp to zero, providing consistent outputs for each simulation run
pduRecorder.setVerbose(true);
initializeSimulationEntities();
simulationManager.simulationJoin();
simulationManager.simulationStart();
// ===================================================================================================
// loop the simulation while allowed, programmer can set additional conditions to break out and finish
while (simulationLoopCount < SIMULATION_MAX_LOOP_COUNT) // are we done yet?
{
simulationLoopCount++; // good practice: increment loop counter as first action in that loop
// =============================================================================================
// * your own simulation code starts here! *
// =============================================================================================
// are there any other variables to modify at the beginning of your loop?
// compute a track, update an ESPDU, whatever it is that your model is doing...
// Where is my entity? Insert changes in position; this sample only changes X position.
entityStatePdu_1.getEntityLocation().setX(entityStatePdu_1.getEntityLocation().getX() + 1.0); // 1m per timestep
// decide whether to fire, and then update the firePdu. Hmmm, you might want a target to shoot at!
// etc. etc. your code goes here for your simulation of interest
// something happens between my simulation entities, la de da de da...
System.out.println ("... My simulation just did something, no really...");
System.out.flush();
// make your reports: narrative code for CommentPdu here (set all to empty strings to avoid sending)
narrativeMessage1 = "MV3500 ExampleSimulationProgram";
narrativeMessage2 = "runSimulation() loop " + simulationLoopCount;
narrativeMessage3 = ""; // intentionally blank for testing
// your loop termination condition goes here
if (simulationLoopCount > 4) // for example
{
simulationComplete = true;
}
// =============================================================================================
// * your own simulation code is finished here! *
// =============================================================================================
// staying synchronized with timestep: wait duration for elapsed time in this loop
// Thread.sleep needs a (long) parameter for milliseconds, which are clumsy to use sometimes
Thread.sleep((long)(currentTimeStep * 1000)); // seconds * (1000 msec/sec) = milliseconds
System.out.println ("... [Pausing for " + currentTimeStep + " seconds]");
// OK now send the status PDUs for this loop, and then continue
System.out.println ("sending PDUs for simulation step " + simulationLoopCount + ", monitor loopback to confirm sent");
System.out.flush();
sendAllPdusForLoopTimestep(entityStatePdu_1, firePdu_1a, currentTimeStepComment, narrativeMessage1, narrativeMessage2, narrativeMessage3);
sendSinglePdu(entityStatePdu_2); // me too i.e. 2!
System.out.println ("... [PDUs successfully sent for this loop]");
System.out.flush();
// ===============================
// current loop now finished, check whether to terminate if simulation complete, otherwise continue
if (simulationComplete || (simulationLoopCount > 10000)) // for example; including fail-safe condition is good
{
System.out.println ("... [loop termination condition met, simulationComplete=" + simulationComplete + "]"); // ", final loopCount=" + loopCount +
System.out.flush();
break;
}
} // end of simulation loop
// ===================================================================================================
narrativeMessage2 = "runSimulation() completed successfully"; // all done
sendCommentPdu(narrativeComment, narrativeMessage1, narrativeMessage2, narrativeMessage3);
System.out.println ("... [final CommentPdu successfully sent for simulation]");
// TODO simulation management PDUs
simulationManager.simulationStop();
simulationManager.simulationLeave();
}
catch (InterruptedException iex) // handle any exception that your code might choose to provoke!
{
Logger.getLogger(ExampleSimulationProgramTam.class.getName()).log(Level.SEVERE, null, iex);
}
}
/* **************************** infrastructure code, modification is seldom needed ************************* */
String narrativeMessage1 = new String();
String narrativeMessage2 = new String();
String narrativeMessage3 = new String();
/* VariableRecordType enumerations have potential use with CommentPdu logs */
/* TODO contrast to EntityType */
VariableRecordType descriptionComment = VariableRecordType.DESCRIPTION;
VariableRecordType narrativeComment = VariableRecordType.COMPLETE_EVENT_REPORT;
VariableRecordType statusComment = VariableRecordType.APPLICATION_STATUS;
VariableRecordType currentTimeStepComment = VariableRecordType.APPLICATION_TIMESTEP;
VariableRecordType otherComment = VariableRecordType.OTHER;
// class variables
DisThreadedNetworkInterface disNetworkInterface;
DisThreadedNetworkInterface.PduListener pduListener;
Pdu receivedPdu;
PduRecorder pduRecorder;
/**
* Constructor design goal: additional built-in initialization conveniences can go here
* to keep student efforts focused on the runSimulation() method.
*/
public ExampleSimulationProgramTam()
{
DisTime.setTimestampStyle(timestampStyle);
try
{
thisHostName = InetAddress.getLocalHost().getHostName();
System.out.println(TRACE_PREFIX + "thisHostName=" + thisHostName);
}
catch (UnknownHostException uhe)
{
System.out.println(TRACE_PREFIX + thisHostName + "not connected to network: " + uhe.getMessage());
}
}
/**
* Utility Constructor that allows your example simulation program to override default network address and port
* @param address network address to use
* @param port corresponding network port to use
*/
public ExampleSimulationProgramTam(String address, int port)
{
super();
setNetworkAddress(address);
setNetworkPort(port);
}
/**
* 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
* @return same object to permit progressive setters
*/
public ExampleSimulationProgramTam setTimestampStyle(DisTime.TimestampStyle newTimestampStyle)
{
timestampStyle = newTimestampStyle;
DisTime.setTimestampStyle(newTimestampStyle);
return this;
}
/**
* Initialize network interface, choosing best available network interface
*/
public void setUpNetworkInterface()
{
disNetworkInterface = new DisThreadedNetworkInterface(getNetworkAddress(), getNetworkPort());
disNetworkInterface.setDescriptor ("ExampleSimulationProgram pdu looping");
System.out.println("Network confirmation:" +
" address=" + disNetworkInterface.getAddress()+ // disNetworkInterface.getMulticastGroup() +
" port=" + disNetworkInterface.getPort()); // + disNetworkInterface.getDisPort());
pduListener = new DisThreadedNetworkInterface.PduListener()
{
/** Callback handler for listener */
@Override
public void incomingPdu(Pdu newPdu)
{
receivedPdu = newPdu;
}
};
disNetworkInterface.addListener(pduListener);
String outputDirectory = DEFAULT_OUTPUT_DIRECTORY;
System.out.println("Beginning pdu save to directory " + outputDirectory);
pduRecorder = new PduRecorder(outputDirectory, 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()
{
pduRecorder.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)
{
try
{
disNetworkInterface.send(pdu);
Thread.sleep(100); // TODO consider refactoring the wait logic and moving externally
}
catch (InterruptedException ex)
{
System.err.println(this.getClass().getName() + " 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)
{
sendAllPdusForLoopTimestep (null, null, commentType, comments);
}
/**
* Send EntityState, Fire, Comment PDUs that got updated for this loop, reflecting state of current simulation timestep.
* @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 entityStatePdu the ESPDU to send, if any
* @param firePdu the FirePDU to send, if any
* @param commentType enumeration value describing purpose of the narrative comment
* @param comments String array of narrative comments
*/
public void sendAllPdusForLoopTimestep(EntityStatePdu entityStatePdu,
FirePdu firePdu,
VariableRecordType commentType,
// vararg... variable-length set of String comments can optionally follow
String... comments)
{
if (entityStatePdu != null)
sendSinglePdu(entityStatePdu);
if (firePdu != null)
sendSinglePdu(firePdu); // bang
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 (commentType == null)
commentType = otherComment; // fallback value otherComment
// now build the commentPdu from these string inputs, thus constructing a narrative entry
CommentPdu commentPdu = pduFactory.makeCommentPdu(commentType, newCommentsList.toArray(new String[0])); // comments);
sendSinglePdu(commentPdu);
if (isVerboseComments())
{
System.out.println("*** [Narrative comment 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;
}
/**
* Initial execution via main() method: handle args array of command-line initialization (CLI) arguments here
* @param args command-line parameters: network address and port
*/
protected void handleArgs (String[] args)
{
// initial execution: handle args array of initialization arguments here
if (args.length == 2)
{
if ((args[0] != null) && !args[0].isEmpty())
thisProgram.setNetworkAddress(args[0]);
if ((args[1] != null) && !args[1].isEmpty())
thisProgram.setNetworkPort(Integer.parseInt(args[1]));
}
else if (args.length != 0)
{
System.err.println("Usage: " + thisProgram.getClass().getSimpleName() + " [address port]");
System.exit(-1);
}
}
/** Locally instantiable copy of program, can be subclassed. */
protected static ExampleSimulationProgramTam thisProgram;
/**
* Main method is first executed when a program instance is loaded.
* @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 command-line parameters: network address and port.
* Command-line arguments are an array of optional String parameters that are passed from execution environment during invocation
*/
public static void main(String[] args)
{
TRACE_PREFIX = "[" + ExampleSimulationProgramTam.class.getName() + "] ";
System.out.println(TRACE_PREFIX + "main() started...");
thisProgram = new ExampleSimulationProgramTam(); // creates instance of self within static main() method
thisProgram.handleArgs (args); // process command-line invocation arguments
thisProgram.setUpNetworkInterface();
// thisProgram.pduRecorder.setDescriptor (TRACE_PREFIX.replace("[","").replace("]","") + " pduRecorder");
thisProgram.runSimulationLoops(); // ... your simulation execution code goes in there ...
thisProgram.tearDownNetworkInterface(); // make sure no processes are left lingering
System.out.println(TRACE_PREFIX + "complete."); // report successful completion
System.exit(0); // ensure all threads and sockets released
}
}
/**
* Copyright (c) 2008-2022, MOVES Institute, Naval Postgraduate School (NPS). All rights reserved.
* This work is provided under a BSD open-source license, see project license.html and license.txt
*
* @author brutzman@nps.edu
*/
package MV3500Cohort2022MayJune.homework2.Tam;
import static MV3500Cohort2022MayJune.homework2.Tam.ExampleSimulationProgramTam.TRACE_PREFIX;
import static MV3500Cohort2022MayJune.homework2.Tam.ExampleSimulationProgramTam.thisProgram;
import edu.nps.moves.dis7.entities.swe.platform.surface._001Poseidon;
import edu.nps.moves.dis7.enumerations.ForceID;
import edu.nps.moves.dis7.pdus.EntityStatePdu;
import edu.nps.moves.dis7.pdus.Pdu;
import edu.nps.moves.dis7.pdus.Vector3Double;
import edu.nps.moves.dis7.utilities.DisTime;
import edu.nps.moves.dis7.utilities.stream.X3dCreateInterpolators;
import edu.nps.moves.dis7.utilities.stream.X3dCreateLineSet;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* The purpose of this program is to provide an easily modifiable example
* simulation for networked entity tracks and presentation, including
* DIS-capable entities doing tasks and reporting them to the network.
* Default settings include PDU recording turned on by default.
* @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleTrackInterpolationLog.txt">ExampleTrackInterpolationLog.txt</a>
* @see <a href="https://calhoun.nps.edu/handle/10945/65436">REPEATABLE UNIT TESTING OF DISTRIBUTED INTERACTIVE SIMULATION (DIS) PROTOCOL BEHAVIOR STREAMS USING WEB STANDARDS</a> by Tobias Brennenstuhl, Masters Thesis, Naval Postgraduate School (NPS), June 2020
* @see <a href="https://gitlab.nps.edu/Savage/SavageTheses/-/tree/master/BrennenstuhlTobias">https://gitlab.nps.edu/Savage/SavageTheses/-/tree/master/BrennenstuhlTobias</a>
*/
public class ExampleTrackInterpolationTam extends ExampleSimulationProgramTam
{
// -------------------- Begin Variables for X3D autogenerated code
private X3dCreateInterpolators x3dInterpolators = new X3dCreateInterpolators();
private X3dCreateLineSet x3dLineSet = new X3dCreateLineSet();
private byte[] globalByteBufferForX3dInterpolators = null;
// -------------------- End Variables for X3D autogenerated code
ArrayList<Pdu> pduSentList = new ArrayList<>();
/**
* This runSimulationLoops() method is a programmer-modifiable method for
* defining and running a new simulation of interest. Welcome! Other parts
* of this program handle bookkeeping and plumbing tasks so that you can
* focus on your model entities and activities. Expandable support includes
* DIS EntityStatePdu, FirePdu and CommentPdu all available for modification
* and sending in a simulation loop. Continuous improvement efforts seek to
* make this program as easy and straightforward as possible for DIS
* simulationists to use and adapt. All of the other methods are setup,
* teardown and configuration that you may find interesting, even helpful,
* but don't really have to worry about.
*/
@SuppressWarnings("SleepWhileInLoop") // yes we do that
@Override // indicates that this method supercedes corresponding superclass method
public void runSimulationLoops()
{
try
{
final int SIMULATION_MAX_LOOP_COUNT = 50; // be deliberate out there! also avoid infinite loops.
int simulationLoopCount = 0; // variable, initialized at 0
boolean simulationComplete = false; // sentinel variable as termination condition, are we done yet?
// TODO reset Clock Time to today's date and timestamp to zero, providing consistent outputs for each simulation run
DisTime.setEpochLvcNow();
simulationTime = initialTime - currentTimeStep; // pre-initialization for first loop
initializeSimulationEntities();
// use declared PDU objects and set their values.
entityID_1.setSiteID(1).setApplicationID(2).setEntityID(3); // made-up example ID;
// TODO someday, use enumerations; is there a unique site triplet for MOVES Institute?
pduRecorder.setVerbose(false);
pduRecorder.hasVerboseOutput(); // debug check
EntityStatePdu espdu_1 = pduFactory.makeEntityStatePdu();
espdu_1.setEntityID(entityID_1);
espdu_1.setForceId(ForceID.FRIENDLY);
espdu_1.setEntityType(new _001Poseidon()); // note import statement above
espdu_1.setMarking("track path");
// espdu_1.clearMarking(); // test
// espdu_1.getMarkingString(); // trace
// espdu_1.setEntityLocation(new Vector3Double().setX(0).setY(0).setZ(0)); // long form
espdu_1.setEntityLocation(0, 0, 0); // utility method
float speedEntity_1 = 1.0f; // meters/second
EntityStatePdu.Direction directionEntity_1 = EntityStatePdu.Direction.NORTH;
PduTrack pduTrack_1 = new PduTrack();
pduTrack_1.setDescriptor("testing 123");
pduTrack_1.setDefaultWaypointInterval(1.0f); // overrides timestamps
pduTrack_1.setAddLineBreaksWithinKeyValues(true);
pduTrack_1.setAuthor("Don Brutzman");
pduTrack_1.setX3dModelName("ExampleTrackInterpolation.x3d");
pduTrack_1.setX3dModelIdentifier("https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleTrackInterpolation.x3d");
pduTrack_1.addPdu(espdu_1); // initial location
// OK send initial PDUs prior to loop
if (pduRecorder.hasVerboseOutput())
System.out.println("sending PDUs for simulation step " + simulationLoopCount + ", monitor loopback to confirm sent");
sendSinglePdu(espdu_1);
// sendCommentPdu(currentTimeStepComment, narrativeMessage1, narrativeMessage2, narrativeMessage3);
pduSentList.add(espdu_1);
reportPdu(simulationLoopCount, espdu_1.getEntityLocation(), directionEntity_1);
// TODO simulation management PDUs for startup, planning to design special class support
// ===================================================================================================
// loop the simulation while allowed, programmer can set additional conditions to break out and finish
while (simulationLoopCount < SIMULATION_MAX_LOOP_COUNT) // are we done yet?
{
simulationLoopCount++; // good practice: increment loop counter as first action in that loop
simulationTime += currentTimeStep; // good practice: update clock along with loop index
// =============================================================================================
// * your own simulation code starts here! *
// =============================================================================================
// are there any other variables to modify at the beginning of your loop?
// compute a track, update an ESPDU, whatever it is that your model is doing...
// Pick direction, change each 10 seconds, traverse a box. No physics. Walk a box!
if (simulationLoopCount <= 10)
directionEntity_1 = EntityStatePdu.Direction.NORTH;
else if (simulationLoopCount <= 20)
directionEntity_1 = EntityStatePdu.Direction.EAST;
else if (simulationLoopCount <= 30)
directionEntity_1 = EntityStatePdu.Direction.SOUTH;
else // if (simulationLoopCount <= 40)
directionEntity_1 = EntityStatePdu.Direction.WEST;
// use utility method to simply update velocity vector using speed value and direction
espdu_1.setEntityLinearVelocity(speedEntity_1, directionEntity_1);
// Where is my entity? Insert changes in position; this sample only changes X position.
espdu_1.advanceEntityLocation(currentTimeStep);
// make your reports: narrative code for CommentPdu here (set all to empty strings to avoid sending)
narrativeMessage1 = "MV3500 TrackSimulationProgram";
narrativeMessage2 = "runSimulation() loop " + simulationLoopCount + " at time " + simulationTime;
narrativeMessage3 = ""; // intentionally blank for testing
// your loop termination condition goes here
if (simulationLoopCount > 40) // for example
{
simulationComplete = true;
}
// =============================================================================================
// * your own simulation code is finished here! *
// =============================================================================================
// staying synchronized with timestep: wait duration for elapsed time in this loop
// Thread.sleep needs a (long) parameter for milliseconds, which are clumsy to use sometimes
if (false) // real-time operation or simulation speedup
{
Thread.sleep((long) (currentTimeStep * 1000)); // seconds * (1000 msec/sec) = milliseconds
System.out.println(TRACE_PREFIX + "Pausing for " + currentTimeStep + " seconds");
}
// OK now send the status PDUs for this loop, and then continue
if (pduRecorder.hasVerboseOutput())
System.out.println("sending PDUs for simulation step " + simulationLoopCount + ", monitor loopback to confirm sent");
sendSinglePdu(espdu_1);
sendCommentPdu(currentTimeStepComment, narrativeMessage1, narrativeMessage2, narrativeMessage3);
if (pduRecorder.hasVerboseOutput())
System.out.println(TRACE_PREFIX + "PDUs successfully sent for this loop");
pduSentList.add(espdu_1);
pduTrack_1.addPdu(espdu_1);
Vector3Double location = espdu_1.getEntityLocation();
reportPdu(simulationLoopCount, location, directionEntity_1);
// ===============================
// current loop now finished, check whether to terminate if simulation complete, otherwise continue
if (simulationComplete || (simulationLoopCount > 10000)) // for example; including fail-safe condition is good
{
System.out.println(TRACE_PREFIX + "loop termination condition met, simulationComplete=" + simulationComplete); // ", final loopCount=" + loopCount +
break;
}
} // end of simulation loop
// ===================================================================================================
System.out.println(TRACE_PREFIX + "all PDUs successfully sent for this loop (pduSentList.size()=" + pduSentList.size() + " total)");
// track analysis
System.out.println(TRACE_PREFIX + "pduTrack_1 initialLocation=" + pduTrack_1.getInitialLocation() + ", latestLocation=" + pduTrack_1.getLatestLocation());
pduTrack_1.sortPdus()
.createRawWaypoints();
System.out.println("pduTrack_1 getEspduCount()=" + pduTrack_1.getEspduCount());
System.out.println("pduTrack_1 duration = " + pduTrack_1.getTotalDurationSeconds() + " seconds = " +
pduTrack_1.getTotalDurationTicks() + " ticks");
System.out.println("=================================");
System.out.println(pduTrack_1.createX3dModel());
System.out.println("=================================");
narrativeMessage2 = "runSimulation() completed successfully"; // all done
sendCommentPdu(narrativeComment, narrativeMessage1, narrativeMessage2, narrativeMessage3);
if (pduRecorder.hasVerboseOutput())
System.out.println(TRACE_PREFIX + "final CommentPdu successfully sent for simulation");
// TODO simulation management PDUs
}
catch (InterruptedException iex) // handle any exception that your code might choose to provoke!
{
Logger.getLogger(ExampleTrackInterpolationTam.class.getName()).log(Level.SEVERE, null, iex);
}
}
/**
* Report current PDU information to console
* @param simulationLoopCount current loop index
* @param location current location
* @param directionEntity current direction
* @return same object to permit progressive setters
*/
public ExampleTrackInterpolationTam reportPdu(int simulationLoopCount, Vector3Double location, EntityStatePdu.Direction directionEntity)
{
System.out.println (String.format("%2d ", simulationLoopCount) + "Entity location=(" +
String.format("%4.1f", location.getX()) + ", " +
String.format("%4.1f", location.getY()) + ", " +
String.format("%4.1f", location.getZ()) + ") " +
String.format("%-5s", directionEntity.name())
// + " " + espdu_1.getEntityLinearVelocity().toString()
);
return this;
}
/* Default constructors used unless otherwise defined/overridden. */
/**
* Main method is first executed when a program instance is loaded.
*
* @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 command-line arguments are an array of optional String
* parameters that are passed from execution environment during invocation
*/
public static void main(String[] args)
{
TRACE_PREFIX = "[" + ExampleTrackInterpolationTam.class.getName() + "] ";
System.out.println(TRACE_PREFIX + "main() started...");
thisProgram = new ExampleTrackInterpolationTam(); // creates instance of self within static main() method
thisProgram.handleArgs (args); // process command-line invocation arguments
thisProgram.setUpNetworkInterface();
thisProgram.pduRecorder.setDescriptor (TRACE_PREFIX.replace("[","").replace("]","") + " pduRecorder");
thisProgram.pduRecorder.setVerbose(false);
thisProgram.setVerboseComments(false);
thisProgram.disNetworkInterface.setVerbose(false);
thisProgram.runSimulationLoops(); // ... your simulation execution code goes in there ...
thisProgram.tearDownNetworkInterface(); // make sure no processes are left lingering
System.out.println(TRACE_PREFIX + "complete."); // report successful completion
System.exit(0); // ensure all threads and sockets released
}
}
/*
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 in package edu.nps.moves.dis7.utilities.stream;
package MV3500Cohort2022MayJune.homework2.Tam;
import MV3500Cohort2022MayJune.homework2.Duran.*;
import edu.nps.moves.dis7.entities.swe.platform.surface._001Poseidon;
import edu.nps.moves.dis7.enumerations.DisPduType;
import edu.nps.moves.dis7.enumerations.ForceID;
import edu.nps.moves.dis7.pdus.EntityID;
import edu.nps.moves.dis7.pdus.EntityStatePdu;
import edu.nps.moves.dis7.pdus.EulerAngles;
import edu.nps.moves.dis7.pdus.Pdu;
import edu.nps.moves.dis7.pdus.Vector3Double;
import edu.nps.moves.dis7.utilities.DisTime;
import edu.nps.moves.dis7.utilities.PduFactory;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* Create a track from DIS ESPDUs
* @author brutzman
*/
public class PduTrack
{
private String descriptor = new String();
private ArrayList<Pdu> pduList = new ArrayList<>();
private EntityStatePdu initialEspdu;
private EntityStatePdu latestEspdu;
private Vector3Double initialLocation;
private Vector3Double latestLocation;
/** waypoint timelineList in seconds */
private ArrayList<Float> timelineList = new ArrayList<>();
private ArrayList<Vector3Double> waypointsList = new ArrayList<>();
private ArrayList<EulerAngles> eulerAnglesList = new ArrayList<>();
private String author = new String();
private String x3dModelIdentifier = new String();
private String x3dModelName = "PduTrackInterpolation.x3d";
private float defaultWaypointInterval = -1;
private float durationSeconds = -1;
private String x3dTimeSensorDEF = new String();
private String x3dPositionInterpolatorDEF = new String();
private String x3dOrientationInterpolatorDEF = new String();
private boolean addLineBreaksWithinKeyValues = false;
/** what kind of timestamp is being used */
public DisTime.TimestampStyle timestampStyle = DisTime.TimestampStyle.IEEE_ABSOLUTE;
/** direct access to pduFactory for creating new PDU instances */
protected PduFactory pduFactory = new PduFactory(timestampStyle);
private LocalDateTime recordingStart;
private LocalDateTime recordingStop;
private String todaysDateString = new String();
/** direct access to byteArrayOutputStream */
protected ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
/** direct access to DataOutputStream */
protected DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
private String TRACE_PREFIX = "[" + (PduTrack.class.getSimpleName()) + "] ";
/**
* Constructor for PduTrack
*/
public PduTrack()
{
// initialization code here
// https://docs.oracle.com/javase/tutorial/datetime/TOC.html
// https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/package-summary.html
// https://stackoverflow.com/questions/5175728/how-to-get-the-current-date-time-in-java/5175900 (scroll down to java.time)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMMM yyyy");
todaysDateString = LocalDate.now().format(formatter);
// System.out.println(TRACE_PREFIX + "today=" + todayString);
}
/**
* Set timestampStyle used by PduFactory
* @param newTimestampStyle new value to set
*/
public PduTrack(DisTime.TimestampStyle newTimestampStyle)
{
timestampStyle = newTimestampStyle;
DisTime.setTimestampStyle(newTimestampStyle);
// automatic super invocation: return PduTrack();
}
/**
* 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 PduTrack setDescriptor(String newDescriptor)
{
if (newDescriptor != null)
this.descriptor = newDescriptor.trim();
TRACE_PREFIX = "[" + (PduTrack.class.getSimpleName() + " " + descriptor) + "] ";
return this;
}
/**
* 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
* @return same object to permit progressive setters
*/
public PduTrack setTimestampStyle(DisTime.TimestampStyle newTimestampStyle)
{
this.timestampStyle = newTimestampStyle;
DisTime.setTimestampStyle(newTimestampStyle);
return this;
}
/**
* Determine initial location, reset to (0 0 0) if not found
* @return current initialLocation
*/
public Vector3Double getInitialLocation() {
if (initialLocation == null)
{
System.out.println (TRACE_PREFIX + "getInitialLocation() not found, isTrackEmpty()=" + isTrackEmpty() + ", returning 0 0 0");
return new Vector3Double();
}
return initialLocation;
}
/**
* Determine current location, reset to (0 0 0) if not found
* @return current latestLocation
*/
public Vector3Double getLatestLocation() {
if (latestLocation == null)
{
System.out.println (TRACE_PREFIX + "getLatestLocation() not found, isTrackEmpty()=" + isTrackEmpty() + ", returning 0 0 0");
return new Vector3Double();
}
return latestLocation;
}
/**
* Get individual Pdu from pduList, index must not exceed existing pduList size
* @param index for pdu of interest
* @return pdu of interest
*/
public Pdu getPdu(int index) throws IndexOutOfBoundsException
{
if ((index >= pduList.size()) || (index < 0))
{
System.out.println (TRACE_PREFIX + "getPdu(" + index + ") out of bounds, pduList.size()=" + pduList.size());
// then throw exception
}
return pduList.get(index);
}
/**
* get current pduList
* @return current pduList
*/
public ArrayList<Pdu> getPduList() {
return pduList;
}
/**
* get current waypointsList
* @return current waypointsList
*/
public ArrayList<Vector3Double> getWaypointsList() {
return waypointsList;
}
/**
* current eulerAnglesList
* @return current eulerAnglesList
*/
public ArrayList<EulerAngles> getEulerAnglesList() {
return eulerAnglesList;
}
/**
* Time in seconds corresponding to each PDU
* @return current timelineList
*/
public ArrayList<Float> getTimelineList() {
return timelineList;
}
/**
* Add PDU, typically ESPDU
* @param newPdu new Pdu to add, typically ESPDU
* @return same object to permit progressive setters
*/
public PduTrack addPdu(Pdu newPdu)
{
if (newPdu.getPduType() == DisPduType.ENTITY_STATE)
{
//// EntityStatePdu deepCopyEspdu = new EntityStatePdu();
// EntityStatePdu deepCopyEspdu = pduFactory.makeEntityStatePdu();
// deepCopyEspdu.setTimestamp (((EntityStatePdu)newPdu).getTimestamp());
// deepCopyEspdu.setMarking (((EntityStatePdu)newPdu).getMarking());
// deepCopyEspdu.setEntityID (((EntityStatePdu)newPdu).getEntityID());
// deepCopyEspdu.setForceId (((EntityStatePdu)newPdu).getForceId());
// deepCopyEspdu.setEntityType (((EntityStatePdu)newPdu).getEntityType());
// deepCopyEspdu.setEntityLocation (((EntityStatePdu)newPdu).getEntityLocation());
// deepCopyEspdu.setEntityOrientation(((EntityStatePdu)newPdu).getEntityOrientation());
EntityStatePdu deepCopyEspdu = ((EntityStatePdu)newPdu).copy();
pduList.add(deepCopyEspdu);
// alternative trials:
// pduList.add(((EntityStatePdu)newPdu).copyDataOutputStream());
// pduList.add(((EntityStatePdu)newPdu).copy());
if (initialLocation == null)
{
initialEspdu = deepCopyEspdu; // must save object since pduList might contain more than ESPDUs
initialLocation = deepCopyEspdu.getEntityLocation();
}
latestEspdu = deepCopyEspdu; // must save object since pduList might contain more than ESPDUs
latestLocation = deepCopyEspdu.getEntityLocation();
}
else pduList.add(newPdu); // TODO copy() - careful, must be a new object and not a reference
return this;
}
/**
* clear all PDUs
* @return same object to permit progressive setters
*/
public PduTrack clearPduLists()
{
getPduList().clear();
waypointsList.clear();
eulerAnglesList.clear();
timelineList.clear();
initialEspdu = null;
latestEspdu = null;
initialLocation = null;
latestLocation = null;
return this;
}
private String normalizeNameToken(String candidateDEF)
{
return candidateDEF.replace(" ", "").replace("-", "")
.replace("(", "").replace(")", "")
.replace("[", "").replace("])", "");
}
/**
* Provide DEF value if not defined by program
* @return current x3dTimeSensorDEF
*/
public String getX3dTimeSensorDEF() {
if (x3dTimeSensorDEF.isEmpty())
x3dTimeSensorDEF = normalizeNameToken(getDescriptor()) + "Clock";
return x3dTimeSensorDEF;
}
/**
* Set DEF value for X3D node
* @param x3dTimeSensorDEF the x3dTimeSensorDEF to set
*/
public void setX3dTimeSensorDEF(String x3dTimeSensorDEF) {
this.x3dTimeSensorDEF = normalizeNameToken(x3dTimeSensorDEF);
}
/**
* Provide DEF value if not defined by program
* @return current x3dPositionInterpolatorDEF
*/
public String getX3dPositionInterpolatorDEF() {
if (x3dPositionInterpolatorDEF.isEmpty())
x3dPositionInterpolatorDEF = normalizeNameToken(getDescriptor()) + "Positions";
return x3dPositionInterpolatorDEF;
}
/**
* Set DEF value for X3D node
* @param x3dPositionInterpolatorDEF the x3dPositionInterpolatorDEF to set
*/
public void setX3dPositionInterpolatorDEF(String x3dPositionInterpolatorDEF) {
this.x3dPositionInterpolatorDEF = normalizeNameToken(x3dPositionInterpolatorDEF);
}
/**
* Provide DEF value if not defined by program
* @return current x3dOrientationInterpolatorDEF
*/
public String getX3dOrientationInterpolatorDEF() {
if (x3dOrientationInterpolatorDEF.isEmpty())
x3dOrientationInterpolatorDEF = normalizeNameToken(getDescriptor()) + "Orientations";
return x3dOrientationInterpolatorDEF;
}
/**
* Set DEF value for X3D node
* @param x3dOrientationInterpolatorDEF the x3dOrientationInterpolatorDEF to set
*/
public void setX3dOrientationInterpolatorDEF(String x3dOrientationInterpolatorDEF) {
this.x3dOrientationInterpolatorDEF = normalizeNameToken(x3dOrientationInterpolatorDEF);
}
/**
* Sort all PDUs by timestamp
* @see <a href="https://stackoverflow.com/questions/16252269/how-to-sort-an-arraylist">StackOverflow: How to sort an ArrayList?</a>
* @see <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/doc-files/coll-overview.html">Collections Framework Overview</a>
* @return same object to permit progressive setters
*/
public PduTrack sortPdus()
{
Collections.sort(pduList, new Comparator<Pdu>() {
@Override
public int compare(Pdu lhs, Pdu rhs)
{
// -1 less than, 1 greater than, 0 equal
if (lhs.occursBefore(rhs))
return -1;
else if (lhs.occursSameTime(rhs))
return 0;
else return 1;
}
});
return this;
}
/**
* Reverse order of PDU list
* @see <a href="https://stackoverflow.com/questions/10766492/what-is-the-simplest-way-to-reverse-an-arraylist">StackOverflow: What is the Simplest Way to Reverse an ArrayList?</a>
* @see <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/doc-files/coll-overview.html">Collections Framework Overview</a>
* @return same object to permit progressive setters
*/
public PduTrack reversePdus()
{
Collections.reverse(pduList);
return this;
}
/**
* Determine whether any ESPDUs have been received by this track
* @return whether track is empty
*/
public boolean isTrackEmpty()
{
return (getEspduCount() == 0);
}
/**
* Count ESPDUs in pduList
* @return number of ESPDUs in pduList
*/
public int getEspduCount()
{
int counter = 0;
for (Pdu nextPdu : getPduList())
{
if (nextPdu.getPduType() == DisPduType.ENTITY_STATE)
counter += 1;
}
return counter;
}
/**
* Compute track duration in timestamp ticks
* @return duration in timestamp ticks between initial and final ESPDU timestamps in waypointList
*/
public int getTotalDurationTicks()
{
int initialTime = -1;
int finalTime = -1;
int durationTicks = -1; // used if pduList is empty
// must skip through pduList since non-ESPDU PDUs may be present
for (Pdu nextPdu : getPduList())
{
if (nextPdu.getPduType() == DisPduType.ENTITY_STATE)
{
if (initialTime == -1)
initialTime = nextPdu.getTimestamp();
finalTime = nextPdu.getTimestamp();
}
}
if ((initialTime >= 0) && (finalTime >= 0))
durationTicks = (finalTime - initialTime);
if (getPduList().isEmpty())
{
System.out.println(TRACE_PREFIX + "getTrackDuration() computed illegal duration=" + durationTicks + " due to empty pdu list");
}
else if ((durationTicks <= 0) && (defaultWaypointInterval <= 0))
{
System.out.println(TRACE_PREFIX + "getTrackDuration() computed illegal duration=" + durationTicks + " due to illegal pdu list");
}
return durationTicks;
}
/**
* Compute track duration in seconds
* @return duration in seconds between initial and final ESPDU timestamps in waypointList
*/
public float getTotalDurationSeconds()
{
if (defaultWaypointInterval > 0)
{
return getEspduCount() * defaultWaypointInterval;
}
else if (getTotalDurationTicks() < 0)
durationSeconds = getTotalDurationTicks() * 1.0f; // TODO convert
return durationSeconds;
}
/**
* Create waypoints and angles using all ESPDU points, with no linear regression or array reduction.
* @return same object to permit progressive setters
*/
public PduTrack createRawWaypoints()
{
// https://stackoverflow.com/questions/6536094/java-arraylist-copy
timelineList.clear();
waypointsList.clear();
eulerAnglesList.clear();
float clock = 0.0f;
for (int i = 0; i < pduList.size(); i++)
{
Pdu nextPdu = pduList.get(i);
if (nextPdu.getPduType() == DisPduType.ENTITY_STATE)
{
EntityStatePdu espdu = (EntityStatePdu)nextPdu;
if (defaultWaypointInterval > 0)
{
timelineList.add(clock);
clock += defaultWaypointInterval;
}
else
{
timelineList.add(espdu.getTimestamp() * 1.0f); // TODO convert
}
waypointsList.add(espdu.getEntityLocation());
eulerAnglesList.add(espdu.getEntityOrientation());
}
}
return this;
}
/**
* Utility method to create TimeSensor
* @return TimeSensor string in XML format
*/
public String createX3dTimeSensorString()
{
StringBuilder sb = new StringBuilder();
sb.append(" <TimeSensor");
sb.append(" DEF='").append(getX3dTimeSensorDEF()).append("'");
sb.append(" cycleInterval='").append(String.valueOf(getTotalDurationSeconds())).append("'");
sb.append(" loop='true'");
sb.append("/>").append("\n");
return sb.toString();
}
/**
* Create PositionInterpolator from Pdu list
* @return X3D PositionInterpolator as string
*/
public String createX3dPositionInterpolatorString()
{
StringBuilder sb = new StringBuilder();
sb.append(" <PositionInterpolator");
sb.append(" DEF='").append(getX3dPositionInterpolatorDEF()).append("'");
sb.append(" key='");
for (int i = 0; i < timelineList.size(); i++)
{
float nextDuration = timelineList.get(i) * 1.0f; // TODO convert
sb.append(String.valueOf(nextDuration));
if (i < timelineList.size() - 1)
sb.append(" ");
}
sb.append("'");
sb.append(" keyValue='");
for (int i = 0; i < waypointsList.size(); i++)
{
if (hasAddLineBreaksWithinKeyValues())
sb.append("\n");
Vector3Double nextPosition = waypointsList.get(i);
sb.append(String.valueOf(nextPosition.getX())).append(" ")
.append(String.valueOf(nextPosition.getY())).append(" ")
.append(String.valueOf(nextPosition.getZ()));
if (i < waypointsList.size() - 1)
sb.append(",");
}
sb.append("'");
sb.append("/>").append("\n");
return sb.toString();
}
/**
* Create OrientationInterpolator from Pdu list
* TODO preliminary support only includes horizontal rotation.
* @return X3D OrientationInterpolator as string
*/
public String createX3dOrientationInterpolatorString()
{
StringBuilder sb = new StringBuilder();
sb.append(" <OrientationInterpolator");
sb.append(" DEF='").append(getX3dOrientationInterpolatorDEF()).append("'");
sb.append(" key='");
for (int i = 0; i < timelineList.size(); i++)
{
float nextDuration = timelineList.get(i) * 1.0f; // TODO convert
sb.append(String.valueOf(nextDuration));
if (i < timelineList.size() - 1)
sb.append(" ");
}
sb.append("'");
sb.append(" keyValue='");
for (int i = 0; i < eulerAnglesList.size(); i++)
{
if (hasAddLineBreaksWithinKeyValues())
sb.append("\n");
EulerAngles nextEulerAngle = new EulerAngles();
float axisX = 0.0f;
float axisY = 1.0f;
float axisZ = 0.0f;
float angle = 0.0f; // radians
nextEulerAngle = eulerAnglesList.get(i);
angle = nextEulerAngle.getTheta();
sb.append(String.valueOf(axisX)).append(" ")
.append(String.valueOf(axisY)).append(" ")
.append(String.valueOf(axisZ)).append(" ")
.append(String.valueOf(angle));
if (i < eulerAnglesList.size() - 1)
sb.append(",");
}
sb.append("'");
sb.append("/>").append("\n");
return sb.toString();
}
/**
* Get name of author used as creator of X3D model
* @return current author
*/
public String getAuthor() {
return author;
}
/**
* Set name of author used as creator of X3D model
* @param author the author to set
*/
public void setAuthor(String author) {
if (author == null)
author = new String();
author = author.trim();
this.author = author;
}
/**
* Get name of online url identifier for X3D model
* @return current x3dModelIdentifier
*/
public String getX3dModelIdentifier() {
return x3dModelIdentifier;
}
/**
* Set name of online url identifier for X3D model
* @param x3dModelIdentifier the x3dModelIdentifier to set
*/
public void setX3dModelIdentifier(String x3dModelIdentifier) {
if (x3dModelIdentifier == null)
x3dModelIdentifier = new String();
x3dModelIdentifier = x3dModelIdentifier.trim();
if (!x3dModelIdentifier.startsWith("http://") && !x3dModelIdentifier.startsWith("https://"))
System.out.println(TRACE_PREFIX + "warning, identifier typically begins with https:// or http://");
else this.x3dModelIdentifier = x3dModelIdentifier;
}
/**
* File name for X3D model production
* @return current x3dModelName
*/
public String getX3dModelName() {
return x3dModelName;
}
/**
* File name for X3D model production
* @param x3dModelName the x3dModelName to set
*/
public void setX3dModelName(String x3dModelName) {
if (x3dModelName == null)
x3dModelName = new String();
x3dModelName = x3dModelName.trim();
this.x3dModelName = x3dModelName;
}
/**
* Verbose (but more readable) output of numeric arrays in X3D model
* @return current addLineBreaksWithinKeyValues
*/
public boolean hasAddLineBreaksWithinKeyValues() {
return addLineBreaksWithinKeyValues;
}
/**
* Verbose (but more readable) output of numeric arrays in X3D model
* @param addLineBreaksWithinKeyValues the addLineBreaksWithinKeyValues to set
*/
public void setAddLineBreaksWithinKeyValues(boolean addLineBreaksWithinKeyValues) {
this.addLineBreaksWithinKeyValues = addLineBreaksWithinKeyValues;
}
/**
* Create full X3D interpolator model from Pdu list, assembling sections of scene graph
* @return X3D model as string
*/
public String createX3dModel()
{
StringBuilder sb = new StringBuilder();
sb.append(createX3dModelHeaderString());
sb.append(createX3dTimeSensorString());
sb.append(createX3dPositionInterpolatorString());
sb.append(createX3dOrientationInterpolatorString());
sb.append(createX3dRoutesGeometryFooterString());
return sb.toString();
}
/**
* Create PositionInterpolator from Pdu list
* @return X3D PositionInterpolator as string
*/
public String createX3dModelHeaderString()
{
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>").append("\n");
sb.append("<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 4.0//EN\" \"https://www.web3d.org/specifications/x3d-4.0.dtd\">").append("\n");
sb.append("<X3D profile='Interchange' version='4.0' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='https://www.web3d.org/specifications/x3d-4.0.xsd'>").append("\n");
sb.append(" <head>").append("\n");
if (!getX3dModelName().isEmpty())
sb.append(" <meta content='").append(getX3dModelName()).append("' name='title'/>").append("\n");
sb.append(" <meta content='Conversion of ESPDU track into X3D animation interpolators and LineSet.' name='description'/>").append("\n");
sb.append(" <meta content='1 January 2022' name='created'/>").append("\n");
sb.append(" <meta content='").append(todaysDateString).append("' name='modified'/>").append("\n");
if (!getAuthor().isEmpty())
sb.append(" <meta content='").append(getAuthor()).append("' name='creator'/>").append("\n");
if (!getX3dModelIdentifier().isEmpty())
sb.append(" <meta content='").append(getX3dModelIdentifier()).append("' name='identifier'/>").append("\n");
sb.append(" <meta content='PduTrack utility, opendis7-java Library https://github.com/open-dis/opendis7-java' name='generator'/>").append("\n");
sb.append(" <meta content='NPS MOVES MV3500 Networked Graphics https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500' name='reference'/>").append("\n");
sb.append(" <meta content='X3D Resources https://www.web3d.org/x3d/content/examples/X3dResources.html' name='reference'/>").append("\n");
sb.append(" <meta content='X3D Scene Authoring Hints https://www.web3d.org/x3d/content/examples/X3dSceneAuthoringHints.html' name='reference'/>").append("\n");
sb.append(" <meta content='X3D Tooltips https://www.web3d.org/x3d/tooltips/X3dTooltips.html' name='reference'/>").append("\n");
sb.append(" <meta content='X3D Validator https://savage.nps.edu/X3dValidator' name='reference'/>").append("\n");
sb.append(" <meta content='Open source https://raw.githubusercontent.com/open-dis/opendis7-java/master/license.html' name='license'/>").append("\n");
sb.append(" </head>").append("\n");
sb.append(" <Scene>").append("\n");
sb.append(" <WorldInfo title='PduTrackInterpolation.x3d'/>").append("\n");
return sb.toString();
}
/**
* Create X3D ROUTEs and footer to connect TimeSensor to interpolators
* @return X3D PositionInterpolator as string
*/
public String createX3dRoutesGeometryFooterString()
{
StringBuilder sb = new StringBuilder();
sb.append(" <ROUTE fromField='fraction_changed' fromNode='")
.append(getX3dTimeSensorDEF())
.append("' toField='set_fraction' toNode='")
.append(getX3dPositionInterpolatorDEF())
.append("'/>").append("\n");
sb.append(" <ROUTE fromField='fraction_changed' fromNode='")
.append(getX3dTimeSensorDEF())
.append("' toField='set_fraction' toNode='")
.append(getX3dOrientationInterpolatorDEF())
.append("'/>").append("\n");
sb.append(" <Shape>").append("\n");
sb.append(" <Appearance DEF='TrackAppearance'>").append("\n");
sb.append(" <Material emissiveColor='0.2 0.8 0.8'/>").append("\n");
sb.append(" </Appearance>").append("\n");
sb.append(" <LineSet vertexCount='").append(waypointsList.size()).append("'>").append("\n");
sb.append(" <Coordinate point='");
for (int i = 0; i < waypointsList.size(); i++)
{
if (hasAddLineBreaksWithinKeyValues())
sb.append("\n");
Vector3Double nextPosition = waypointsList.get(i);
sb.append(String.valueOf(nextPosition.getX())).append(" ")
.append(String.valueOf(nextPosition.getY())).append(" ")
.append(String.valueOf(nextPosition.getZ()));
if (i < waypointsList.size() - 1)
sb.append(",");
}
sb.append("'/>").append("\n");
sb.append(" </LineSet>").append("\n");
sb.append(" </Shape>").append("\n");
sb.append(" <Transform DEF='AnimationTransform'>").append("\n");
sb.append(" <Transform rotation='0 0 1 1.57'>").append("\n");
sb.append(" <Shape>").append("\n");
sb.append(" <Appearance USE='TrackAppearance'/>").append("\n");
sb.append(" <Cone bottomRadius='0.5'/>").append("\n");
sb.append(" </Shape>").append("\n");
sb.append(" </Transform>").append("\n");
sb.append(" </Transform>").append("\n");
sb.append(" <ROUTE fromField='value_changed' fromNode='")
.append(getX3dPositionInterpolatorDEF())
.append("' toField='translation' toNode='AnimationTransform'/>").append("\n");
sb.append(" <ROUTE fromField='value_changed' fromNode='")
.append(getX3dOrientationInterpolatorDEF())
.append("' toField='rotation' toNode='AnimationTransform'/>").append("\n");
sb.append(" </Scene>").append("\n");
sb.append("</X3D>").append("\n");
return sb.toString();
}
/**
* get defaultWaypointInterval
* @return current wayPointInterval
*/
public float getDefaultWaypointInterval() {
return defaultWaypointInterval;
}
/**
* Set uniform waypoint interval (currently for testing)
* @param newWaypointInterval the wayPointInterval to set, in seconds, must be greater than zero
* @return same object to permit progressive setters */
public PduTrack setDefaultWaypointInterval(float newWaypointInterval) {
if (newWaypointInterval > 0.0)
this.defaultWaypointInterval = newWaypointInterval;
else
{
System.out.println(TRACE_PREFIX + "error in setWaypointInterval(newWaypointInterval=" + newWaypointInterval + ") must be greater than zero");
return this;
}
float clock = 0.0f;
if (!timelineList.isEmpty())
{
ArrayList<Float> newTimelineList = new ArrayList<>();
for (int i = 0; i < getEspduCount(); i++)
{
newTimelineList.add(clock);
clock += defaultWaypointInterval;
}
timelineList = newTimelineList; // TO Array copy?
}
return this;
}
/** whether or not to insert commas between hex values */
private boolean insertCommas = true;
/**
* determine whether comma insertion is turned on
* @return whether or not to insert commas between hex values
*/
public boolean hasInsertCommas() {
return insertCommas;
}
/**
* set whether comma insertion is turned on
* @param insertCommas the insertCommas value to set
*/
public void setInsertCommas(boolean insertCommas) {
this.insertCommas = insertCommas;
}
/**
* Convert byte array to hex string
* @param bytes input data
* @param insertCommas whether to insert commas between hex values
* @return hex string
*/
public String bytesToHex(byte[] bytes, boolean insertCommas)
{
this.setInsertCommas(insertCommas);
return bytesToHex(bytes);
}
/**
* Convert byte array to hex string
* @param bytes input data
* @see <a href="https://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to-a-hex-string-in-java">https://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to-a-hex-string-in-java</a>
* @return hex string
*/
public static String bytesToHex(byte[] bytes)
{
boolean insertCommas = true;
final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
char[] hexChars = new char[bytes.length * 2];
StringBuilder sb = new StringBuilder();
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
// if (!(hexChars[j * 2] == '0')) // omit leading zero
sb.append(hexChars[j * 2]);
sb.append(hexChars[j * 2 + 1]);
if (insertCommas && (j < bytes.length - 1))
sb.append(", ");
}
return sb.toString();
}
/**
* Report current PDU information to console
* @param anEspdu EntityStatePdu of interest
* @return same object to permit progressive setters
*/
public PduTrack reportPdu(EntityStatePdu anEspdu)
{
System.out.println (
String.format("%s", anEspdu.getMarkingString().trim()) + ", " +
DisTime.convertToString(anEspdu.getTimestamp()) + " (" +
String.format("%08d", anEspdu.getTimestamp()) + "), " +
"EntityID=(" +
anEspdu.getEntityID().getSiteID() + ", " +
anEspdu.getEntityID().getApplicationID() + ", " +
anEspdu.getEntityID().getEntityID() + "), " +
"location=(" +
String.format("%4.1f", anEspdu.getEntityLocation().getX()) + ", " +
String.format("%4.1f", anEspdu.getEntityLocation().getY()) + ", " +
String.format("%4.1f", anEspdu.getEntityLocation().getZ()) + ")"
// + " " + espdu_1.getEntityLinearVelocity().toString()
);
return this;
}
/** Flush all buffers to reduce console scrambling while threaded
*/
protected void flushBuffers()
{
try
{
dataOutputStream.flush();
byteArrayOutputStream.flush();
byteArrayOutputStream.reset();
System.err.flush();
System.out.flush();
}
catch (IOException ioe)
{
System.out.println(TRACE_PREFIX + "flushBuffers() IOException: " + ioe.getMessage());
}
}
/** Self test to check basic operation, invoked by main()
*/
@SuppressWarnings("SleepWhileInLoop")
public void selfTest()
{
final int TOTAL_PDUS = 5;
System.out.println(TRACE_PREFIX + "selfTest() start...");
PduTrack pduTrack = new PduTrack();
pduTrack.setDescriptor("PduTrack Self Test");
pduTrack.setAuthor("Don Brutzman");
pduTrack.setX3dModelIdentifier("https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/PduTrackInterpolation.x3d");
pduTrack.setDefaultWaypointInterval(1.0f); // experimentation with timestamp values
DisTime.setEpochLvcNow();
recordingStart = LocalDateTime.now();
Instant epoch = DisTime.getEpochLvc();
System.out.println(TRACE_PREFIX + "DisTime.hasEpochLvc()=" + DisTime.hasEpochLvc() +
", DisTime.getEpochLvc()=" + epoch +
", Instant.now()=" + Instant.now());
EntityID entityID_123 = new EntityID();
entityID_123.setSiteID(1).setApplicationID(2).setEntityID(3); // made-up example ID;
// TODO someday, use enumerations; is there a unique site triplet for MOVES Institute?
for (int i = 0; i < TOTAL_PDUS; i++) // create espdus and add each to track pduList
{
// EntityStatePdu espdu = new EntityStatePdu();
EntityStatePdu espdu = pduFactory.makeEntityStatePdu(); // TODO check Pdu.Type
espdu.setTimestamp(DisTime.getCurrentDisTimestamp()); // chooses appropriate version
espdu.setMarking("ESPDU " + i);
espdu.setEntityLocation(i, i, i);
espdu.setEntityOrientation(0, (float)(45.0 * Math.PI / 180.0), 0);
espdu.setEntityID(entityID_123);
espdu.setForceId(ForceID.FRIENDLY);
espdu.setEntityType(new _001Poseidon()); // note import statement above
pduTrack.addPdu(espdu); // create copy
reportPdu(espdu);
try
{
Thread.sleep(100l);
}
catch (InterruptedException ie)
{
System.out.println(TRACE_PREFIX + "exceptional sleep dulay when generating ESPDUs: " + ie.getMessage());
}
}
// System.out.println(TRACE_PREFIX + "reversePdus() then sortPdus() to test track operations");
// pduTrack.reversePdus(); // test
// pduTrack.sortPdus(); // restore
pduTrack.createRawWaypoints(); // copies all ESPDU points to waypoints
System.out.println(TRACE_PREFIX + "getEspduCount()=" + pduTrack.getEspduCount());
System.out.println(TRACE_PREFIX + "getDefaultWaypointInterval()=" + pduTrack.getDefaultWaypointInterval());
System.out.println(TRACE_PREFIX + "getTotalDurationSeconds()=" + pduTrack.getTotalDurationSeconds());
System.out.println("=================================");
System.out.println("PduTrack pduList marshalling checks");
System.out.println("= = = = = = = = = = = = = = = = =");
try
{
// int BYTE_BUFFER_SIZE = 400; // TODO what is expected max buffer size?
for (int i = 0; i < TOTAL_PDUS; i++)
{
Pdu pdu = pduTrack.getPduList().get(i);
if (!(pdu instanceof EntityStatePdu))
continue; // skip remainder of this loop
EntityStatePdu espdu = (EntityStatePdu) pdu;
System.out.println("espdu from pduTrack pduList");
reportPdu(espdu);
byte[] byteArray = espdu.marshal();
System.out.println("espdu.marshal() byteArray: " + bytesToHex(byteArray));
flushBuffers();
ByteBuffer byteBuffer = ByteBuffer.allocate(byteArray.length);
espdu.marshal(byteBuffer);
System.out.println("espdu.marshal(byteBuffer): " + bytesToHex(byteBuffer.array()));
flushBuffers();
espdu.marshal(dataOutputStream);
byte[] byteArrayDOS = byteArrayOutputStream.toByteArray();
System.out.println("espdu.marshal(dataOutputStream): " + bytesToHex(byteArrayDOS));
flushBuffers();
System.out.println(); // - - - - - - - - - - - - - - - - -
System.out.println("espdu.copyByteBuffer()");
reportPdu(espdu.copyByteBuffer());
byte[] byteArrayCopy = espdu.copyByteBuffer().marshal();
System.out.println("espdu.copyByteBuffer().marshal() byteArray: " + bytesToHex(byteArrayCopy));
flushBuffers();
ByteBuffer byteBufferCopy = ByteBuffer.allocate(byteArray.length); // TODO is there a better way to reset?
espdu.copyByteBuffer().marshal(byteBufferCopy);
System.out.println("espdu.copyByteBuffer().marshal(byteBufferCopy): " + bytesToHex(byteBufferCopy.array()));
flushBuffers();
espdu.copyByteBuffer().marshal(dataOutputStream);
byte[] byteArrayDosCopy = byteArrayOutputStream.toByteArray();
System.out.println("espdu.copyByteBuffer().marshal(dataOutputStream): " + bytesToHex(byteArrayDosCopy));
flushBuffers();
System.out.println(); // - - - - - - - - - - - - - - - - -
System.out.println("espdu.copyDataOutputStream()");
reportPdu(espdu.copyDataOutputStream());
byte[] byteArrayCopyDOS = espdu.copyDataOutputStream().marshal();
System.out.println("espdu.copyDataOutputStream().marshal() byteArray: " + bytesToHex(byteArrayCopyDOS));
flushBuffers();
ByteBuffer byteBufferCopyDOS = ByteBuffer.allocate(byteArray.length); // TODO is there a better way to reset?
espdu.copyDataOutputStream().marshal(byteBufferCopyDOS);
System.out.println("espdu.copyDataOutputStream().marshal(byteBufferCopy): " + bytesToHex(byteBufferCopyDOS.array()));
flushBuffers();
espdu.copyDataOutputStream().marshal(dataOutputStream);
byte[] byteArrayDosCopy2 = byteArrayOutputStream.toByteArray();
System.out.println("espdu.copyDataOutputStream().marshal(dataOutputStream): " + bytesToHex(byteArrayDosCopy2));
flushBuffers();
System.out.println();
System.out.println("= = = = = = = = = = = = = = = = =");
}
}
catch(Exception e)
{
System.out.println(TRACE_PREFIX + "Marshalling test exception: " + e.getMessage());
}
System.out.println("=================================");
pduTrack.setAddLineBreaksWithinKeyValues(true);
System.out.println(pduTrack.createX3dModel()); //
System.out.println("=================================");
recordingStop = LocalDateTime.now();
System.out.println(TRACE_PREFIX + "selfTest() complete.");
}
/**
* 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("*** PduTrack.main() self test started...");
PduTrack pduTrack = new PduTrack();
pduTrack.setDescriptor("main() self test");
pduTrack.selfTest();
System.out.println("*** PduTrack.main() self test complete.");
}
}
package MV3500Cohort2022MayJune.homework2.Tam;
import MV3500Cohort2022MayJune.homework2.Duran.*;
import MV3500Cohort2021JulySeptember.homework2.Domonique.*;
import java.io.*;
import java.net.*;
/**
*
* @author Johanna Tam
*/
public class TamTcpExampleClient {
/** IPv6 String constant for localhost address, similarly IPv4 127.0.0.1
* @see <a href="https://en.wikipedia.org/wiki/localhost">https://en.wikipedia.org/wiki/localhost</a>
* @see <a href="https://en.wikipedia.org/wiki/IPv6_address">https://en.wikipedia.org/wiki/IPv6_address</a>
*/
public final static String LOCALHOST = "0:0:0:0:0:0:0:1";
/**
* Program invocation, execution starts here
* @param args command-line arguments
* @throws java.lang.InterruptedException user can cancel execution
*/
public static void main(String[] args) throws InterruptedException {
// Local variables/fields
Socket socket = null;
InputStream is;
Reader isr;
BufferedReader br;
String serverMessage;
int clientLoopCount = 0;
try {
while (true)
{
clientLoopCount++; // increment at beginning of loop for reliability
System.out.println(TamTcpExampleClient.class.getName() + " creating socket...");
// We request an IP to connect to ("localhost") and
// port number at that IP (2317). This establishes
// a connection to that IP in the form of a Socket
// object; the server uses a ServerSocket to wait for
// connections.
socket = new Socket(LOCALHOST, 2317); // locohost?
// Now hook everything up (i.e. set up the streams), Java style:
is = socket.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
// Read a single line written by the server. We'd
// do things a bit differently if there were many lines to be read
// from the server instead of one only.
serverMessage = br.readLine();
System.out.println("==================================================");
// System.out.print ("Client loop " + clientLoopCount + ": ");
System.out.println("I am hungry");
System.out.println("The message the server sent was: '" + serverMessage + "'");
// socket gets closed, either automatically/silently by this code (or possibly by the server)
Thread.sleep(500l); // slow things down, for example 500l (long) = 500 msec (1/2 second)
} // end while(true) // infinite loops are dangerous, be sure to kill this process!
}
catch (IOException e)
{
System.err.println("Problem with " + TamTcpExampleClient.class.getName() + " networking:"); // describe what is happening
System.err.println("Error: " + e);
// Provide more helpful information to user if exception occurs due to running twice at one time
if (e instanceof java.net.BindException) {
System.err.println("*** Be sure to stop any other running instances of programs using this port!");
}
}
finally // occurs after any other activity when shutting down
{
try {
if (socket != null)
socket.close();
} catch (IOException e) {}
// program exit: tell somebody about that happening. Likely cause: server drops connection.
System.out.println();
System.out.println(TamTcpExampleClient.class.getName() + " exit");
}
}
}
\ No newline at end of file
package MV3500Cohort2022MayJune.homework2.Tam;
import MV3500Cohort2022MayJune.homework2.Duran.*;
import MV3500Cohort2021JulySeptember.homework2.Domonique.*;
import java.io.*;
import java.net.*;
/**
* homework assignment
* @author Johanna Tam
*/
public class TamTcpExampleServer {
/**
* Program invocation, execution starts here
* If already compiled, can run using console in directory ../../build/classes/ by invoking \
* java -classpath . TcpExamples.TcpExample3Server
* @param args command-line arguments
*/
public static void main(String[] args) {
try {
// ServerSocket waits for a connection from a client.
// Notice that it is outside the loop; ServerSocket
// needs to be made only once.
System.out.println(TamTcpExampleServer.class.getName() + " has started..."); // it helps debugging to put this on console first
ServerSocket serverSocket = new ServerSocket(2317);
OutputStream os;
PrintStream ps;
InetAddress localAddress, remoteAddress;
int localPort, remotePort;
int serverLoopCount = 0;
// Server is up and waiting (i.e. "blocked" or paused)
// Loop, infinitely, waiting for client connections.
// Stop the program somewhere else.
while (true) {
// block until connected to a client
try (Socket clientConnectionSocket = serverSocket.accept())
{
serverLoopCount++; // increment at beginning of loop for reliability
// Now hook everything up (i.e. set up the streams), Java style:
os = clientConnectionSocket.getOutputStream();
ps = new PrintStream(os);
ps.println("okay " + serverLoopCount + " let's go to Starbucks"); // this gets sent back to client!
// Print some information locally about the Socket connection.
// This includes the port and IP numbers on both sides (the socket pair).
localAddress = clientConnectionSocket.getLocalAddress();
remoteAddress = clientConnectionSocket.getInetAddress();
localPort = clientConnectionSocket.getLocalPort();
remotePort = clientConnectionSocket.getPort();
System.out.print ("Server loop " + serverLoopCount + ": ");
// My socket pair connection looks like this, to localhost:
// Socket pair: (( /0:0:0:0:0:0:0:1, 2317 ), ( /0:0:0:0:0:0:0:1, 54876 ))
// Socket pair: (( /0:0:0:0:0:0:0:1, 2317 ), ( /0:0:0:0:0:0:0:1, 54881 ))
// Why is the first IP/port the same, while the second set has different ports?
System.out.println(TamTcpExampleServer.class.getName() + " socket pair showing host name, address, port:");
System.out.println(" (( " +
localAddress.getHostName() + "=" + localAddress.getHostAddress() + ", " + localPort + " ), ( " +
remoteAddress.getHostName() + "=" + remoteAddress.getHostAddress() + ", " + remotePort + " ))");
if ( localAddress.getHostName().equals( localAddress.getHostAddress()) ||
remoteAddress.getHostName().equals(remoteAddress.getHostAddress()))
System.out.println(" note HostName matches address if host has no DNS name");
// Notice the use of flush() and try w/ resources. Without
// the try w/ resources the Socket object may stay open for
// a while after the client has stopped needing this
// connection. try w/ resources explicitly ends the connection.
ps.flush();
// like it or not, you're outta here!
}
}
} catch (IOException e) {
System.err.println("Problem with " + TamTcpExampleServer.class.getName() + " networking: " + e);
// Provide more helpful information to user if exception occurs due to running twice at one time
if (e instanceof java.net.BindException) {
System.err.println("*** Be sure to stop any other running instances of programs using this port!");
}
}
}
}
/**
* ExampleSimpleSimulation program-modification homework assignment supporting the NPS MOVES MV3500 Networked Graphics course.
*
* @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/tree/master/assignments">networkedGraphicsMV3500 assignments</a>
* @see java.lang.Package
* @see <a href="https://stackoverflow.com/questions/22095487/why-is-package-info-java-useful">StackOverflow: why-is-package-info-java-useful</a>
* @see <a href="https://stackoverflow.com/questions/624422/how-do-i-document-packages-in-java">StackOverflow: how-do-i-document-packages-in-java</a>
*/
package MV3500Cohort2022MayJune.homework2.Tam;
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