8129114: Sjavac should stream back compiler output to the client as soon as it becomes available
Summary: Protocol revised, javac output sent back to client slightly earlier.
Reviewed-by: jlahoda
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/AutoFlushWriter.java Fri Sep 04 13:24:15 2015 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.sjavac;
+
+import java.io.FilterWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+public class AutoFlushWriter extends FilterWriter {
+
+ public AutoFlushWriter(Writer out) {
+ super(out);
+ }
+
+ @Override
+ public void write(int c) throws IOException {
+ super.write(c);
+ if (c == '\n' || c == '\r')
+ flush();
+ }
+
+ @Override
+ public void write(String str, int off, int len) throws IOException {
+ super.write(str, off, len);
+ if (str.contains("\n") || str.contains("\r"))
+ flush();
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ super.write(cbuf, off, len);
+ for (char c : cbuf) {
+ if (c == '\n' || c == '\r') {
+ flush();
+ break;
+ }
+ }
+ }
+}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CleanProperties.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CleanProperties.java Fri Sep 04 13:24:15 2015 +0200
@@ -31,7 +31,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
-import java.io.PrintStream;
import java.io.Writer;
import java.net.URI;
import java.util.ArrayList;
@@ -78,8 +77,8 @@
int debugLevel,
boolean incremental,
int numCores,
- PrintStream out,
- PrintStream err) {
+ Writer out,
+ Writer err) {
boolean rc = true;
for (String pkgName : pkgSrcs.keySet()) {
String pkgNameF = pkgName.replace('.',File.separatorChar);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java Fri Sep 04 13:24:15 2015 +0200
@@ -26,14 +26,22 @@
package com.sun.tools.sjavac;
import java.io.File;
-import java.io.PrintStream;
+import java.io.IOException;
+import java.io.Writer;
import java.net.URI;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import com.sun.tools.sjavac.comp.CompilationService;
import com.sun.tools.sjavac.options.Options;
@@ -83,8 +91,8 @@
int debugLevel,
boolean incremental,
int numCores,
- final PrintStream out,
- final PrintStream err) {
+ final Writer out,
+ final Writer err) {
Log.debug("Performing CompileJavaPackages transform...");
@@ -200,102 +208,83 @@
}
}
- // The return values for each chunked compile.
- final CompilationSubResult[] rn = new CompilationSubResult[numCompiles];
- // The requets, might or might not run as a background thread.
- final Thread[] requests = new Thread[numCompiles];
-
long start = System.currentTimeMillis();
- for (int i=0; i<numCompiles; ++i) {
- final int ii = i;
- final CompileChunk cc = compileChunks[i];
-
- // Pass the num_cores and the id (appended with the chunk number) to the server.
- Object lock = new Object();
- requests[i] = new Thread() {
- @Override
- public void run() {
- rn[ii] = sjavac.compile("n/a",
- id + "-" + ii,
- args.prepJavacArgs(),
- Collections.<File>emptyList(),
- cc.srcs,
- visibleSources);
- // In the code below we have to keep in mind that two
- // different compilation results may include results for
- // the same package.
- synchronized (lock) {
-
- for (String pkg : rn[ii].packageArtifacts.keySet()) {
- Set<URI> pkgArtifacts = rn[ii].packageArtifacts.get(pkg);
- packageArtifacts.merge(pkg, pkgArtifacts, Util::union);
- }
-
- for (String pkg : rn[ii].packageDependencies.keySet()) {
- packageDependencies.putIfAbsent(pkg, new HashMap<>());
- packageDependencies.get(pkg).putAll(rn[ii].packageDependencies.get(pkg));
- }
-
- for (String pkg : rn[ii].packageCpDependencies.keySet()) {
- packageCpDependencies.putIfAbsent(pkg, new HashMap<>());
- packageCpDependencies.get(pkg).putAll(rn[ii].packageCpDependencies.get(pkg));
- }
+ // Prepare compilation calls
+ List<Callable<CompilationSubResult>> compilationCalls = new ArrayList<>();
+ final Object lock = new Object();
+ for (int i = 0; i < numCompiles; i++) {
+ CompileChunk cc = compileChunks[i];
+ if (cc.srcs.isEmpty()) {
+ continue;
+ }
- for (String pkg : rn[ii].packagePubapis.keySet()) {
- packagePubapis.merge(pkg, rn[ii].packagePubapis.get(pkg), PubApi::mergeTypes);
- }
-
- for (String pkg : rn[ii].dependencyPubapis.keySet()) {
- dependencyPubapis.merge(pkg, rn[ii].dependencyPubapis.get(pkg), PubApi::mergeTypes);
- }
- }
+ String chunkId = id + "-" + String.valueOf(i);
+ compilationCalls.add(() -> {
+ CompilationSubResult result = sjavac.compile("n/a",
+ chunkId,
+ args.prepJavacArgs(),
+ Collections.<File>emptyList(),
+ cc.srcs,
+ visibleSources);
+ synchronized (lock) {
+ safeWrite(result.stdout, out);
+ safeWrite(result.stderr, err);
}
- };
+ return result;
+ });
+ }
- if (cc.srcs.size() > 0) {
- String numdeps = "";
- if (cc.numDependents > 0) numdeps = "(with "+cc.numDependents+" dependents) ";
- if (!incremental || cc.numPackages > 16) {
- String info = "("+cc.pkgFromTos+")";
- if (info.equals("( to )")) {
- info = "";
- }
- Log.info("Compiling "+cc.srcs.size()+" files "+numdeps+"in "+cc.numPackages+" packages "+info);
- } else {
- Log.info("Compiling "+cc.pkgNames+numdeps);
- }
- if (concurrentCompiles) {
- requests[ii].start();
- }
- else {
- requests[ii].run();
- // If there was an error, then stop early when running single threaded.
- if (rn[i].returnCode != 0) {
- Log.info(rn[i].stdout);
- Log.error(rn[i].stderr);
- return false;
- }
- }
+ // Perform compilations and collect results
+ List<CompilationSubResult> subResults = new ArrayList<>();
+ List<Future<CompilationSubResult>> futs = new ArrayList<>();
+ ExecutorService exec = Executors.newFixedThreadPool(concurrentCompiles ? compilationCalls.size() : 1);
+ for (Callable<CompilationSubResult> compilationCall : compilationCalls) {
+ futs.add(exec.submit(compilationCall));
+ }
+ for (Future<CompilationSubResult> fut : futs) {
+ try {
+ subResults.add(fut.get());
+ } catch (ExecutionException ee) {
+ Log.error("Compilation failed: " + ee.getMessage());
+ } catch (InterruptedException ee) {
+ Log.error("Compilation interrupted: " + ee.getMessage());
+ Thread.currentThread().interrupt();
}
}
- if (concurrentCompiles) {
- // If there are background threads for the concurrent compiles, then join them.
- for (int i=0; i<numCompiles; ++i) {
- try { requests[i].join(); } catch (InterruptedException e) { }
+ exec.shutdownNow();
+
+ // Process each sub result
+ for (CompilationSubResult subResult : subResults) {
+ for (String pkg : subResult.packageArtifacts.keySet()) {
+ Set<URI> pkgArtifacts = subResult.packageArtifacts.get(pkg);
+ packageArtifacts.merge(pkg, pkgArtifacts, Util::union);
+ }
+
+ for (String pkg : subResult.packageDependencies.keySet()) {
+ packageDependencies.putIfAbsent(pkg, new HashMap<>());
+ packageDependencies.get(pkg).putAll(subResult.packageDependencies.get(pkg));
+ }
+
+ for (String pkg : subResult.packageCpDependencies.keySet()) {
+ packageCpDependencies.putIfAbsent(pkg, new HashMap<>());
+ packageCpDependencies.get(pkg).putAll(subResult.packageCpDependencies.get(pkg));
+ }
+
+ for (String pkg : subResult.packagePubapis.keySet()) {
+ packagePubapis.merge(pkg, subResult.packagePubapis.get(pkg), PubApi::mergeTypes);
+ }
+
+ for (String pkg : subResult.dependencyPubapis.keySet()) {
+ dependencyPubapis.merge(pkg, subResult.dependencyPubapis.get(pkg), PubApi::mergeTypes);
+ }
+
+ // Check the return values.
+ if (subResult.returnCode != 0) {
+ rc = false;
}
}
- // Check the return values.
- for (int i=0; i<numCompiles; ++i) {
- if (compileChunks[i].srcs.size() > 0) {
- if (rn[i].returnCode != 0) {
- Log.info(rn[i].stdout);
- Log.error(rn[i].stderr);
- rc = false;
- }
- }
- }
long duration = System.currentTimeMillis() - start;
long minutes = duration/60000;
long seconds = (duration-minutes*60000)/1000;
@@ -304,6 +293,16 @@
return rc;
}
+ private void safeWrite(String str, Writer w) {
+ if (str.length() > 0) {
+ try {
+ w.write(str);
+ } catch (IOException e) {
+ Log.error("Could not print compilation output.");
+ }
+ }
+ }
+
/**
* Split up the sources into compile chunks. If old package dependents information
* is available, sort the order of the chunks into the most dependent first!
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileProperties.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileProperties.java Fri Sep 04 13:24:15 2015 +0200
@@ -85,8 +85,8 @@
int debugLevel,
boolean incremental,
int numCores,
- PrintStream out,
- PrintStream err) {
+ Writer out,
+ Writer err) {
boolean rc = true;
for (String pkgName : pkgSrcs.keySet()) {
String pkgNameF = Util.toFileSystemPath(pkgName);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CopyFile.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CopyFile.java Fri Sep 04 13:24:15 2015 +0200
@@ -31,7 +31,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.PrintStream;
+import java.io.Writer;
import java.net.URI;
import java.util.HashSet;
import java.util.Map;
@@ -72,8 +72,8 @@
int debugLevel,
boolean incremental,
int numCores,
- PrintStream out,
- PrintStream err)
+ Writer out,
+ Writer err)
{
boolean rc = true;
String dest_filename;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/JavacState.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/JavacState.java Fri Sep 04 13:24:15 2015 +0200
@@ -31,7 +31,7 @@
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
-import java.io.PrintStream;
+import java.io.Writer;
import java.net.URI;
import java.nio.file.NoSuchFileException;
import java.text.SimpleDateFormat;
@@ -131,12 +131,12 @@
private CompileJavaPackages compileJavaPackages = new CompileJavaPackages();
// Where to send stdout and stderr.
- private PrintStream out, err;
+ private Writer out, err;
// Command line options.
private Options options;
- JavacState(Options op, boolean removeJavacState, PrintStream o, PrintStream e) {
+ JavacState(Options op, boolean removeJavacState, Writer o, Writer e) {
options = op;
out = o;
err = e;
@@ -311,7 +311,7 @@
/**
* Load a javac_state file.
*/
- public static JavacState load(Options options, PrintStream out, PrintStream err) {
+ public static JavacState load(Options options, Writer out, Writer err) {
JavacState db = new JavacState(options, false, out, err);
Module lastModule = null;
Package lastPackage = null;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Log.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Log.java Fri Sep 04 13:24:15 2015 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,8 @@
package com.sun.tools.sjavac;
-import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Writer;
/**
* Utility class only for sjavac logging.
@@ -37,7 +38,7 @@
* deletion without notice.</b>
*/
public class Log {
- private static PrintStream out, err;
+ private static PrintWriter out, err;
public final static int WARN = 1;
public final static int INFO = 2;
@@ -71,9 +72,9 @@
err.println(msg);
}
- static public void initializeLog(PrintStream o, PrintStream e) {
- out = o;
- err = e;
+ static public void initializeLog(Writer o, Writer e) {
+ out = new PrintWriter(o);
+ err = new PrintWriter(e);
}
static public void setLogLevel(String l) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Transformer.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Transformer.java Fri Sep 04 13:24:15 2015 +0200
@@ -25,7 +25,7 @@
package com.sun.tools.sjavac;
-import java.io.PrintStream;
+import java.io.Writer;
import java.net.URI;
import java.util.Map;
import java.util.Set;
@@ -97,8 +97,8 @@
int debugLevel,
boolean incremental,
int numCores,
- PrintStream out,
- PrintStream err);
+ Writer out,
+ Writer err);
void setExtra(String e);
void setExtra(Options args);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java Fri Sep 04 13:24:15 2015 +0200
@@ -25,13 +25,14 @@
package com.sun.tools.sjavac.client;
-import java.io.PrintStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import com.sun.tools.sjavac.AutoFlushWriter;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.comp.SjavacImpl;
import com.sun.tools.sjavac.options.Options;
-import com.sun.tools.sjavac.server.CompilationResult;
import com.sun.tools.sjavac.server.Sjavac;
/**
@@ -43,10 +44,12 @@
public class ClientMain {
public static int run(String[] args) {
- return run(args, System.out, System.err);
+ return run(args,
+ new AutoFlushWriter(new OutputStreamWriter(System.out)),
+ new AutoFlushWriter(new OutputStreamWriter(System.err)));
}
- public static int run(String[] args, PrintStream out, PrintStream err) {
+ public static int run(String[] args, Writer out, Writer err) {
Log.initializeLog(out, err);
@@ -78,14 +81,11 @@
sjavac = new SjavacImpl();
}
- CompilationResult cr = sjavac.compile(args);
-
- out.print(cr.stdout);
- err.print(cr.stderr);
+ int rc = sjavac.compile(args, out, err);
if (!background)
sjavac.shutdown();
- return cr.returnCode;
+ return rc;
}
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/SjavacClient.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/SjavacClient.java Fri Sep 04 13:24:15 2015 +0200
@@ -25,11 +25,14 @@
package com.sun.tools.sjavac.client;
+import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Writer;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
@@ -43,7 +46,6 @@
import com.sun.tools.sjavac.options.OptionHelper;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.server.CompilationSubResult;
-import com.sun.tools.sjavac.server.CompilationResult;
import com.sun.tools.sjavac.server.PortFile;
import com.sun.tools.sjavac.server.Sjavac;
import com.sun.tools.sjavac.server.SjavacServer;
@@ -119,29 +121,47 @@
}
@Override
- public CompilationResult compile(String[] args) {
- CompilationResult result;
+ public int compile(String[] args, Writer stdout, Writer stderr) {
+ int result = -1;
try (Socket socket = tryConnect()) {
- // The ObjectInputStream constructor will block until the
- // corresponding ObjectOutputStream has written and flushed the
- // header, so it is important that the ObjectOutputStreams on server
- // and client are opened before the ObjectInputStreams.
- ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
- ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
- oos.writeObject(id);
- oos.writeObject(SjavacServer.CMD_COMPILE);
- oos.writeObject(args);
- oos.flush();
- result = (CompilationResult) ois.readObject();
- } catch (IOException | ClassNotFoundException ex) {
- Log.error("[CLIENT] Exception caught: " + ex);
- result = new CompilationResult(CompilationSubResult.ERROR_FATAL);
- result.stderr = Util.getStackTrace(ex);
+ PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
+ BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+
+ // Send args array to server
+ out.println(args.length);
+ for (String arg : args)
+ out.println(arg);
+ out.flush();
+
+ // Read server response line by line
+ String line;
+ while (null != (line = in.readLine())) {
+ String[] typeAndContent = line.split(":", 2);
+ String type = typeAndContent[0];
+ String content = typeAndContent[1];
+ switch (type) {
+ case SjavacServer.LINE_TYPE_STDOUT:
+ stdout.write(content);
+ stdout.write('\n');
+ break;
+ case SjavacServer.LINE_TYPE_STDERR:
+ stderr.write(content);
+ stderr.write('\n');
+ break;
+ case SjavacServer.LINE_TYPE_RC:
+ result = Integer.parseInt(content);
+ break;
+ }
+ }
+ } catch (IOException ioe) {
+ Log.error("[CLIENT] Exception caught: " + ioe);
+ result = CompilationSubResult.ERROR_FATAL;
+ ioe.printStackTrace(new PrintWriter(stderr));
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // Restore interrupt
Log.error("[CLIENT] compile interrupted.");
- result = new CompilationResult(CompilationSubResult.ERROR_FATAL);
- result.stderr = Util.getStackTrace(ie);
+ result = CompilationSubResult.ERROR_FATAL;
+ ie.printStackTrace(new PrintWriter(stderr));
}
return result;
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PooledSjavac.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PooledSjavac.java Fri Sep 04 13:24:15 2015 +0200
@@ -24,13 +24,13 @@
*/
package com.sun.tools.sjavac.comp;
+import java.io.Writer;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import com.sun.tools.sjavac.Log;
-import com.sun.tools.sjavac.server.CompilationResult;
import com.sun.tools.sjavac.server.Sjavac;
/**
@@ -54,10 +54,10 @@
}
@Override
- public CompilationResult compile(String[] args) {
+ public int compile(String[] args, Writer out, Writer err) {
try {
return pool.submit(() -> {
- return delegate.compile(args);
+ return delegate.compile(args, out, err);
}).get();
} catch (Exception e) {
e.printStackTrace();
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java Fri Sep 04 13:24:15 2015 +0200
@@ -24,12 +24,9 @@
*/
package com.sun.tools.sjavac.comp;
-import static com.sun.tools.sjavac.server.CompilationResult.ERROR_FATAL;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -49,7 +46,6 @@
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.options.SourceLocation;
-import com.sun.tools.sjavac.server.CompilationResult;
import com.sun.tools.sjavac.server.Sjavac;
/**
@@ -64,39 +60,33 @@
public class SjavacImpl implements Sjavac {
@Override
- public CompilationResult compile(String[] args) {
-
- ByteArrayOutputStream outBaos = new ByteArrayOutputStream();
- ByteArrayOutputStream errBaos = new ByteArrayOutputStream();
- PrintStream out = new PrintStream(outBaos);
- PrintStream err = new PrintStream(errBaos);
-
+ public int compile(String[] args, Writer out, Writer err) {
Options options;
try {
options = Options.parseArgs(args);
} catch (IllegalArgumentException e) {
Log.error(e.getMessage());
- return new CompilationResult(ERROR_FATAL);
+ return RC_FATAL;
}
Log.setLogLevel(options.getLogLevel());
if (!validateOptions(options))
- return new CompilationResult(ERROR_FATAL);
+ return RC_FATAL;
if (!createIfMissing(options.getDestDir()))
- return new CompilationResult(ERROR_FATAL);
+ return RC_FATAL;
if (!createIfMissing(options.getStateDir()))
- return new CompilationResult(ERROR_FATAL);
+ return RC_FATAL;
Path gensrc = options.getGenSrcDir();
if (gensrc != null && !createIfMissing(gensrc))
- return new CompilationResult(ERROR_FATAL);
+ return RC_FATAL;
Path hdrdir = options.getHeaderDir();
if (hdrdir != null && !createIfMissing(hdrdir))
- return new CompilationResult(ERROR_FATAL);
+ return RC_FATAL;
// Load the prev build state database.
JavacState javac_state = JavacState.load(options, out, err);
@@ -132,9 +122,7 @@
if (sources.isEmpty()) {
Log.error("Found nothing to compile!");
- return new CompilationResult(CompilationResult.ERROR_FATAL,
- new String(outBaos.toByteArray(), UTF_8),
- new String(errBaos.toByteArray(), UTF_8));
+ return RC_FATAL;
}
@@ -251,19 +239,13 @@
javac_state.removeSuperfluousArtifacts(recently_compiled);
}
- return new CompilationResult(rc[0] ? 0 : ERROR_FATAL,
- new String(outBaos.toByteArray(), UTF_8),
- new String(errBaos.toByteArray(), UTF_8));
+ return rc[0] ? RC_OK : RC_FATAL;
} catch (ProblemException e) {
Log.error(e.getMessage());
- return new CompilationResult(ERROR_FATAL,
- new String(outBaos.toByteArray(), UTF_8),
- new String(errBaos.toByteArray(), UTF_8));
+ return RC_FATAL;
} catch (Exception e) {
- e.printStackTrace(err);
- return new CompilationResult(ERROR_FATAL,
- new String(outBaos.toByteArray(), UTF_8),
- new String(errBaos.toByteArray(), UTF_8));
+ e.printStackTrace(new PrintWriter(err));
+ return RC_FATAL;
}
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/CompilationResult.java Wed Jul 05 20:48:33 2017 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.tools.sjavac.server;
-
-import java.io.Serializable;
-
-/**
- * <p><b>This is NOT part of any supported API.
- * If you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.</b>
- */
-public class CompilationResult implements Serializable {
-
- static final long serialVersionUID = 46739181113L;
-
- // Return code constants
- public final static int ERROR_FATAL = -1;
-
- public String stdout;
- public String stderr;
- public int returnCode;
-
- public CompilationResult(int returnCode) {
- this(returnCode, "", "");
- }
-
- public CompilationResult(int returnCode, String stdout, String stderr) {
- this.returnCode = returnCode;
- this.stdout = stdout;
- this.stderr = stderr;
- }
-
- public void setReturnCode(int returnCode) {
- this.returnCode = returnCode;
- }
-}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/IdleResetSjavac.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/IdleResetSjavac.java Fri Sep 04 13:24:15 2015 +0200
@@ -24,6 +24,7 @@
*/
package com.sun.tools.sjavac.server;
+import java.io.Writer;
import java.util.Timer;
import java.util.TimerTask;
@@ -60,10 +61,10 @@
}
@Override
- public CompilationResult compile(String[] args) {
+ public int compile(String[] args, Writer out, Writer err) {
startCall();
try {
- return delegate.compile(args);
+ return delegate.compile(args, out, err);
} finally {
endCall();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/LinePrefixFilterWriter.java Fri Sep 04 13:24:15 2015 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.sjavac.server;
+
+import java.io.FilterWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Inserts {@literal prefix} in front of each line written.
+ *
+ * A line is considered to be terminated by any one of a line feed, a carriage
+ * return, or a carriage return followed immediately by a line feed.
+ */
+public class LinePrefixFilterWriter extends FilterWriter {
+
+ private final String prefix;
+ private boolean atBeginningOfLine = true;
+ private char lastChar = '\0';
+
+ protected LinePrefixFilterWriter(Writer out, String prefix) {
+ super(out);
+ this.prefix = prefix;
+ }
+
+ @Override
+ public void write(String str, int off, int len) throws IOException {
+ for (int i = 0; i < len; i++) {
+ write(str.charAt(off + i));
+ }
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ for (int i = 0; i < len; i++) {
+ write(cbuf[off + i]);
+ }
+ }
+
+ @Override
+ public void write(int c) throws IOException {
+ if (lastChar == '\r' && c == '\n') {
+ // Second character of CR+LF sequence.
+ // Do nothing. We already started a new line on last character.
+ } else {
+ if (atBeginningOfLine) {
+ super.write(prefix, 0, prefix.length());
+ }
+ super.write(c);
+ atBeginningOfLine = c == '\r' || c == '\n';
+ }
+ lastChar = (char) c;
+ }
+}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/RequestHandler.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/RequestHandler.java Fri Sep 04 13:24:15 2015 +0200
@@ -24,15 +24,21 @@
*/
package com.sun.tools.sjavac.server;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
+import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_RC;
+import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_STDERR;
+import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_STDOUT;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.io.Writer;
import java.net.Socket;
+import com.sun.tools.sjavac.AutoFlushWriter;
import com.sun.tools.sjavac.Log;
+
/**
* A RequestHandler handles requests performed over a socket. Specifically it
* - Reads the command string specifying which method is to be invoked
@@ -61,15 +67,26 @@
@Override
public void run() {
- try (ObjectOutputStream oout = new ObjectOutputStream(socket.getOutputStream());
- ObjectInputStream oin = new ObjectInputStream(socket.getInputStream())) {
- String id = (String) oin.readObject();
- String cmd = (String) oin.readObject();
- Log.info("Handling request, id: " + id + " cmd: " + cmd);
- switch (cmd) {
- case SjavacServer.CMD_COMPILE: handleCompileRequest(oin, oout); break;
- default: Log.error("Unknown command: " + cmd);
+ try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
+
+ // Read argument array
+ int n = Integer.parseInt(in.readLine());
+ String[] args = new String[n];
+ for (int i = 0; i < n; i++) {
+ args[i] = in.readLine();
}
+
+ // Perform compilation
+ Writer stdout = new LinePrefixFilterWriter(new AutoFlushWriter(out), LINE_TYPE_STDOUT + ":");
+ Writer stderr = new LinePrefixFilterWriter(new AutoFlushWriter(out), LINE_TYPE_STDERR + ":");
+ int rc = sjavac.compile(args, stdout, stderr);
+ stdout.flush();
+ stderr.flush();
+
+ // Send return code back to client
+ out.println(LINE_TYPE_RC + ":" + rc);
+
} catch (Exception ex) {
// Not much to be done at this point. The client side request
// code will most likely throw an IOException and the
@@ -79,21 +96,4 @@
Log.error(sw.toString());
}
}
-
- private void handleCompileRequest(ObjectInputStream oin,
- ObjectOutputStream oout) throws IOException {
- try {
- // Read request arguments
- String[] args = (String[]) oin.readObject();
-
- // Perform compilation
- CompilationResult cr = sjavac.compile(args);
-
- // Write request response
- oout.writeObject(cr);
- oout.flush();
- } catch (ClassNotFoundException cnfe) {
- throw new IOException(cnfe);
- }
- }
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/ServerMain.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/ServerMain.java Fri Sep 04 13:24:15 2015 +0200
@@ -26,6 +26,7 @@
package com.sun.tools.sjavac.server;
import java.io.IOException;
+import java.io.OutputStreamWriter;
import com.sun.tools.sjavac.Log;
@@ -38,7 +39,8 @@
public class ServerMain {
public static int run(String[] args) {
- Log.initializeLog(System.out, System.err);
+ Log.initializeLog(new OutputStreamWriter(System.out),
+ new OutputStreamWriter(System.err));
// Any options other than --startserver?
if (args.length > 1) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/Sjavac.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/Sjavac.java Fri Sep 04 13:24:15 2015 +0200
@@ -24,6 +24,8 @@
*/
package com.sun.tools.sjavac.server;
+import java.io.Writer;
+
/**
* Interface of the SjavacImpl, the sjavac client and all wrappers such as
@@ -35,6 +37,10 @@
* deletion without notice.</b>
*/
public interface Sjavac {
- CompilationResult compile(String[] args);
+
+ final static int RC_FATAL = -1;
+ final static int RC_OK = 0;
+
+ int compile(String[] args, Writer stdout, Writer stderr);
void shutdown();
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java Fri Sep 04 13:24:15 2015 +0200
@@ -53,8 +53,10 @@
*/
public class SjavacServer implements Terminable {
- // Used in protocol to indicate which method to invoke
- public final static String CMD_COMPILE = "compile";
+ // Used in protocol to tell the content of each line
+ public final static String LINE_TYPE_RC = "RC";
+ public final static String LINE_TYPE_STDOUT = "STDOUT";
+ public final static String LINE_TYPE_STDERR = "STDERR";
final private String portfilename;
final private String logfile;
--- a/langtools/test/tools/sjavac/IdleShutdown.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/test/tools/sjavac/IdleShutdown.java Fri Sep 04 13:24:15 2015 +0200
@@ -29,9 +29,9 @@
* @build Wrapper
* @run main Wrapper IdleShutdown
*/
+import java.io.Writer;
import java.util.concurrent.atomic.AtomicLong;
-import com.sun.tools.sjavac.server.CompilationResult;
import com.sun.tools.sjavac.server.IdleResetSjavac;
import com.sun.tools.sjavac.server.Sjavac;
import com.sun.tools.sjavac.server.Terminable;
@@ -65,11 +65,11 @@
// Use Sjavac object and wait less than TIMEOUT_MS in between calls
Thread.sleep(TIMEOUT_MS - 1000);
log("Compiling");
- service.compile(new String[0]);
+ service.compile(new String[0], null, null);
Thread.sleep(TIMEOUT_MS - 1000);
log("Compiling");
- service.compile(new String[0]);
+ service.compile(new String[0], null, null);
if (timeoutTimestamp.get() != -1)
throw new AssertionError("Premature timeout detected.");
@@ -103,13 +103,13 @@
public void shutdown() {
}
@Override
- public CompilationResult compile(String[] args) {
+ public int compile(String[] args, Writer out, Writer err) {
// Attempt to trigger idle timeout during a call by sleeping
try {
Thread.sleep(TIMEOUT_MS + 1000);
} catch (InterruptedException e) {
}
- return null;
+ return 0;
}
}
}
--- a/langtools/test/tools/sjavac/PooledExecution.java Wed Jul 05 20:48:33 2017 +0200
+++ b/langtools/test/tools/sjavac/PooledExecution.java Fri Sep 04 13:24:15 2015 +0200
@@ -30,11 +30,11 @@
* @build Wrapper
* @run main Wrapper PooledExecution
*/
+import java.io.Writer;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import com.sun.tools.sjavac.comp.PooledSjavac;
-import com.sun.tools.sjavac.server.CompilationResult;
import com.sun.tools.sjavac.server.Sjavac;
@@ -67,7 +67,7 @@
for (int i = 0; i < NUM_REQUESTS; i++) {
tasks[i] = new Thread() {
public void run() {
- service.compile(new String[0]);
+ service.compile(new String[0], null, null);
tasksFinished.incrementAndGet();
}
};
@@ -109,7 +109,7 @@
AtomicInteger activeRequests = new AtomicInteger(0);
@Override
- public CompilationResult compile(String[] args) {
+ public int compile(String[] args, Writer out, Writer err) {
leftToStart.countDown();
int numActiveRequests = activeRequests.incrementAndGet();
System.out.printf("Left to start: %2d / Currently active: %2d%n",
@@ -123,7 +123,7 @@
}
activeRequests.decrementAndGet();
System.out.println("Task completed");
- return null;
+ return 0;
}
@Override