mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 02:54:35 +02:00
8129114: Sjavac should stream back compiler output to the client as soon as it becomes available
Protocol revised, javac output sent back to client slightly earlier. Reviewed-by: jlahoda
This commit is contained in:
parent
33994176ee
commit
ab159bb1f7
20 changed files with 337 additions and 246 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
|
@ -23,38 +23,40 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.sjavac.server;
|
||||
package com.sun.tools.sjavac;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.FilterWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* <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 {
|
||||
public class AutoFlushWriter extends FilterWriter {
|
||||
|
||||
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 AutoFlushWriter(Writer out) {
|
||||
super(out);
|
||||
}
|
||||
|
||||
public CompilationResult(int returnCode, String stdout, String stderr) {
|
||||
this.returnCode = returnCode;
|
||||
this.stdout = stdout;
|
||||
this.stderr = stderr;
|
||||
@Override
|
||||
public void write(int c) throws IOException {
|
||||
super.write(c);
|
||||
if (c == '\n' || c == '\r')
|
||||
flush();
|
||||
}
|
||||
|
||||
public void setReturnCode(int returnCode) {
|
||||
this.returnCode = returnCode;
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,6 @@ import java.io.FileInputStream;
|
|||
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 @@ public class CleanProperties implements Transformer {
|
|||
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);
|
||||
|
|
|
@ -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 @@ public class CompileJavaPackages implements Transformer {
|
|||
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 @@ public class CompileJavaPackages implements Transformer {
|
|||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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,
|
||||
String chunkId = id + "-" + String.valueOf(i);
|
||||
compilationCalls.add(() -> {
|
||||
CompilationSubResult result = sjavac.compile("n/a",
|
||||
chunkId,
|
||||
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) {
|
||||
safeWrite(result.stdout, out);
|
||||
safeWrite(result.stderr, err);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
for (String pkg : rn[ii].packageArtifacts.keySet()) {
|
||||
Set<URI> pkgArtifacts = rn[ii].packageArtifacts.get(pkg);
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
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 : rn[ii].packageDependencies.keySet()) {
|
||||
for (String pkg : subResult.packageDependencies.keySet()) {
|
||||
packageDependencies.putIfAbsent(pkg, new HashMap<>());
|
||||
packageDependencies.get(pkg).putAll(rn[ii].packageDependencies.get(pkg));
|
||||
packageDependencies.get(pkg).putAll(subResult.packageDependencies.get(pkg));
|
||||
}
|
||||
|
||||
for (String pkg : rn[ii].packageCpDependencies.keySet()) {
|
||||
for (String pkg : subResult.packageCpDependencies.keySet()) {
|
||||
packageCpDependencies.putIfAbsent(pkg, new HashMap<>());
|
||||
packageCpDependencies.get(pkg).putAll(rn[ii].packageCpDependencies.get(pkg));
|
||||
packageCpDependencies.get(pkg).putAll(subResult.packageCpDependencies.get(pkg));
|
||||
}
|
||||
|
||||
for (String pkg : rn[ii].packagePubapis.keySet()) {
|
||||
packagePubapis.merge(pkg, rn[ii].packagePubapis.get(pkg), PubApi::mergeTypes);
|
||||
for (String pkg : subResult.packagePubapis.keySet()) {
|
||||
packagePubapis.merge(pkg, subResult.packagePubapis.get(pkg), PubApi::mergeTypes);
|
||||
}
|
||||
|
||||
for (String pkg : rn[ii].dependencyPubapis.keySet()) {
|
||||
dependencyPubapis.merge(pkg, rn[ii].dependencyPubapis.get(pkg), PubApi::mergeTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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) { }
|
||||
}
|
||||
for (String pkg : subResult.dependencyPubapis.keySet()) {
|
||||
dependencyPubapis.merge(pkg, subResult.dependencyPubapis.get(pkg), PubApi::mergeTypes);
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (subResult.returnCode != 0) {
|
||||
rc = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
long minutes = duration/60000;
|
||||
long seconds = (duration-minutes*60000)/1000;
|
||||
|
@ -304,6 +293,16 @@ public class CompileJavaPackages implements Transformer {
|
|||
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!
|
||||
|
|
|
@ -85,8 +85,8 @@ public class CompileProperties implements Transformer {
|
|||
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);
|
||||
|
|
|
@ -31,7 +31,7 @@ import java.io.FileOutputStream;
|
|||
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 @@ public class CopyFile implements Transformer {
|
|||
int debugLevel,
|
||||
boolean incremental,
|
||||
int numCores,
|
||||
PrintStream out,
|
||||
PrintStream err)
|
||||
Writer out,
|
||||
Writer err)
|
||||
{
|
||||
boolean rc = true;
|
||||
String dest_filename;
|
||||
|
|
|
@ -31,7 +31,7 @@ import java.io.FileNotFoundException;
|
|||
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 @@ public class JavacState {
|
|||
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 @@ public class JavacState {
|
|||
/**
|
||||
* 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;
|
||||
|
|
|
@ -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 @@ import java.io.PrintStream;
|
|||
* 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 @@ public class Log {
|
|||
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) {
|
||||
|
|
|
@ -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 @@ public interface Transformer {
|
|||
int debugLevel,
|
||||
boolean incremental,
|
||||
int numCores,
|
||||
PrintStream out,
|
||||
PrintStream err);
|
||||
Writer out,
|
||||
Writer err);
|
||||
|
||||
void setExtra(String e);
|
||||
void setExtra(Options args);
|
||||
|
|
|
@ -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 @@ import com.sun.tools.sjavac.server.Sjavac;
|
|||
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 @@ public class ClientMain {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.Util;
|
|||
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 @@ public class SjavacClient implements Sjavac {
|
|||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
|
|
@ -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 @@ public class PooledSjavac implements Sjavac {
|
|||
}
|
||||
|
||||
@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();
|
||||
|
|
|
@ -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.Transformer;
|
|||
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 @@ import com.sun.tools.sjavac.server.Sjavac;
|
|||
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 @@ public class SjavacImpl implements Sjavac {
|
|||
|
||||
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 @@ public class SjavacImpl implements Sjavac {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 @@ public class IdleResetSjavac implements Sjavac {
|
|||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 @@ public class RequestHandler implements Runnable {
|
|||
|
||||
@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 @@ public class RequestHandler implements Runnable {
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 @@ import com.sun.tools.sjavac.Log;
|
|||
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) {
|
||||
|
|
|
@ -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 @@ package com.sun.tools.sjavac.server;
|
|||
* 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();
|
||||
}
|
||||
|
|
|
@ -53,8 +53,10 @@ import com.sun.tools.sjavac.comp.SjavacImpl;
|
|||
*/
|
||||
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;
|
||||
|
|
|
@ -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 @@ public class IdleShutdown {
|
|||
// 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 class IdleShutdown {
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 @@ public class PooledExecution {
|
|||
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 @@ public class PooledExecution {
|
|||
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 @@ public class PooledExecution {
|
|||
}
|
||||
activeRequests.decrementAndGet();
|
||||
System.out.println("Task completed");
|
||||
return null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue