Skip to content
Snippets Groups Projects
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.");
        }
    }
}