import java.util.*;
import java.io.*;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author Ikonija Bogojevic
* @author Sandra Weber
* @author Miguel Perez
*
* This is the main Client class, which spawns ClientThreads which connect to the server. This class
* includes methods for obtaining the user's commands and validating them.
*/
public class Client {
private static String hostName;
// create a variable to initialize new threads with
private static Thread thrd = null;
// the threads are kept track of with a linked list
private static LinkedList list = new LinkedList();
// AtomicLong is a class that is synchronized, and can be used across
// multiple threads. Here it is used for benchmarking, to store the sum
// of the command completion times for all threads
private static AtomicLong totalTime = new AtomicLong(0);
// this AtomicLong is used to keep track of the current # of running threads
private static AtomicLong runningThreads = new AtomicLong(0);
private static boolean printOutput = true;
public static void main(String[] args) {
int menuSelection = 0;
int numProcesses = 1;
// if no hostname is provided, quit
if (args.length == 0) {
System.out.println("User did not enter a host name. Client program exiting.");
System.exit(1);
}
// until the user selects 8, the Exit option, keep looping and
// offering the menu again after running the queries to the server
else while (menuSelection != 8) {
// display the menu and get the user's choice
menuSelection = mainMenu();
// if 8, exit program
if (menuSelection == 8) {
System.out.println("Quitting.");
System.exit(0);
}
// if 7, ask which command should be run in the benchmark mode
// and how many connections to create
if (menuSelection == 7) {
printOutput = false;
menuSelection = benchmarkMenu();
numProcesses = numProcessesMenu();
}
// create threads. since numProcesses is initialized to 1 and gets reset
// at the end of this loop, if the user has not selected to benchmark
// a command, this loop will only create one process
totalTime.set(0);
runningThreads.set(numProcesses);
for (int i = 0; i < numProcesses; i++) {
// make a new thread, tell it the hostname to connect to
// and the command to run. It is also passed the totalTime object,
// so it can record how much time its command took to complete
thrd = new Thread(new ClientThread(args[0], menuSelection, totalTime, printOutput, runningThreads));
thrd.start(); // start the thread
list.add(thrd); // add the thread to the end of the linked list
}
// wait for all of the threads to complete before going to the top
// of the loop again. This ensures that all threads complete before the
// menu is shown again
for (int i = 0; i < numProcesses; i++) {
try {
// wait for the thread to finish
list.get(i).join();
} catch (InterruptedException e) {
// if the join interrupts the thread, print an error
e.printStackTrace();
}
}
// while runningThreads is not 0, there are still clients waiting for the server
// to send a response, so keep looping (waiting) until they are finished
while (runningThreads.get() != 0) {}
System.out.println("Average response time: " + (totalTime.get() / numProcesses) + " ms\n");
numProcesses = 1;
printOutput = true;
}
}
//----------------------------------------------------------------------------
/**
* Function to prompt the user for a command to run
* @return command number 1-8
*/
public static int mainMenu() {
int menuSelection = 0;
// loop (and prompt again) until the user's input is an integer between 1 and 8
while ((menuSelection <= 0) || (menuSelection > 8)) {
System.out.println("The menu provides the following choices to the user: ");
System.out.println("1. Host current Date and Time \n2. Host uptime\n"
+ "3. Host memory use \n4. Host Netstat \n5. Host current users "
+ "\n6. Host running processes \n7. Benchmark (measure mean response time)\n8. Quit ");
System.out.print("Please provide number corresponding to the action you want to be performed: ");
Scanner sc = new Scanner(System.in);
if (sc.hasNextInt()) menuSelection = sc.nextInt();
}
return menuSelection;
}
/**
* Function to prompt the user for a benchmark command to run
* @return command number 1-6
*/
public static int benchmarkMenu() {
int menuSelection = 0;
// loop (and prompt again) until the user's input is an integer between 1 and 6
while ((menuSelection <= 0) || (menuSelection > 6)) {
System.out.println("Which command would you like to benchmark? ");
System.out.println("1. Host current Date and Time \n2. Host uptime\n"
+ "3. Host memory use \n4. Host Netstat \n5. Host current users "
+ "\n6. Host running processes");
System.out.print("Please provide number corresponding to the action you want to be performed: ");
Scanner sc = new Scanner(System.in);
if (sc.hasNextInt()) menuSelection = sc.nextInt();
}
return menuSelection;
}
/**
* Function to prompt the user for how many connections to make (for measuring the mean response time)
* @return number 1-100
*/
public static int numProcessesMenu() {
int menuSelection = 0;
// loop (and prompt again) until the user's input is an integer between 1 and 100
while ((menuSelection <= 0) || (menuSelection > 100)) {
System.out.print("How many connections to the server would you like to open? [1-100]: ");
Scanner sc = new Scanner(System.in);
if (sc.hasNextInt()) menuSelection = sc.nextInt();
}
return menuSelection;
}
}