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.NotImplementedException; 36 import jdk.jshell.spi.ExecutionControl.ResolutionException; 37 import jdk.jshell.spi.ExecutionControl.StoppedException; 38 import jdk.jshell.spi.ExecutionControl.UserException; 39 import static jdk.jshell.execution.RemoteCodes.*; 40 41 /** 42 * Forwards commands from the input to the specified {@link ExecutionControl} 43 * instance, then responses back on the output. 44 */ 45 class ExecutionControlForwarder { 46 47 private final ExecutionControl ec; 48 private final ObjectInput in; 49 private final ObjectOutput out; 50 51 ExecutionControlForwarder(ExecutionControl ec, ObjectInput in, ObjectOutput out) { 52 this.ec = ec; 53 this.in = in; 54 this.out = out; 55 } 56 57 private boolean writeSuccess() throws IOException { 58 writeStatus(RESULT_SUCCESS); 59 flush(); 60 return true; 61 } 62 63 private boolean writeSuccessAndResult(String result) throws IOException { 64 writeStatus(RESULT_SUCCESS); 65 writeUTF(result); 66 flush(); 67 return true; 68 } 69 70 private boolean writeSuccessAndResult(Object result) throws IOException { 71 writeStatus(RESULT_SUCCESS); 72 writeObject(result); 73 flush(); 74 return true; 75 } 76 77 private void writeStatus(int status) throws IOException { 78 out.writeInt(status); 79 } 80 81 private void writeObject(Object o) throws IOException { 82 out.writeObject(o); 83 } 84 85 private void writeInt(int i) throws IOException { 86 out.writeInt(i); 87 } 88 89 private void writeUTF(String s) throws IOException { 90 if (s == null) { 91 s = ""; 92 } 93 out.writeUTF(s); 94 } 95 96 private void flush() throws IOException { 97 out.flush(); 98 } 99 100 private boolean processCommand() throws IOException { 101 try { 102 int prefix = in.readInt(); 103 if (prefix != COMMAND_PREFIX) { 104 throw new EngineTerminationException("Invalid command prefix: " + prefix); 105 } 106 String cmd = in.readUTF(); 107 switch (cmd) { 108 case CMD_LOAD: { 109 // Load a generated class file over the wire 110 ClassBytecodes[] cbcs = (ClassBytecodes[]) in.readObject(); 111 ec.load(cbcs); 112 return writeSuccess(); 113 } 114 case CMD_REDEFINE: { 115 // Load a generated class file over the wire 116 ClassBytecodes[] cbcs = (ClassBytecodes[]) in.readObject(); 117 ec.redefine(cbcs); 118 return writeSuccess(); 119 } 120 case CMD_INVOKE: { 121 // Invoke executable entry point in loaded code 122 String className = in.readUTF(); 123 String methodName = in.readUTF(); 124 String res = ec.invoke(className, methodName); 125 return writeSuccessAndResult(res); 126 } 127 case CMD_VAR_VALUE: { 128 // Retrieve a variable value 129 String className = in.readUTF(); 130 String varName = in.readUTF(); 131 String res = ec.varValue(className, varName); 132 return writeSuccessAndResult(res); 133 } 134 case CMD_ADD_CLASSPATH: { 135 // Append to the claspath 136 String cp = in.readUTF(); 137 ec.addToClasspath(cp); 138 return writeSuccess(); 139 } 140 case CMD_SET_CLASSPATH: { 141 // Set the claspath 142 String cp = in.readUTF(); 143 ec.setClasspath(cp); 144 return writeSuccess(); 145 } 146 case CMD_STOP: { 147 // Stop the current execution 148 try { 149 ec.stop(); 150 } catch (Throwable ex) { 151 // JShell-core not waiting for a result, ignore 152 } 153 return true; 154 } 155 case CMD_CLOSE: { 156 // Terminate this process 157 try { 158 ec.close(); 159 } catch (Throwable ex) { 160 // JShell-core not waiting for a result, ignore 161 } 162 return true; 163 } 164 default: { 165 Object arg = in.readObject(); 166 Object res = ec.extensionCommand(cmd, arg); 167 return writeSuccessAndResult(res); 168 } 169 } 170 } catch (IOException ex) { 171 // handled by the outer level 172 throw ex; 173 } catch (EngineTerminationException ex) { 174 writeStatus(RESULT_TERMINATED); 175 writeUTF(ex.getMessage()); 176 flush(); 177 return false; 178 } catch (NotImplementedException ex) { 179 writeStatus(RESULT_NOT_IMPLEMENTED); 180 writeUTF(ex.getMessage()); 181 flush(); 182 return true; 183 } catch (InternalException ex) { 184 writeStatus(RESULT_INTERNAL_PROBLEM); 185 writeUTF(ex.getMessage()); 186 flush(); 187 return true; 188 } catch (ClassInstallException ex) { 189 writeStatus(RESULT_CLASS_INSTALL_EXCEPTION); 190 writeUTF(ex.getMessage()); 191 writeObject(ex.installed()); 192 flush(); 193 return true; 194 } catch (UserException ex) { 195 writeStatus(RESULT_USER_EXCEPTION); 196 writeUTF(ex.getMessage()); 197 writeUTF(ex.causeExceptionClass()); 198 writeObject(ex.getStackTrace()); 199 flush(); 200 return true; 201 } catch (ResolutionException ex) { 202 writeStatus(RESULT_CORRALLED); 203 writeInt(ex.id()); 204 writeObject(ex.getStackTrace()); 205 flush(); 206 return true; 207 } catch (StoppedException ex) { 208 writeStatus(RESULT_STOPPED); 209 flush(); 210 return true; 211 } catch (Throwable ex) { 212 writeStatus(RESULT_TERMINATED); 213 writeUTF(ex.getMessage()); 214 flush(); 215 return false; 216 } 217 } 218 219 void commandLoop() { 220 try { 221 while (processCommand()) { 222 // condition is loop action 223 } 224 } catch (IOException ex) { 225 // drop out of loop 226 } 227 } 228 229 }