diff --git a/jgrab-runner/src/main/java/com/athaydes/jgrab/daemon/JGrabDaemon.java b/jgrab-runner/src/main/java/com/athaydes/jgrab/daemon/JGrabDaemon.java index 3ad1679..89cc70b 100644 --- a/jgrab-runner/src/main/java/com/athaydes/jgrab/daemon/JGrabDaemon.java +++ b/jgrab-runner/src/main/java/com/athaydes/jgrab/daemon/JGrabDaemon.java @@ -21,7 +21,7 @@ /** * JGrab daemon, a TCP socket server that runs in the background waiting for Java code to run. */ -public class JGrabDaemon { +public final class JGrabDaemon { private static final Logger logger = LoggerFactory.getLogger( JGrabDaemon.class ); private static final String STOP_OPTION = "--stop"; @@ -42,6 +42,7 @@ public class JGrabDaemon { } ) ); } + @SuppressWarnings( "resource" ) public static void start( RunArgs runArgs ) { new Thread( () -> { logger.debug( "Starting JGrab Daemon" ); @@ -60,87 +61,10 @@ public static void start( RunArgs runArgs ) { final PrintStream out = new PrintStream( clientSocket.getOutputStream(), true ); BufferedReader in = new BufferedReader( new InputStreamReader( clientSocket.getInputStream() ) ) ) { - String firstLine = null; - String inputLine; - StringBuilder messageBuilder = new StringBuilder( 1024 ); - - while ( ( inputLine = in.readLine() ) != null ) { - if ( firstLine == null ) { - firstLine = inputLine; - } else { - messageBuilder.append( inputLine ).append( '\n' ); - } - } - - if ( firstLine == null ) { - out.println( "Communication error (input line is null)" ); - continue; - } - - JavaCode code; - String[] args; - - // check for Java file contents preceded by Java arguments - if ( messageBuilder.length() > 0 && JAVA_ARGUMENTS_LINE.matcher( firstLine ).matches() ) { - // remove the [] demarkers - String javaArgs = firstLine.substring( 1, firstLine.length() - 1 ); - logger.debug( "Java arguments: {}", javaArgs ); - code = new StringJavaCode( messageBuilder.toString() ); - args = javaArgs.split( " " ); - } else { - String input = ( firstLine + "\n" + messageBuilder ).trim(); - - if ( input.equals( STOP_OPTION ) ) { - logger.info( "--stop option received, stopping JGrab Daemon" ); - out.println( "=== JGrab Daemon stopped ===" ); - return; - } - - if ( input.equals( VERSION_OPTION ) ) { - logger.info( "--version option received" ); - System.setOut( out ); - System.setErr( out ); - JGrabRunner.printVersion(); - continue; - } - - if ( input.startsWith( JGrabOptions.SNIPPET_OPTION ) ) { - String snippet = input.substring( JGrabOptions.SNIPPET_OPTION.length() ); - if ( snippet.isEmpty() ) { - out.println( "ERROR: no snippet provided to execute" ); - continue; - } else { - code = new StringJavaCode( snippet ); - args = new String[ 0 ]; - } - } else { - code = new StringJavaCode( input ); - args = new String[ 0 ]; - } - } - - logSourceCode( code ); - - var deps = code.extractDependencies(); - - logger.debug( "Dependencies to grab: {}", deps ); - - var classpath = libsCache.classpathOf( deps, () -> grabber.grab( deps ) ); - - System.setIn( clientSocket.getInputStream() ); - System.setOut( out ); - System.setErr( out ); - - // run this synchronously, which means only one program can run per daemon at a time - try { - runArgs.accept( code, args, classpath ); - } catch ( Throwable t ) { - t.printStackTrace( out ); - } + handleClient( in, out, runArgs ); } catch ( IOException e ) { logger.warn( "Problem handling client message", e ); } finally { - System.setIn( System.in ); System.setOut( System.out ); System.setErr( System.err ); } @@ -148,6 +72,104 @@ public static void start( RunArgs runArgs ) { }, "jgrab-daemon" ).start(); } + private static void handleClient( + BufferedReader in, + PrintStream out, + RunArgs runArgs ) throws IOException { + var request = parseRequest( in, out ); + if ( request == null ) return; + + logSourceCode( request.code ); + + var deps = request.code.extractDependencies(); + + logger.debug( "Dependencies to grab: {}", deps ); + + var classpath = libsCache.classpathOf( deps, () -> grabber.grab( deps ) ); + + System.setOut( out ); + System.setErr( out ); + + // run this synchronously, which means only one program can run per daemon at a time + try { + runArgs.accept( request.code, request.args, classpath ); + } catch ( Throwable t ) { + t.printStackTrace( out ); + } + } + + private static CodeRunRequest parseRequest( BufferedReader in, PrintStream out ) throws IOException { + String firstLine = null; + String inputLine; + StringBuilder messageBuilder = new StringBuilder( 1024 ); + + while ( ( inputLine = in.readLine() ) != null ) { + if ( firstLine == null ) { + firstLine = inputLine; + } else { + messageBuilder.append( inputLine ).append( '\n' ); + } + } + + if ( firstLine == null ) { + out.println( "Communication error (input line is null)" ); + return null; + } + + JavaCode code; + String[] args; + + // check for Java file contents preceded by Java arguments + if ( messageBuilder.length() > 0 && JAVA_ARGUMENTS_LINE.matcher( firstLine ).matches() ) { + // remove the [] demarkers + String javaArgs = firstLine.substring( 1, firstLine.length() - 1 ); + logger.debug( "Java arguments: {}", javaArgs ); + code = new StringJavaCode( messageBuilder.toString() ); + args = javaArgs.split( " " ); + } else { + String input = ( firstLine + "\n" + messageBuilder ).trim(); + + if ( input.equals( STOP_OPTION ) ) { + logger.info( "--stop option received, stopping JGrab Daemon" ); + out.println( "=== JGrab Daemon stopped ===" ); + return null; + } + + if ( input.equals( VERSION_OPTION ) ) { + logger.info( "--version option received" ); + System.setOut( out ); + System.setErr( out ); + JGrabRunner.printVersion(); + return null; + } + + if ( input.startsWith( JGrabOptions.SNIPPET_OPTION ) ) { + String snippet = input.substring( JGrabOptions.SNIPPET_OPTION.length() ); + if ( snippet.isEmpty() ) { + out.println( "ERROR: no snippet provided to execute" ); + return null; + } else { + code = new StringJavaCode( snippet ); + args = new String[ 0 ]; + } + } else { + code = new StringJavaCode( input ); + args = new String[ 0 ]; + } + } + return new CodeRunRequest( code, args ); + } + + private static final class CodeRunRequest { + public final JavaCode code; + public final String[] args; + + public CodeRunRequest( JavaCode code, String[] args ) { + this.code = code; + this.args = args; + } + } + private static void logSourceCode( Object source ) { logger.trace( "Source code:\n------------------------------------\n" + "{}\n------------------------------------\n", source );