1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.jshell.execution; 26 27 import java.io.IOException; 28 import java.io.ObjectInput; 29 import java.io.ObjectOutput; 30 import jdk.jshell.spi.ExecutionControl; 31 import jdk.jshell.spi.ExecutionControl.ClassBytecodes; 32 import jdk.jshell.spi.ExecutionControl.ClassInstallException; 33 import jdk.jshell.spi.ExecutionControl.EngineTerminationException; 34 import jdk.jshell.spi.ExecutionControl.InternalException; 35 import jdk.jshell.spi.ExecutionControl.ResolutionException; 36 import jdk.jshell.spi.ExecutionControl.StoppedException; 37 import jdk.jshell.spi.ExecutionControl.UserException; 38 39 /** 40 * Forwards commands from the input to the specified {@link ExecutionControl} 41 * instance, then responses back on the output. 42 */ 43 class ExecutionControlForwarder { 44 45 private final ExecutionControl ec; 46 private final ObjectInput in; 47 private final ObjectOutput out; 48 49 ExecutionControlForwarder(ExecutionControl ec, ObjectInput in, ObjectOutput out) { 50 this.ec = ec; 51 this.in = in; 52 this.out = out; 53 } 54 55 private boolean writeSuccess() throws IOException { 56 writeStatus(RemoteStatus.SUCCESS); 57 flush(); 58 return true; 59 } 60 61 private boolean writeSuccessAndResult(String result) throws IOException { 62 writeStatus(RemoteStatus.SUCCESS); 63 writeUTF(result); 64 flush(); 65 return true; 66 } 67 68 private void writeStatus(RemoteStatus status) throws IOException { 69 out.writeObject(status); 70 } 71 72 private void writeObject(Object o) throws IOException { 73 out.writeObject(o); 74 } 75 76 private void writeInt(int i) throws IOException { 77 out.writeInt(i); 78 } 79 80 private void writeUTF(String s) throws IOException { 81 if (s == null) { 82 s = ""; 83 } 84 out.writeUTF(s); 85 } 86 87 private void flush() throws IOException { 88 out.flush(); 89 } 90 91 private boolean processCommand() throws IOException { 92 RemoteCommand cmd; 93 try { 94 cmd = (RemoteCommand) in.readObject(); 95 if (cmd == null) { 96 throw new IOException("Missing command: " + cmd); 97 } 98 switch (cmd) { 99 case LOAD: { 100 // Load a generated class file over the wire 101 ClassBytecodes[] cbcs = (ClassBytecodes[]) in.readObject(); 102 ec.load(cbcs); 103 return writeSuccess(); 104 } 105 case REDEFINE: { 106 // Load a generated class file over the wire 107 ClassBytecodes[] cbcs = (ClassBytecodes[]) in.readObject(); 108 ec.redefine(cbcs); 109 return writeSuccess(); 110 } 111 case INVOKE: { 112 // Invoke executable entry point in loaded code 113 String className = in.readUTF(); 114 String methodName = in.readUTF(); 115 String res = ec.invoke(className, methodName); 116 return writeSuccessAndResult(res); 117 } 118 case VAR_VALUE: { 119 // Retrieve a variable value 120 String className = in.readUTF(); 121 String varName = in.readUTF(); 122 String res = ec.varValue(className, varName); 123 return writeSuccessAndResult(res); 124 } 125 case ADD_CLASSPATH: { 126 // Append to the claspath 127 String cp = in.readUTF(); 128 ec.addToClasspath(cp); 129 return writeSuccess(); 130 } 131 case SET_CLASSPATH: { 132 // Set the claspath 133 String cp = in.readUTF(); 134 ec.setClasspath(cp); 135 return writeSuccess(); 136 } 137 case STOP: { 138 // Stop the current execution 139 try { 140 ec.stop(); 141 } catch (Throwable ex) { 142 // JShell-core not waiting for a result, ignore 143 } 144 return true; 145 } 146 case CLOSE: { 147 // Terminate this process 148 try { 149 ec.close(); 150 } catch (Throwable ex) { 151 // JShell-core not waiting for a result, ignore 152 } 153 return true; 154 } 155 } 156 return false; // cannot get here, make the compiler happy 157 } catch (IOException ex) { 158 // handled by the outer level 159 throw ex; 160 } catch (EngineTerminationException ex) { 161 writeStatus(RemoteStatus.TERMINATED); 162 writeUTF(ex.getMessage()); 163 flush(); 164 return false; 165 } catch (InternalException ex) { 166 writeStatus(RemoteStatus.INTERNAL_PROBLEM); 167 writeUTF(ex.getMessage()); 168 flush(); 169 return true; 170 } catch (ClassInstallException ex) { 171 writeStatus(RemoteStatus.CLASS_INSTALL_EXCEPTION); 172 writeUTF(ex.getMessage()); 173 writeObject(ex.installed()); 174 flush(); 175 return true; 176 } catch (UserException ex) { 177 writeStatus(RemoteStatus.USER_EXCEPTION); 178 writeUTF(ex.getMessage()); 179 writeUTF(ex.causeExceptionClass()); 180 writeObject(ex.getStackTrace()); 181 flush(); 182 return true; 183 } catch (ResolutionException ex) { 184 writeStatus(RemoteStatus.CORRALLED); 185 writeInt(ex.id()); 186 writeObject(ex.getStackTrace()); 187 flush(); 188 return true; 189 } catch (StoppedException ex) { 190 writeStatus(RemoteStatus.STOPPED); 191 flush(); 192 return true; 193 } catch (Throwable ex) { 194 writeStatus(RemoteStatus.TERMINATED); 195 writeUTF(ex.getMessage()); 196 flush(); 197 return false; 198 } 199 } 200 201 void commandLoop() { 202 try { 203 while (processCommand()) { 204 // condition is loop action 205 } 206 } catch (IOException ex) { 207 // ignore 208 } 209 } 210 211 }