Something went wrong on our end
-
Brutzman, Don authoredBrutzman, Don authored
TcpSentryHandlerThread.java 9.55 KiB
package TcpExamples;
import java.io.*;
import java.net.*;
import java.util.Arrays;
import java.util.List;
/**
* <p>
* This utility class supports the {@link TcpExamples.TcpSentryDispatchServer} program,
* handling all programming logic needed for a new socket connection
* to run in a thread of its own. This is the server
* portion as well, so we artificially invent what happens
* if the server can't respond to a connection for several seconds.
* </p>
* <p>
* Warning: do not run this class! It is created and used automatically by {@link TcpExamples.TcpSentryDispatchServer} at run time.
* </p>
*
* @see TcpSentryClient
* @see TcpSentryDispatchServer
* @see TcpExample4Client
* @see TcpExample4DispatchServer
* @see TcpExample4HandlerThread
*
* @see <a href="../../../src/TcpExamples/TcpSentryTerminalLog.txt" target="blank">TcpSentryTerminalLog.txt</a>
* @see <a href="../../../src/TcpExamples/TcpExample4SequenceDiagram.png" target="blank">TcpExample4SequenceDiagram.png</a>
* @see <a href="../../../src/TcpExamples/TcpExample4SequenceSketch.png" target="blank">TcpExample4SequenceSketch.png</a>
*
* @author Don McGregor
* @author Don Brutzman
* @author MV3500 class
*/
public class TcpSentryHandlerThread extends Thread
{
/** who is speaking, by role */
static final String ACTOR = "[sentry] ";
/** Sentry Scenario access list, as written this list is case sensitive.
* See <a href="https://stackoverflow.com/questions/1005073/initialization-of-an-arraylist-in-one-line" target="blank">https://stackoverflow.com/questions/1005073/initialization-of-an-arraylist-in-one-line</a>
*/
public static List<String> allowedNamesList =
Arrays.asList("Tim", "Stephen", "Mark", "Rene", "Simon", "James", "Ethan", "Jin Hong", "Don");
/** Sentry command vocabulary: the guard is out of the house! */
public static final String SENTRY_WATCH_PRESENT = "Announcement: the sentry watch is present and standing guard.";
/** Sentry command vocabulary: hand signal or loud statement (across the standoff distance) to next vehicle waiting at STOP sign */
public static final String APPROACH_THE_GATE = "(verbal or hand gesture) You may approach the gate.";
/** Sentry command vocabulary: use a standard admonition for broad recognition by visitors */
public static final String HALT_WHO_GOES_THERE = "Halt who goes there?";
/** Sentry command vocabulary */
public static final String YOU_MAY_PASS = "You may pass, have a great MOVES day!";
/** Sentry command vocabulary */
public static final String HOLD_IT_RIGHT_THERE = "You may not pass! Leave immediately or else...";
/** Sentry command vocabulary */
public static final String PAY_ATTENTION = "Did you hear me? Pay attention please.";
/** TODO, not implemented: visitor ignores the sentry's direction to leave and enters the base */
public static final String INTRUDER_ALERT = "An unauthorized visitor has entered the base!";
/** The socket connection to a client */
Socket socket;
/**
* The thread constructor creates the socket from a ServerSocket, waiting for the client to connect,
* and passes that socket when constructing the thread responsible for handling the connection.
*
* @param socket The socket connection handled by this thread
*/
TcpSentryHandlerThread(Socket socket)
{
this.socket = socket;
System.out.println(ACTOR + "1h.TcpSentryClient, " + TcpSentryHandlerThread.class.getName());
}
/**
* Program invocation and execution starts here - but is illegal and unwanted, so warn the unsuspecting user!
* @param args command-line arguments
*/
public static void main(String[] args)
{
System.out.println ("*** TcpSentryHandlerThread is not a standalone executable progam.");
System.out.println ("*** Please run TcpSentryDispatchServer instead... now handing the baton back to the boss.");
TcpSentryDispatchServer.main(new String[] { /* dummy args */ });
// exit
}
/** Handles one connection. We add an artificial slowness
* to handling the connection with a sleep(). This means
* the client won't see a server connection response for ten seconds (default).
*/
// @overriding run() method in Java Thread class is deliberate
@Override
public void run()
{
try
{
System.out.println(ACTOR + "startup, menu 1g.TcpSentryServer, " + TcpSentryHandlerThread.class.getName());
// now starting to handle the thread
// setup input stream and output stream
InputStream socketInputStream = socket.getInputStream();
Reader socketInputStreamReader = new InputStreamReader(socketInputStream);
BufferedReader socketBufferedReader = new BufferedReader(socketInputStreamReader);
OutputStream socketOutputStream = socket.getOutputStream();
PrintStream socketPrintStream = new PrintStream(socketOutputStream);
final long TIMEOUT = 100; // 2000 milliseconds = 2 seconds, 10000 milliseconds = 10 seconds
// System.out.println(prefix + " pausing for TIMEOUT=" + TIMEOUT + "ms" +
// " to emulate computation and avoid server-side overload");
Thread.sleep(TIMEOUT);
////////////////////////////////////////////////////////////////////////////////////////////
// Assignment code
// since this thread is running, a socket connection has already been received from dispatch server.
// PrintStream is the Java way to use System.print() to pass string data along the socket.
socketPrintStream.println(ACTOR + SENTRY_WATCH_PRESENT);
System.out.println(ACTOR + SENTRY_WATCH_PRESENT);
// make sure that message indeed escapes current process and is pushed through socket to reach the client
socketPrintStream.flush();
// now the query-response interactions begin...
socketPrintStream.println(ACTOR + APPROACH_THE_GATE);
System.out.println(ACTOR + APPROACH_THE_GATE);
// No communications response occurs, instead the visitor drives up to the gate
socketPrintStream.println(ACTOR + HALT_WHO_GOES_THERE);
System.out.println(ACTOR + HALT_WHO_GOES_THERE);
String clientResponse = socketBufferedReader.readLine();
System.out.println (clientResponse);
// trim actor prefix if neccessary
int messageIndex = clientResponse.indexOf("]");
if (messageIndex > 0)
clientResponse = clientResponse.substring(messageIndex + 1).trim();
while (clientResponse.isBlank()) // repeat if needed
{
socketPrintStream.println(ACTOR + PAY_ATTENTION);
System.out.println(ACTOR + PAY_ATTENTION);
socketPrintStream.println(ACTOR + HALT_WHO_GOES_THERE);
System.out.println(ACTOR + HALT_WHO_GOES_THERE);
clientResponse = socketBufferedReader.readLine();
System.out.println (clientResponse);
// trim actor prefix if neccessary
messageIndex = clientResponse.indexOf("]");
if (messageIndex > 0)
clientResponse = clientResponse.substring(messageIndex + 1).trim();
}
if (clientResponse.trim().equalsIgnoreCase("quit") ||
clientResponse.trim().equalsIgnoreCase("exit"))
{
System.out.println (ACTOR + "Exiting the program.");
socket.close();
System.exit(0); // shuts down thread, not dispatch server
}
// simple response
socketPrintStream.println(ACTOR + "Hello, " + clientResponse);
System.out.println(ACTOR + "Hello, " + clientResponse);
// now check credential and respond accordingly
if (allowedNamesList.contains(clientResponse))
{
socketPrintStream.println(ACTOR + YOU_MAY_PASS);
System.out.println(ACTOR + YOU_MAY_PASS);
}
else
{
socketPrintStream.println(ACTOR + HOLD_IT_RIGHT_THERE);
System.out.println(ACTOR + HOLD_IT_RIGHT_THERE);
}
////////////////////////////////////////////////////////////////////////////////////////////
// socket.close(); // all clear, no longer need socket
System.out.println(ACTOR + "this visitor interaction is complete.");
System.out.println("=================================================================================");
// execution complete
}
catch(IOException | InterruptedException e) // either a networking or a threading problem
{
System.out.println("*** " + ACTOR + "Problem with networking,"); // describe what is happening
System.out.println(" " + e);
// Provide more helpful information to user if exception occurs due to running twice at one time
if (e instanceof java.net.BindException)
System.out.println("*** Be sure to stop any other running instances of programs using this port!");
}
finally
{
System.out.println(TcpSentryHandlerThread.class.getName() + " all done.");
}
}
}