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.DataInputStream; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.OutputStream; 31 import java.util.regex.Matcher; 32 import java.util.regex.Pattern; 33 34 /** 35 * Read from an InputStream which has been packetized and write its contents 36 * to the named OutputStreams. 37 * 38 * @author Jan Lahoda 39 * @see Util#demultiplexInput(java.io.InputStream, jdk.jshell.execution.ECLogger, java.io.OutputStream, java.io.OutputStream, java.io.OutputStream...) 40 */ 41 class DemultiplexInput extends Thread { 42 43 private static final Pattern AUX_FORMAT = Pattern.compile("aux(\\d+)"); 44 private final DataInputStream delegate; 45 private final PipeInputStream command; 46 private final OutputStream out; 47 private final OutputStream err; 48 private final OutputStream[] aux; 49 private final ECLogger log; 50 51 DemultiplexInput(InputStream input, PipeInputStream command, ECLogger log, 52 OutputStream out, OutputStream err, OutputStream... aux) { 53 super("output reader"); 54 this.delegate = new DataInputStream(input); 55 this.command = command; 56 this.out = out; 57 this.err = err; 58 this.aux = aux; 59 this.log = log; 60 } 61 62 @Override 63 public void run() { 64 try { 65 while (true) { 66 int nameLen = delegate.read(); 67 if (nameLen == (-1)) { 68 break; 69 } 70 byte[] name = new byte[nameLen]; 71 DemultiplexInput.this.delegate.readFully(name); 72 int dataLen = delegate.read(); 73 byte[] data = new byte[dataLen]; 74 DemultiplexInput.this.delegate.readFully(data); 75 String chan = new String(name, "UTF-8"); 76 switch (chan) { 77 case "err": 78 err.write(data); 79 break; 80 case "out": 81 out.write(data); 82 break; 83 case "command": 84 for (byte b : data) { 85 command.write(Byte.toUnsignedInt(b)); 86 } 87 break; 88 default: { 89 Matcher mat = AUX_FORMAT.matcher(chan); 90 if (mat.matches()) { 91 int i = Integer.parseInt(mat.group(1)); 92 if (i >= 1 && i < aux.length) { 93 aux[i-1].write(data); 94 log.debug("WROTE on %s : %s", chan, data); 95 break; 96 } 97 } 98 log.debug("Unexpected channel name: %s", chan); 99 break; 100 } 101 } 102 } 103 } catch (IOException ex) { 104 log.debug(ex, "Failed reading output"); 105 } finally { 106 command.close(); 107 } 108 } 109 110 }