#!/opt/jython2.7.0/bin/jython # CSC543s24ServerDemo.py D. Parson csc543 spring 2024 # Running a client thread and server in single process for this demo. # See docs in https://jython.readthedocs.io/en/latest/ and https://www.jython.org/ and # https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/package-summary.html import sys from java.lang import Thread, Runnable from java.util.concurrent import LinkedBlockingQueue # main server thread blocks from java.util.concurrent import Executors, Callable, ExecutorCompletionService from java.util.concurrent import ExecutionException, CancellationException from time import localtime, strftime, sleep class Client(Runnable): ''' The client thread prompts & reads the keyboard and sends the sleep(N) or shutdown or shutdownNow request to the server via a LinkedBlockingQueue that simulates a submission UDP socket. It does not process the result, which is done in the CompletionService. ''' def __init__(self, cliToSrvr): self.cliToSrvr = cliToSrvr def run(self): seqno = 0 while True: inline = '' while not inline: try: inline = raw_input('Enter seconds number or shutdown: ') inline = inline.strip() if not inline: sys.stdout.write('\n') ; sys.stdout.flush() except EOFError: inline = 'shutdownNow' # ctrl-D is EOF except (Exception, KeyboardInterrupt) as ohno: sys.stderr.write('BAD KEYBOARDINPUT: ' + str(ohno) + '\n') if inline == 'shutdown' or inline == 'shutdownNow': self.cliToSrvr.offer([str(seqno), inline, strftime('%H:%M:%S', localtime())]) break # terminates client thread try: value = int(inline) if value < 0: raise ValueError("Invalid negative number: " + inline) else: self.cliToSrvr.offer([str(seqno), inline, strftime('%H:%M:%S', localtime())]) seqno += 1 except Exception as oops: sys.stderr.write('BAD INPUT: ' + inline + '\n') class Task(Callable): # Worker thread's task ''' The Task sleeps for N seconds as passed to its constructor. ''' def __init__(self, serialNo, seconds, startTime): self.startTime = startTime self.serialNo = serialNo self.seconds = seconds def call(self): try: Thread.sleep(int(self.seconds) * 1000) # int could throw exp # sleep(int(self.seconds)) return [self.serialNo, self.seconds, startTime, strftime('%H:%M:%S', localtime())] except (Exception, KeyboardInterrupt) as oops: sys.stderr.write("ERROR in Task: " + str(oops) + '\n') return [self.serialNo, "ERROR: " + str(self.seconds), startTime, strftime('%H:%M:%S', localtime())] class Completer(Runnable): ''' The Completer thread picks up and prints task request from the CompletionService. ''' def __init__(self, completionService): self.completionService = completionService def run(self): while True: try: nextFuture = self.completionService.take() sys.stdout.write("\nCOMPLETED: " + str(nextFuture.get()) + '\n') sys.stdout.write('Enter seconds number or shutdown: ') sys.stdout.flush() except (Exception, ExecutionException, CancellationException) as wow: sys.stderr.write('CompletionService Future get() exception: ' + str(wow) + '\n') __usage__ = \ 'jython CSC543s24ServerDemo.py single|fixed3|cached' if __name__ == '__main__': # print("Length of sys.argv: ", len(sys.argv)) if len(sys.argv) != 2: raise ValueError("ERROR, USAGE " + __usage__) if not sys.argv[1] in ['single', 'fixed3', 'cached']: raise ValueError("ERROR, " + sys.argv[3] + " not in single|fixed3|cached") # Construct in main thread "happens before" starting other threads. cliToSrvr = LinkedBlockingQueue() client = Client(cliToSrvr) clientThread = Thread(client) clientThread.start() if sys.argv[1] == 'single': server = Executors.newSingleThreadExecutor() elif sys.argv[1] == 'fixed3': server = Executors.newFixedThreadPool(3) else: server = Executors.newCachedThreadPool() completionService = ExecutorCompletionService(server) completer = Completer(completionService) completerThread = Thread(completer) completerThread.setDaemon(True) # This thread will not inhibit exiting. completerThread.start() while True: # This is the main server thread: serialNo, action, startTime = cliToSrvr.take() if action == 'shutdown': server.shutdown() break elif action == 'shutdownNow': server.shutdownNow() break else: t = Task(serialNo, action, startTime) # OOPS server.submit(t) completionService.submit(t) # sys.exit(0) clientThread.join()