8048594: The sjavac client/server protocol should be hidden behind an interface
Reviewed-by: jfranck
--- a/langtools/src/share/classes/com/sun/tools/sjavac/CleanProperties.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/CleanProperties.java Tue Jun 17 14:01:27 2014 +0200
@@ -36,6 +36,7 @@
import java.util.Properties;
import com.sun.tools.sjavac.options.Options;
+import com.sun.tools.sjavac.server.JavacService;
/**
* The clean properties transform should not be necessary.
@@ -56,7 +57,8 @@
// Any extra information is ignored for clean properties.
}
- public boolean transform(Map<String,Set<URI>> pkgSrcs,
+ public boolean transform(JavacService javacService,
+ Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<URI,Set<String>> visibleClasses,
Map<String,Set<String>> oldPackageDependencies,
--- a/langtools/src/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java Tue Jun 17 14:01:27 2014 +0200
@@ -25,15 +25,18 @@
package com.sun.tools.sjavac;
+import java.io.File;
import java.io.PrintStream;
import java.net.URI;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Random;
import java.util.Set;
import java.util.Map;
import com.sun.tools.sjavac.options.Options;
-import com.sun.tools.sjavac.server.JavacServer;
+import com.sun.tools.sjavac.server.CompilationResult;
+import com.sun.tools.sjavac.server.JavacService;
import com.sun.tools.sjavac.server.SysInfo;
/**
@@ -64,9 +67,10 @@
args = a;
}
- public boolean transform(Map<String,Set<URI>> pkgSrcs,
- Set<URI> visibleSources,
- Map<URI,Set<String>> visibleClasses,
+ public boolean transform(final JavacService javacService,
+ Map<String,Set<URI>> pkgSrcs,
+ final Set<URI> visibleSources,
+ final Map<URI,Set<String>> visibleClasses,
Map<String,Set<String>> oldPackageDependents,
URI destRoot,
final Map<String,Set<URI>> packageArtifacts,
@@ -75,24 +79,25 @@
int debugLevel,
boolean incremental,
int numCores,
- PrintStream out,
- PrintStream err)
+ final PrintStream out,
+ final PrintStream err)
{
boolean rc = true;
boolean concurrentCompiles = true;
// Fetch the id.
- String id = Util.extractStringOption("id", args.getServerConf());
- if (id == null || id.equals("")) {
+ String idOpt = Util.extractStringOption("id", args.getServerConf());
+ if (idOpt == null || idOpt.equals("")) {
// No explicit id set. Create a random id so that the requests can be
// grouped properly in the server.
- id = "id"+(((new Random()).nextLong())&Long.MAX_VALUE);
+ idOpt = "id"+(((new Random()).nextLong())&Long.MAX_VALUE);
}
+ final String id = idOpt;
// Only keep portfile and sjavac settings..
String psServerSettings = Util.cleanSubOptions(Util.set("portfile","sjavac","background","keepalive"), args.getServerConf());
// Get maximum heap size from the server!
- SysInfo sysinfo = JavacServer.connectGetSysInfo(psServerSettings, out, err);
+ SysInfo sysinfo = javacService.getSysInfo();
if (sysinfo.numCores == -1) {
Log.error("Could not query server for sysinfo!");
return false;
@@ -201,13 +206,10 @@
}
// The return values for each chunked compile.
- final int[] rn = new int[numCompiles];
+ final CompilationResult[] rn = new CompilationResult[numCompiles];
// The requets, might or might not run as a background thread.
final Thread[] requests = new Thread[numCompiles];
- final Set<URI> fvisible_sources = visibleSources;
- final Map<URI,Set<String>> fvisible_classes = visibleClasses;
-
long start = System.currentTimeMillis();
for (int i=0; i<numCompiles; ++i) {
@@ -215,23 +217,20 @@
final CompileChunk cc = compileChunks[i];
// Pass the num_cores and the id (appended with the chunk number) to the server.
- final String cleanedServerSettings = psServerSettings+",poolsize="+numCores+",id="+id+"-"+ii;
- final PrintStream fout = out;
- final PrintStream ferr = err;
+ final String cleanedServerSettings = psServerSettings+",poolsize="+numCores+",id="+id+"-"+i;
- requests[ii] = new Thread() {
+ requests[i] = new Thread() {
@Override
public void run() {
- rn[ii] = JavacServer.useServer(cleanedServerSettings,
- args.prepJavacArgs(),
- cc.srcs,
- fvisible_sources,
- fvisible_classes,
- packageArtifacts,
- packageDependencies,
- packagePubapis,
- null,
- fout, ferr);
+ rn[ii] = javacService.compile("n/a",
+ id + "-" + ii,
+ args.prepJavacArgs(),
+ Collections.<File>emptyList(),
+ cc.srcs,
+ visibleSources);
+ packageArtifacts.putAll(rn[ii].packageArtifacts);
+ packageDependencies.putAll(rn[ii].packageDependencies);
+ packagePubapis.putAll(rn[ii].packagePubapis);
}
};
@@ -253,7 +252,7 @@
else {
requests[ii].run();
// If there was an error, then stop early when running single threaded.
- if (rn[i] != 0) {
+ if (rn[i].returnCode != 0) {
return false;
}
}
@@ -269,7 +268,7 @@
// Check the return values.
for (int i=0; i<numCompiles; ++i) {
if (compileChunks[i].srcs.size() > 0) {
- if (rn[i] != 0) {
+ if (rn[i].returnCode != 0) {
rc = false;
}
}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/CompileProperties.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/CompileProperties.java Tue Jun 17 14:01:27 2014 +0200
@@ -38,6 +38,7 @@
import java.util.Map;
import com.sun.tools.sjavac.options.Options;
+import com.sun.tools.sjavac.server.JavacService;
/**
* Compile properties transform a properties file into a Java source file.
@@ -63,7 +64,8 @@
public void setExtra(Options a) {
}
- public boolean transform(Map<String,Set<URI>> pkgSrcs,
+ public boolean transform(JavacService javacService,
+ Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<URI,Set<String>> visibleClasses,
Map<String,Set<String>> oldPackageDependents,
--- a/langtools/src/share/classes/com/sun/tools/sjavac/CopyFile.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/CopyFile.java Tue Jun 17 14:01:27 2014 +0200
@@ -32,6 +32,7 @@
import java.util.Map;
import com.sun.tools.sjavac.options.Options;
+import com.sun.tools.sjavac.server.JavacService;
/**
* The copy file transform simply copies a matching file from -src to -d .
@@ -50,7 +51,8 @@
public void setExtra(Options a) {
}
- public boolean transform(Map<String,Set<URI>> pkgSrcs,
+ public boolean transform(JavacService javacService,
+ Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<URI,Set<String>> visibleClasses,
Map<String,Set<String>> oldPackageDependents,
--- a/langtools/src/share/classes/com/sun/tools/sjavac/JavacState.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/JavacState.java Tue Jun 17 14:01:27 2014 +0200
@@ -40,6 +40,7 @@
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.options.SourceLocation;
+import com.sun.tools.sjavac.server.JavacService;
/**
* The javac state class maintains the previous (prev) and the current (now)
@@ -625,7 +626,7 @@
sr.put(e.getKey(), e.getValue());
}
}
- perform(binDir, sr);
+ perform(null, binDir, sr);
}
/**
@@ -641,20 +642,21 @@
sr.put(e.getKey(), e.getValue());
}
- perform(gensrcDir, sr);
+ perform(null, gensrcDir, sr);
}
/**
* Compile all the java sources. Return true, if it needs to be called again!
*/
- public boolean performJavaCompilations(Options args,
+ public boolean performJavaCompilations(JavacService javacService,
+ Options args,
Set<String> recentlyCompiled,
boolean[] rcValue) {
Map<String,Transformer> suffixRules = new HashMap<>();
suffixRules.put(".java", compileJavaPackages);
compileJavaPackages.setExtra(args);
- rcValue[0] = perform(binDir, suffixRules);
+ rcValue[0] = perform(javacService, binDir, suffixRules);
recentlyCompiled.addAll(taintedPackages());
clearTaintedPackages();
boolean again = !packagesWithChangedPublicApis.isEmpty();
@@ -684,7 +686,9 @@
* For all packages, find all sources belonging to the package, group the sources
* based on their transformers and apply the transformers on each source code group.
*/
- private boolean perform(File outputDir, Map<String,Transformer> suffixRules)
+ private boolean perform(JavacService javacService,
+ File outputDir,
+ Map<String,Transformer> suffixRules)
{
boolean rc = true;
// Group sources based on transforms. A source file can only belong to a single transform.
@@ -709,7 +713,8 @@
Map<String,String> packagePublicApis =
Collections.synchronizedMap(new HashMap<String, String>());
- boolean r = t.transform(srcs,
+ boolean r = t.transform(javacService,
+ srcs,
visibleSrcs,
visibleClasses,
prev.dependents(),
--- a/langtools/src/share/classes/com/sun/tools/sjavac/Main.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/Main.java Tue Jun 17 14:01:27 2014 +0200
@@ -33,7 +33,9 @@
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.options.SourceLocation;
+import com.sun.tools.sjavac.server.JavacService;
import com.sun.tools.sjavac.server.JavacServer;
+import com.sun.tools.sjavac.server.JavacServiceClient;
/**
* The main class of the smart javac wrapper tool.
@@ -339,7 +341,12 @@
do {
// Clean out artifacts in tainted packages.
javac_state.deleteClassArtifactsInTaintedPackages();
- again = javac_state.performJavaCompilations(options, recently_compiled, rc);
+ // Create a JavacService to delegate the actual compilation to.
+ // Currently sjavac always connects to a server through a socket
+ // regardless if sjavac runs as a background service or not.
+ // This will most likely change in the future.
+ JavacService javacService = new JavacServiceClient(options.getServerConf());
+ again = javac_state.performJavaCompilations(javacService, options, recently_compiled, rc);
if (!rc[0]) break;
} while (again);
// Only update the state if the compile went well.
--- a/langtools/src/share/classes/com/sun/tools/sjavac/Transformer.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/Transformer.java Tue Jun 17 14:01:27 2014 +0200
@@ -31,6 +31,7 @@
import java.util.Map;
import com.sun.tools.sjavac.options.Options;
+import com.sun.tools.sjavac.server.JavacService;
/**
* The transform interface is used to transform content inside a package, from one form to another.
@@ -82,7 +83,8 @@
* If num_cores is set to a non-zero value. The transform should attempt to use no more than these
* number of threads for heavy work.
*/
- boolean transform(Map<String,Set<URI>> pkgSrcs,
+ boolean transform(JavacService javacService,
+ Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSources,
Map<URI,Set<String>> visibleClasses,
Map<String,Set<String>> oldPackageDependencies,
--- a/langtools/src/share/classes/com/sun/tools/sjavac/Util.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/Util.java Tue Jun 17 14:01:27 2014 +0200
@@ -26,6 +26,8 @@
package com.sun.tools.sjavac;
import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashSet;
@@ -67,17 +69,32 @@
}
public static String extractStringOption(String opName, String s) {
+ return extractStringOption(opName, s, null);
+ }
+
+ public static String extractStringOption(String opName, String s, String deflt) {
int p = s.indexOf(opName+"=");
- if (p == -1) return null;
+ if (p == -1) return deflt;
p+=opName.length()+1;
int pe = s.indexOf(',', p);
if (pe == -1) pe = s.length();
return s.substring(p, pe);
}
+ public static boolean extractBooleanOption(String opName, String s, boolean deflt) {
+ String str = extractStringOption(opName, s);
+ return "true".equals(str) ? true
+ : "false".equals(str) ? false
+ : deflt;
+ }
+
public static int extractIntOption(String opName, String s) {
+ return extractIntOption(opName, s, 0);
+ }
+
+ public static int extractIntOption(String opName, String s, int deflt) {
int p = s.indexOf(opName+"=");
- if (p == -1) return 0;
+ if (p == -1) return deflt;
p+=opName.length()+1;
int pe = s.indexOf(',', p);
if (pe == -1) pe = s.length();
--- a/langtools/src/share/classes/com/sun/tools/sjavac/comp/JavaCompilerWithDeps.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/JavaCompilerWithDeps.java Tue Jun 17 14:01:27 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -29,8 +29,6 @@
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
-import com.sun.tools.sjavac.server.CompilerThread;
-import java.io.File;
/** Subclass to Resolve that overrides collect.
*
@@ -44,16 +42,16 @@
/** The dependency database
*/
protected Dependencies deps;
- protected CompilerThread compilerThread;
+ protected JavacServiceImpl javacService;
- public JavaCompilerWithDeps(Context context, CompilerThread t) {
+ public JavaCompilerWithDeps(Context context, JavacServiceImpl jsi) {
super(context);
deps = Dependencies.instance(context);
- compilerThread = t;
+ javacService = jsi;
needRootClasses = true;
}
- public static void preRegister(Context context, final CompilerThread t) {
+ public static void preRegister(Context context, final JavacServiceImpl t) {
context.put(compilerKey, new Context.Factory<JavaCompiler>() {
public JavaCompiler make(Context c) {
JavaCompiler instance = new JavaCompilerWithDeps(c, t);
@@ -99,7 +97,7 @@
// Now check if the truncated uri ends with the path. (It does not == failure!)
if (path.length() > 0 && !path.equals("/unnamed package/") && !pp.endsWith(path)) {
- compilerThread.logError("Error: The source file "+sym.sourcefile.getName()+
+ javacService.logError("Error: The source file "+sym.sourcefile.getName()+
" is located in the wrong package directory, because it contains the class "+
sym.getQualifiedName());
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/JavacServiceImpl.java Tue Jun 17 14:01:27 2014 +0200
@@ -0,0 +1,121 @@
+package com.sun.tools.sjavac.comp;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import javax.tools.JavaCompiler.CompilationTask;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.sjavac.Util;
+import com.sun.tools.sjavac.server.CompilationResult;
+import com.sun.tools.sjavac.server.JavacServer;
+import com.sun.tools.sjavac.server.JavacService;
+import com.sun.tools.sjavac.server.SysInfo;
+
+public class JavacServiceImpl implements JavacService {
+
+ JavacServer javacServer;
+ private ThreadLocal<Boolean> forcedExit;
+
+ public JavacServiceImpl(JavacServer javacServer) {
+ this.javacServer = javacServer;
+
+ }
+
+ public void logError(String msg) {
+// stderr.println(msg);
+ forcedExit.set(true);
+ }
+
+ @Override
+ public SysInfo getSysInfo() {
+ return new SysInfo(Runtime.getRuntime().availableProcessors(),
+ Runtime.getRuntime().maxMemory());
+ }
+
+ @Override
+ public CompilationResult compile(String protocolId,
+ String invocationId,
+ String[] args,
+ List<File> explicitSources,
+ Set<URI> sourcesToCompile,
+ Set<URI> visibleSources) {
+
+ JavacTool compiler = JavacTool.create();
+ StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
+ SmartFileManager smartFileManager = new SmartFileManager(fileManager);
+ Context context = new Context();
+ ResolveWithDeps.preRegister(context);
+ AttrWithDeps.preRegister(context);
+ JavaCompilerWithDeps.preRegister(context, this);
+
+ // Now setup the actual compilation....
+ CompilationResult compilationResult = new CompilationResult(0);
+
+ // First deal with explicit source files on cmdline and in at file.
+ ListBuffer<JavaFileObject> compilationUnits = new ListBuffer<>();
+ for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(explicitSources)) {
+ compilationUnits.append(i);
+ }
+ // Now deal with sources supplied as source_to_compile.
+ ListBuffer<File> sourcesToCompileFiles = new ListBuffer<>();
+ for (URI u : sourcesToCompile) {
+ sourcesToCompileFiles.append(new File(u));
+ }
+ for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(sourcesToCompileFiles)) {
+ compilationUnits.append(i);
+ }
+ // Log the options to be used.
+ StringBuilder options = new StringBuilder();
+ for (String s : args) {
+ options.append(">").append(s).append("< ");
+ }
+ javacServer.log(protocolId+" <"+invocationId+"> options "+options.toString());
+
+ forcedExit.set(false);
+ // Create a new logger.
+ StringWriter stdoutLog = new StringWriter();
+ StringWriter stderrLog = new StringWriter();
+ PrintWriter stdout = new PrintWriter(stdoutLog);
+ PrintWriter stderr = new PrintWriter(stderrLog);
+ com.sun.tools.javac.main.Main.Result rc = com.sun.tools.javac.main.Main.Result.OK;
+ try {
+ if (compilationUnits.size() > 0) {
+ smartFileManager.setVisibleSources(visibleSources);
+ smartFileManager.cleanArtifacts();
+ smartFileManager.setLog(stdout);
+
+
+ // Do the compilation!
+ CompilationTask task = compiler.getTask(stderr, smartFileManager, null, Arrays.asList(args), null, compilationUnits, context);
+ rc = ((JavacTaskImpl) task).doCall();
+ smartFileManager.flush();
+ }
+ } catch (Exception e) {
+ stderr.println(e.getMessage());
+ forcedExit.set(true);
+ }
+
+ compilationResult.packageArtifacts = smartFileManager.getPackageArtifacts();
+
+ Dependencies deps = Dependencies.instance(context);
+ compilationResult.packageDependencies = deps.getDependencies();
+ compilationResult.packagePubapis = deps.getPubapis();
+
+ compilationResult.stdout = stdoutLog.toString();
+ compilationResult.stderr = stderrLog.toString();
+ compilationResult.returnCode = rc.exitCode == 0 && forcedExit.get() ? -1 : rc.exitCode;
+
+ return compilationResult;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/CompilationResult.java Tue Jun 17 14:01:27 2014 +0200
@@ -0,0 +1,30 @@
+package com.sun.tools.sjavac.server;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class CompilationResult {
+
+ // Return code constants
+ public final static int ERROR_BUT_TRY_AGAIN = -4712;
+ public final static int ERROR_FATAL = -1;
+
+ public int returnCode;
+ public Map<String, Set<URI>> packageArtifacts = new HashMap<>();
+ public Map<String, Set<String>> packageDependencies = new HashMap<>();
+ public Map<String, String> packagePubapis = new HashMap<>();
+ public SysInfo sysinfo;
+ public String stdout;
+ public String stderr;
+
+ public CompilationResult(int returnCode) {
+ this.returnCode = returnCode;
+ this.sysinfo = new SysInfo(-1, -1);
+ }
+
+ public void setReturnCode(int returnCode) {
+ this.returnCode = returnCode;
+ }
+}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/CompilerPool.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/CompilerPool.java Tue Jun 17 14:01:27 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -31,6 +31,8 @@
import java.util.Stack;
import java.util.concurrent.Future;
+import com.sun.tools.sjavac.comp.JavacServiceImpl;
+
/** The compiler pool maintains compiler threads.
*
* <p><b>This is NOT part of any supported API.
@@ -147,7 +149,7 @@
public CompilerThread grabCompilerThread() throws InterruptedException {
available.acquire();
if (compilers.empty()) {
- return new CompilerThread(this);
+ return new CompilerThread(this, new JavacServiceImpl(javacServer));
}
return compilers.pop();
}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/CompilerThread.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/CompilerThread.java Tue Jun 17 14:01:27 2014 +0200
@@ -55,6 +55,7 @@
import com.sun.tools.sjavac.comp.AttrWithDeps;
import com.sun.tools.sjavac.comp.Dependencies;
import com.sun.tools.sjavac.comp.JavaCompilerWithDeps;
+import com.sun.tools.sjavac.comp.JavacServiceImpl;
import com.sun.tools.sjavac.comp.ResolveWithDeps;
import com.sun.tools.sjavac.comp.SmartFileManager;
@@ -71,6 +72,7 @@
public class CompilerThread implements Runnable {
private JavacServer javacServer;
private CompilerPool compilerPool;
+ private JavacServiceImpl javacServiceImpl;
private List<Future<?>> subTasks;
// Communicating over this socket.
@@ -85,9 +87,10 @@
// If true, then this thread is serving a request.
private boolean inUse = false;
- CompilerThread(CompilerPool cp) {
+ CompilerThread(CompilerPool cp, JavacServiceImpl javacServiceImpl) {
compilerPool = cp;
javacServer = cp.getJavacServer();
+ this.javacServiceImpl = javacServiceImpl;
}
/**
@@ -131,7 +134,7 @@
context = new Context();
ResolveWithDeps.preRegister(context);
AttrWithDeps.preRegister(context);
- JavaCompilerWithDeps.preRegister(context, this);
+ JavaCompilerWithDeps.preRegister(context, javacServiceImpl);
subTasks = new ArrayList<>();
}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/JavacServer.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/JavacServer.java Tue Jun 17 14:01:27 2014 +0200
@@ -24,30 +24,22 @@
*/
package com.sun.tools.sjavac.server;
-import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
-import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.FileNotFoundException;
-import java.net.URI;
-import java.util.HashSet;
-import java.util.Set;
import java.util.HashMap;
import java.util.Map;
import java.net.InetAddress;
-import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
-import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Random;
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.ProblemException;
import java.io.*;
-import java.util.*;
/**
* The JavacServer class contains methods both to setup a server that responds to requests and methods to connect to this server.
@@ -73,8 +65,6 @@
// Though usually only one javac server is started by a client.
private static Map<String, PortFile> allPortFiles;
private static Map<String, Long> maxServerMemory;
- final static int ERROR_FATAL = -1;
- final static int ERROR_BUT_TRY_AGAIN = -4712;
final static String PROTOCOL_COOKIE_VERSION = "----THE-COOKIE-V2----";
final static String PROTOCOL_CWD = "----THE-CWD----";
final static String PROTOCOL_ID = "----THE-ID----";
@@ -99,7 +89,7 @@
/**
* Acquire the port file. Synchronized since several threads inside an smart javac wrapper client acquires the same port file at the same time.
*/
- private static synchronized PortFile getPortFile(String filename) throws FileNotFoundException {
+ public static synchronized PortFile getPortFile(String filename) throws FileNotFoundException {
if (allPortFiles == null) {
allPortFiles = new HashMap<>();
}
@@ -179,17 +169,12 @@
// and stderr are redirected already.
// The pool size is a limit the number of concurrent compiler threads used.
// The server might use less than these to avoid memory problems.
- int poolsize = Util.extractIntOption("poolsize", settings);
- if (poolsize <= 0) {
- // If not set, default to the number of cores.
- poolsize = Runtime.getRuntime().availableProcessors();
- }
+ int defaultPoolSize = Runtime.getRuntime().availableProcessors();
+ int poolsize = Util.extractIntOption("poolsize", settings, defaultPoolSize);
// How many seconds of inactivity will the server accept before quitting?
- int keepalive = Util.extractIntOption("keepalive", settings);
- if (keepalive <= 0) {
- keepalive = 120;
- }
+ int keepalive = Util.extractIntOption("keepalive", settings, 120);
+
// The port file is locked and the server port and cookie is written into it.
PortFile portFile = getPortFile(portfile);
JavacServer s;
@@ -220,134 +205,6 @@
}
/**
- * Dispatch a compilation request to a javac server.
- *
- * @param args are the command line args to javac and is allowed to contain source files, @file and other command line options to javac.
- *
- * The generated classes, h files and other artifacts from the javac invocation are stored by the javac server to disk.
- *
- * @param sources_to_compile The sources to compile.
- *
- * @param visibleSources If visible sources has a non zero size, then visible_sources are the only files in the file system that the javac server can see!
- * (Sources to compile are always visible.) The visible sources are those supplied by the (filtered) -sourcepath
- *
- * @param visibleClasses If visible classes for a specific root/jar has a non zero size, then visible_classes are the only class files that the javac server
- * can see, in that root/jar. It maps from a classpath root or a jar file to the set of visible classes for that root/jar.
- *
- * The server return meta data about the build in the following parameters.
- * @param package_artifacts, map from package name to set of created artifacts for that package.
- * @param package_dependencies, map from package name to set of packages that it depends upon.
- * @param package_pubapis, map from package name to unique string identifying its pub api.
- */
- public static int useServer(String settings, String[] args,
- Set<URI> sourcesToCompile,
- Set<URI> visibleSources,
- Map<URI, Set<String>> visibleClasses,
- Map<String, Set<URI>> packageArtifacts,
- Map<String, Set<String>> packageDependencies,
- Map<String, String> packagePubapis,
- SysInfo sysinfo,
- PrintStream out,
- PrintStream err) {
- try {
- // The id can perhaps be used in the future by the javac server to reuse the
- // JavaCompiler instance for several compiles using the same id.
- String id = Util.extractStringOption("id", settings);
- String portfile = Util.extractStringOption("portfile", settings);
- String logfile = Util.extractStringOption("logfile", settings);
- String stdouterrfile = Util.extractStringOption("stdouterrfile", settings);
- String background = Util.extractStringOption("background", settings);
- if (background == null || !background.equals("false")) {
- background = "true";
- }
- // The sjavac option specifies how the server part of sjavac is spawned.
- // If you have the experimental sjavac in your path, you are done. If not, you have
- // to point to a com.sun.tools.sjavac.Main that supports --startserver
- // for example by setting: sjavac=java%20-jar%20...javac.jar%com.sun.tools.sjavac.Main
- String sjavac = Util.extractStringOption("sjavac", settings);
- int poolsize = Util.extractIntOption("poolsize", settings);
- int keepalive = Util.extractIntOption("keepalive", settings);
-
- if (keepalive <= 0) {
- // Default keepalive for server is 120 seconds.
- // I.e. it will accept 120 seconds of inactivity before quitting.
- keepalive = 120;
- }
- if (portfile == null) {
- err.println("No portfile was specified!");
- return -1;
- }
- if (logfile == null) {
- logfile = portfile + ".javaclog";
- }
- if (stdouterrfile == null) {
- stdouterrfile = portfile + ".stdouterr";
- }
- // Default to sjavac and hope it is in the path.
- if (sjavac == null) {
- sjavac = "sjavac";
- }
-
- int attempts = 0;
- int rc = -1;
- do {
- PortFile port_file = getPortFile(portfile);
- synchronized (port_file) {
- port_file.lock();
- port_file.getValues();
- port_file.unlock();
- }
- if (!port_file.containsPortInfo()) {
- String cmd = fork(sjavac, port_file.getFilename(), logfile, poolsize, keepalive, err, stdouterrfile, background);
-
- if (background.equals("true") && !port_file.waitForValidValues()) {
- // Ouch the server did not start! Lets print its stdouterrfile and the command used.
- printFailedAttempt(cmd, stdouterrfile, err);
- // And give up.
- return -1;
- }
- }
- rc = connectAndCompile(port_file, id, args, sourcesToCompile, visibleSources,
- packageArtifacts, packageDependencies, packagePubapis, sysinfo,
- out, err);
- // Try again until we manage to connect. Any error after that
- // will cause the compilation to fail.
- if (rc == ERROR_BUT_TRY_AGAIN) {
- // We could not connect to the server. Try again.
- attempts++;
- try {
- Thread.sleep(WAIT_BETWEEN_CONNECT_ATTEMPTS * 1000);
- } catch (InterruptedException e) {
- }
- }
- } while (rc == ERROR_BUT_TRY_AGAIN && attempts < MAX_NUM_CONNECT_ATTEMPTS);
- return rc;
- } catch (Exception e) {
- e.printStackTrace(err);
- return -1;
- }
- }
-
- private static void printFailedAttempt(String cmd, String f, PrintStream err) {
- err.println("---- Failed to start javac server with this command -----");
- err.println(cmd);
- try {
- BufferedReader in = new BufferedReader(new FileReader(f));
- err.println("---- stdout/stderr output from attempt to start javac server -----");
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- break;
- }
- err.println(l);
- }
- err.println("------------------------------------------------------------------");
- } catch (Exception e) {
- err.println("The stdout/stderr output in file " + f + " does not exist and the server did not start.");
- }
- }
-
- /**
* Spawn the server instance.
*/
@@ -367,15 +224,15 @@
/**
* Fork a background process. Returns the command line used that can be printed if something failed.
*/
- private static String fork(String sjavac, String portfile, String logfile, int poolsize, int keepalive,
- final PrintStream err, String stdouterrfile, String background)
+ public static String fork(String sjavac, String portfile, String logfile, int poolsize, int keepalive,
+ final PrintStream err, String stdouterrfile, boolean background)
throws IOException, ProblemException {
if (stdouterrfile != null && stdouterrfile.trim().equals("")) {
stdouterrfile = null;
}
final String startserver = "--startserver:portfile=" + portfile + ",logfile=" + logfile + ",stdouterrfile=" + stdouterrfile + ",poolsize=" + poolsize + ",keepalive="+ keepalive;
- if (background.equals("true")) {
+ if (background) {
sjavac += "%20" + startserver;
sjavac = sjavac.replaceAll("%20", " ");
sjavac = sjavac.replaceAll("%2C", ",");
@@ -421,243 +278,6 @@
}
/**
- * Expect this key on the next line read from the reader.
- */
- private static boolean expect(BufferedReader in, String key) throws IOException {
- String s = in.readLine();
- if (s != null && s.equals(key)) {
- return true;
- }
- return false;
- }
-
- /**
- * Make a request to the server only to get the maximum possible heap size to use for compilations.
- *
- * @param port_file The port file used to synchronize creation of this server.
- * @param id The identify of the compilation.
- * @param out Standard out information.
- * @param err Standard err information.
- * @return The maximum heap size in bytes.
- */
- public static SysInfo connectGetSysInfo(String serverSettings, PrintStream out, PrintStream err) {
- SysInfo sysinfo = new SysInfo(-1, -1);
- String id = Util.extractStringOption("id", serverSettings);
- String portfile = Util.extractStringOption("portfile", serverSettings);
- try {
- PortFile pf = getPortFile(portfile);
- useServer(serverSettings, new String[0],
- new HashSet<URI>(),
- new HashSet<URI>(),
- new HashMap<URI, Set<String>>(),
- new HashMap<String, Set<URI>>(),
- new HashMap<String, Set<String>>(),
- new HashMap<String, String>(),
- sysinfo, out, err);
- } catch (Exception e) {
- e.printStackTrace(err);
- }
- return sysinfo;
- }
-
- /**
- * Connect and compile using the javac server settings and the args. When using more advanced features, the sources_to_compile and visible_sources are
- * supplied to the server and meta data is returned in package_artifacts, package_dependencies and package_pubapis.
- */
- private static int connectAndCompile(PortFile portFile, String id, String[] args,
- Set<URI> sourcesToCompile,
- Set<URI> visibleSources,
- Map<String, Set<URI>> packageArtifacts,
- Map<String, Set<String>> packageDependencies,
- Map<String, String> packagePublicApis,
- SysInfo sysinfo,
- PrintStream out,
- PrintStream err) {
- int rc = -3;
- try {
- int port = portFile.containsPortInfo() ? portFile.getPort() : 0;
- if (port == 0) {
- return ERROR_BUT_TRY_AGAIN;
- }
- long cookie = portFile.getCookie();
-
- // Acquire the localhost/127.0.0.1 address.
- InetAddress addr = InetAddress.getByName(null);
- SocketAddress sockaddr = new InetSocketAddress(addr, port);
- Socket sock = new Socket();
- int timeoutMs = CONNECTION_TIMEOUT * 1000;
- try {
- sock.connect(sockaddr, timeoutMs);
- } catch (java.net.ConnectException e) {
- err.println("Could not connect to javac server found in portfile: " + portFile.getFilename() + " " + e);
- return ERROR_BUT_TRY_AGAIN;
- }
- if (!sock.isConnected()) {
- err.println("Could not connect to javac server found in portfile: " + portFile.getFilename());
- return ERROR_BUT_TRY_AGAIN;
- }
- BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
- PrintWriter sockout = new PrintWriter(sock.getOutputStream());
-
- sockout.println(PROTOCOL_COOKIE_VERSION);
- sockout.println("" + cookie);
- sockout.println(PROTOCOL_CWD);
- sockout.println(System.getProperty("user.dir"));
- sockout.println(PROTOCOL_ID);
- sockout.println(id);
- sockout.println(PROTOCOL_ARGS);
- for (String s : args) {
- StringBuffer buf = new StringBuffer();
- String[] paths = s.split(File.pathSeparator);
- int c = 0;
- for (String path : paths) {
- File f = new File(path);
- if (f.isFile() || f.isDirectory()) {
- buf.append(f.getAbsolutePath());
- c++;
- if (c < paths.length) {
- buf.append(File.pathSeparator);
- }
- } else {
- buf = new StringBuffer(s);
- break;
- }
- }
- sockout.println(buf.toString());
- }
- sockout.println(PROTOCOL_SOURCES_TO_COMPILE);
- for (URI uri : sourcesToCompile) {
- sockout.println(uri.toString());
- }
- sockout.println(PROTOCOL_VISIBLE_SOURCES);
- for (URI uri : visibleSources) {
- sockout.println(uri.toString());
- }
- sockout.println(PROTOCOL_END);
- sockout.flush();
-
- StringBuffer stdout = new StringBuffer();
- StringBuffer stderr = new StringBuffer();
-
- if (!expect(in, PROTOCOL_STDOUT)) {
- return ERROR_FATAL;
- }
- // Load stdout
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return ERROR_FATAL;
- }
- if (l.equals(PROTOCOL_STDERR)) {
- break;
- }
- stdout.append(l);
- stdout.append('\n');
- }
- // Load stderr
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return ERROR_FATAL;
- }
- if (l.equals(PROTOCOL_PACKAGE_ARTIFACTS)) {
- break;
- }
- stderr.append(l);
- stderr.append('\n');
- }
- // Load the package artifacts
- Set<URI> lastUriSet = null;
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return ERROR_FATAL;
- }
- if (l.equals(PROTOCOL_PACKAGE_DEPENDENCIES)) {
- break;
- }
- if (l.length() > 1 && l.charAt(0) == '+') {
- String pkg = l.substring(1);
- lastUriSet = new HashSet<>();
- packageArtifacts.put(pkg, lastUriSet);
- } else if (l.length() > 1 && lastUriSet != null) {
- lastUriSet.add(new URI(l.substring(1)));
- }
- }
- // Load package dependencies
- Set<String> lastPackageSet = null;
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return ERROR_FATAL;
- }
- if (l.equals(PROTOCOL_PACKAGE_PUBLIC_APIS)) {
- break;
- }
- if (l.length() > 1 && l.charAt(0) == '+') {
- String pkg = l.substring(1);
- lastPackageSet = new HashSet<>();
- packageDependencies.put(pkg, lastPackageSet);
- } else if (l.length() > 1 && lastPackageSet != null) {
- lastPackageSet.add(l.substring(1));
- }
- }
- // Load package pubapis
- Map<String, StringBuffer> tmp = new HashMap<>();
- StringBuffer lastPublicApi = null;
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return ERROR_FATAL;
- }
- if (l.equals(PROTOCOL_SYSINFO)) {
- break;
- }
- if (l.length() > 1 && l.charAt(0) == '+') {
- String pkg = l.substring(1);
- lastPublicApi = new StringBuffer();
- tmp.put(pkg, lastPublicApi);
- } else if (l.length() > 1 && lastPublicApi != null) {
- lastPublicApi.append(l.substring(1));
- lastPublicApi.append("\n");
- }
- }
- for (String p : tmp.keySet()) {
- assert (packagePublicApis.get(p) == null);
- String api = tmp.get(p).toString();
- packagePublicApis.put(p, api);
- }
- // Now reading the max memory possible.
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return ERROR_FATAL;
- }
- if (l.equals(PROTOCOL_RETURN_CODE)) {
- break;
- }
- if (l.startsWith("num_cores=") && sysinfo != null) {
- sysinfo.numCores = Integer.parseInt(l.substring(10));
- }
- if (l.startsWith("max_memory=") && sysinfo != null) {
- sysinfo.maxMemory = Long.parseLong(l.substring(11));
- }
- }
- String l = in.readLine();
- if (l == null) {
- err.println("No return value from the server!");
- return ERROR_FATAL;
- }
- rc = Integer.parseInt(l);
- out.print(stdout);
- err.print(stderr);
- } catch (Exception e) {
- e.printStackTrace(err);
- }
- return rc;
- }
-
- /**
* Run the server thread until it exits. Either because of inactivity or because the port file has been deleted by someone else, or overtaken by some other
* javac server.
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/JavacService.java Tue Jun 17 14:01:27 2014 +0200
@@ -0,0 +1,18 @@
+package com.sun.tools.sjavac.server;
+
+import java.io.File;
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+
+public interface JavacService {
+
+ SysInfo getSysInfo();
+
+ CompilationResult compile(String protocolId,
+ String invocationId,
+ String[] args,
+ List<File> explicitSources,
+ Set<URI> sourcesToCompile,
+ Set<URI> visibleSources);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/JavacServiceClient.java Tue Jun 17 14:01:27 2014 +0200
@@ -0,0 +1,408 @@
+package com.sun.tools.sjavac.server;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.sun.tools.sjavac.Util;
+
+import static com.sun.tools.sjavac.server.CompilationResult.ERROR_BUT_TRY_AGAIN;
+import static com.sun.tools.sjavac.server.CompilationResult.ERROR_FATAL;
+
+public class JavacServiceClient implements JavacService {
+
+
+ // The id can perhaps be used in the future by the javac server to reuse the
+ // JavaCompiler instance for several compiles using the same id.
+ private final String id;
+ private final String portfile;
+ private final String logfile;
+ private final String stdouterrfile;
+ private final boolean background;
+
+ // Default keepalive for server is 120 seconds.
+ // I.e. it will accept 120 seconds of inactivity before quitting.
+ private final int keepalive;
+ private final int poolsize;
+
+ // The sjavac option specifies how the server part of sjavac is spawned.
+ // If you have the experimental sjavac in your path, you are done. If not, you have
+ // to point to a com.sun.tools.sjavac.Main that supports --startserver
+ // for example by setting: sjavac=java%20-jar%20...javac.jar%com.sun.tools.sjavac.Main
+ private final String sjavac;
+
+ public JavacServiceClient(String settings) {
+ id = Util.extractStringOption("id", settings);
+ portfile = Util.extractStringOption("portfile", settings);
+ logfile = Util.extractStringOption("logfile", settings, portfile + ".javaclog");
+ stdouterrfile = Util.extractStringOption("stdouterrfile", settings, portfile + ".stdouterr");
+ background = Util.extractBooleanOption("background", settings, true);
+ sjavac = Util.extractStringOption("sjavac", settings, "sjavac");
+ int poolsize = Util.extractIntOption("poolsize", settings);
+ keepalive = Util.extractIntOption("keepalive", settings, 120);
+
+ this.poolsize = poolsize > 0 ? poolsize : Runtime.getRuntime().availableProcessors();
+ }
+
+
+ /**
+ * Make a request to the server only to get the maximum possible heap size to use for compilations.
+ *
+ * @param port_file The port file used to synchronize creation of this server.
+ * @param id The identify of the compilation.
+ * @param out Standard out information.
+ * @param err Standard err information.
+ * @return The maximum heap size in bytes.
+ */
+ @Override
+ public SysInfo getSysInfo() {
+ try {
+ CompilationResult cr = useServer(new String[0],
+ Collections.<URI>emptySet(),
+ Collections.<URI>emptySet(),
+ Collections.<URI, Set<String>>emptyMap());
+ return cr.sysinfo;
+ } catch (Exception e) {
+ return new SysInfo(-1, -1);
+ }
+ }
+
+ @Override
+ public CompilationResult compile(String protocolId,
+ String invocationId,
+ String[] args,
+ List<File> explicitSources,
+ Set<URI> sourcesToCompile,
+ Set<URI> visibleSources) {
+ // Delegate to useServer, which delegates to compileHelper
+ return useServer(args, sourcesToCompile, visibleSources, null);
+ }
+
+ /**
+ * Connect and compile using the javac server settings and the args. When using more advanced features, the sources_to_compile and visible_sources are
+ * supplied to the server and meta data is returned in package_artifacts, package_dependencies and package_pubapis.
+ */
+ public CompilationResult compileHelper(String id,
+ String[] args,
+ Set<URI> sourcesToCompile,
+ Set<URI> visibleSources) {
+
+ CompilationResult rc = new CompilationResult(-3);
+
+ try {
+ PortFile portFile = JavacServer.getPortFile(this.portfile);
+
+ int port = portFile.containsPortInfo() ? portFile.getPort() : 0;
+ if (port == 0) {
+ return new CompilationResult(ERROR_BUT_TRY_AGAIN);
+ }
+ long cookie = portFile.getCookie();
+ // Acquire the localhost/127.0.0.1 address.
+ InetAddress addr = InetAddress.getByName(null);
+ SocketAddress sockaddr = new InetSocketAddress(addr, port);
+ Socket sock = new Socket();
+ int timeoutMs = JavacServer.CONNECTION_TIMEOUT * 1000;
+ try {
+ sock.connect(sockaddr, timeoutMs);
+ } catch (java.net.ConnectException e) {
+ rc.setReturnCode(ERROR_BUT_TRY_AGAIN);
+ rc.stderr = "Could not connect to javac server found in portfile: " + portFile.getFilename() + " " + e;
+ return rc;
+ }
+ if (!sock.isConnected()) {
+ rc.setReturnCode(ERROR_BUT_TRY_AGAIN);
+ rc.stderr = "Could not connect to javac server found in portfile: " + portFile.getFilename();
+ return rc;
+ }
+
+ //
+ // Send arguments
+ //
+ BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
+ PrintWriter sockout = new PrintWriter(sock.getOutputStream());
+
+ sockout.println(JavacServer.PROTOCOL_COOKIE_VERSION);
+ sockout.println("" + cookie);
+ sockout.println(JavacServer.PROTOCOL_CWD);
+ sockout.println(System.getProperty("user.dir"));
+ sockout.println(JavacServer.PROTOCOL_ID);
+ sockout.println(id);
+ sockout.println(JavacServer.PROTOCOL_ARGS);
+ for (String s : args) {
+ StringBuffer buf = new StringBuffer();
+ String[] paths = s.split(File.pathSeparator);
+ int c = 0;
+ for (String path : paths) {
+ File f = new File(path);
+ if (f.isFile() || f.isDirectory()) {
+ buf.append(f.getAbsolutePath());
+ c++;
+ if (c < paths.length) {
+ buf.append(File.pathSeparator);
+ }
+ } else {
+ buf = new StringBuffer(s);
+ break;
+ }
+ }
+ sockout.println(buf.toString());
+ }
+ sockout.println(JavacServer.PROTOCOL_SOURCES_TO_COMPILE);
+ for (URI uri : sourcesToCompile) {
+ sockout.println(uri.toString());
+ }
+ sockout.println(JavacServer.PROTOCOL_VISIBLE_SOURCES);
+ for (URI uri : visibleSources) {
+ sockout.println(uri.toString());
+ }
+ sockout.println(JavacServer.PROTOCOL_END);
+ sockout.flush();
+
+ //
+ // Receive result
+ //
+ StringBuffer stdout = new StringBuffer();
+ StringBuffer stderr = new StringBuffer();
+
+ if (!JavacServiceClient.expect(in, JavacServer.PROTOCOL_STDOUT)) {
+ return new CompilationResult(ERROR_FATAL);
+ }
+ // Load stdout
+ for (;;) {
+ String l = in.readLine();
+ if (l == null) {
+ return new CompilationResult(ERROR_FATAL);
+ }
+ if (l.equals(JavacServer.PROTOCOL_STDERR)) {
+ break;
+ }
+ stdout.append(l);
+ stdout.append('\n');
+ }
+ // Load stderr
+ for (;;) {
+ String l = in.readLine();
+ if (l == null) {
+ return new CompilationResult(ERROR_FATAL);
+ }
+ if (l.equals(JavacServer.PROTOCOL_PACKAGE_ARTIFACTS)) {
+ break;
+ }
+ stderr.append(l);
+ stderr.append('\n');
+ }
+ // Load the package artifacts
+ Set<URI> lastUriSet = null;
+ for (;;) {
+ String l = in.readLine();
+ if (l == null) {
+ return new CompilationResult(ERROR_FATAL);
+ }
+ if (l.equals(JavacServer.PROTOCOL_PACKAGE_DEPENDENCIES)) {
+ break;
+ }
+ if (l.length() > 1 && l.charAt(0) == '+') {
+ String pkg = l.substring(1);
+ lastUriSet = new HashSet<>();
+ rc.packageArtifacts.put(pkg, lastUriSet);
+ } else if (l.length() > 1 && lastUriSet != null) {
+ lastUriSet.add(new URI(l.substring(1)));
+ }
+ }
+ // Load package dependencies
+ Set<String> lastPackageSet = null;
+ for (;;) {
+ String l = in.readLine();
+ if (l == null) {
+ return new CompilationResult(ERROR_FATAL);
+ }
+ if (l.equals(JavacServer.PROTOCOL_PACKAGE_PUBLIC_APIS)) {
+ break;
+ }
+ if (l.length() > 1 && l.charAt(0) == '+') {
+ String pkg = l.substring(1);
+ lastPackageSet = new HashSet<>();
+ rc.packageDependencies.put(pkg, lastPackageSet);
+ } else if (l.length() > 1 && lastPackageSet != null) {
+ lastPackageSet.add(l.substring(1));
+ }
+ }
+ // Load package pubapis
+ Map<String, StringBuffer> tmp = new HashMap<>();
+ StringBuffer lastPublicApi = null;
+ for (;;) {
+ String l = in.readLine();
+ if (l == null) {
+ return new CompilationResult(ERROR_FATAL);
+ }
+ if (l.equals(JavacServer.PROTOCOL_SYSINFO)) {
+ break;
+ }
+ if (l.length() > 1 && l.charAt(0) == '+') {
+ String pkg = l.substring(1);
+ lastPublicApi = new StringBuffer();
+ tmp.put(pkg, lastPublicApi);
+ } else if (l.length() > 1 && lastPublicApi != null) {
+ lastPublicApi.append(l.substring(1));
+ lastPublicApi.append("\n");
+ }
+ }
+ for (String p : tmp.keySet()) {
+ //assert (packagePublicApis.get(p) == null);
+ String api = tmp.get(p).toString();
+ rc.packagePubapis.put(p, api);
+ }
+ // Now reading the max memory possible.
+ for (;;) {
+ String l = in.readLine();
+ if (l == null) {
+ return new CompilationResult(ERROR_FATAL);
+ }
+ if (l.equals(JavacServer.PROTOCOL_RETURN_CODE)) {
+ break;
+ }
+ if (l.startsWith("num_cores=")) {
+ rc.sysinfo.numCores = Integer.parseInt(l.substring(10));
+ }
+ if (l.startsWith("max_memory=")) {
+ rc.sysinfo.maxMemory = Long.parseLong(l.substring(11));
+ }
+ }
+ String l = in.readLine();
+ if (l == null) {
+ rc.setReturnCode(ERROR_FATAL);
+ rc.stderr = "No return value from the server!";
+ return rc;
+ }
+ rc.setReturnCode(Integer.parseInt(l));
+ rc.stdout = stdout.toString();
+ rc.stderr = stderr.toString();
+ } catch (Exception e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ rc.stderr = sw.toString();
+ }
+ return rc;
+ }
+
+ /**
+ * Dispatch a compilation request to a javac server.
+ *
+ * @param args are the command line args to javac and is allowed to contain source files, @file and other command line options to javac.
+ *
+ * The generated classes, h files and other artifacts from the javac invocation are stored by the javac server to disk.
+ *
+ * @param sources_to_compile The sources to compile.
+ *
+ * @param visibleSources If visible sources has a non zero size, then visible_sources are the only files in the file system that the javac server can see!
+ * (Sources to compile are always visible.) The visible sources are those supplied by the (filtered) -sourcepath
+ *
+ * @param visibleClasses If visible classes for a specific root/jar has a non zero size, then visible_classes are the only class files that the javac server
+ * can see, in that root/jar. It maps from a classpath root or a jar file to the set of visible classes for that root/jar.
+ *
+ * The server return meta data about the build in the following parameters.
+ * @param package_artifacts, map from package name to set of created artifacts for that package.
+ * @param package_dependencies, map from package name to set of packages that it depends upon.
+ * @param package_pubapis, map from package name to unique string identifying its pub api.
+ */
+ public CompilationResult useServer(String[] args,
+ Set<URI> sourcesToCompile,
+ Set<URI> visibleSources,
+ Map<URI, Set<String>> visibleClasses) {
+ try {
+ if (portfile == null) {
+ CompilationResult cr = new CompilationResult(CompilationResult.ERROR_FATAL);
+ cr.stderr = "No portfile was specified!";
+ return cr;
+ }
+
+ int attempts = 0;
+ CompilationResult rc;
+ do {
+ PortFile port_file = JavacServer.getPortFile(portfile);
+ synchronized (port_file) {
+ port_file.lock();
+ port_file.getValues();
+ port_file.unlock();
+ }
+ if (!port_file.containsPortInfo()) {
+ String cmd = JavacServer.fork(sjavac, port_file.getFilename(), logfile, poolsize, keepalive, System.err, stdouterrfile, background);
+
+ if (background && !port_file.waitForValidValues()) {
+ // Ouch the server did not start! Lets print its stdouterrfile and the command used.
+ StringWriter sw = new StringWriter();
+ JavacServiceClient.printFailedAttempt(cmd, stdouterrfile, new PrintWriter(sw));
+ // And give up.
+ CompilationResult cr = new CompilationResult(ERROR_FATAL);
+ cr.stderr = sw.toString();
+ return cr;
+ }
+ }
+ rc = compileHelper(id, args, sourcesToCompile, visibleSources);
+ // Try again until we manage to connect. Any error after that
+ // will cause the compilation to fail.
+ if (rc.returnCode == CompilationResult.ERROR_BUT_TRY_AGAIN) {
+ // We could not connect to the server. Try again.
+ attempts++;
+ try {
+ Thread.sleep(JavacServer.WAIT_BETWEEN_CONNECT_ATTEMPTS * 1000);
+ } catch (InterruptedException e) {
+ }
+ }
+ } while (rc.returnCode == ERROR_BUT_TRY_AGAIN && attempts < JavacServer.MAX_NUM_CONNECT_ATTEMPTS);
+ return rc;
+ } catch (Exception e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ CompilationResult cr = new CompilationResult(ERROR_FATAL);
+ cr.stderr = sw.toString();
+ return cr;
+ }
+ }
+
+ public static void printFailedAttempt(String cmd, String f, PrintWriter err) {
+ err.println("---- Failed to start javac server with this command -----");
+ err.println(cmd);
+ try {
+ BufferedReader in = new BufferedReader(new FileReader(f));
+ err.println("---- stdout/stderr output from attempt to start javac server -----");
+ for (;;) {
+ String l = in.readLine();
+ if (l == null) {
+ break;
+ }
+ err.println(l);
+ }
+ err.println("------------------------------------------------------------------");
+ } catch (Exception e) {
+ err.println("The stdout/stderr output in file " + f + " does not exist and the server did not start.");
+ }
+ }
+
+ /**
+ * Expect this key on the next line read from the reader.
+ */
+ public static boolean expect(BufferedReader in, String key) throws IOException {
+ String s = in.readLine();
+ if (s != null && s.equals(key)) {
+ return true;
+ }
+ return false;
+ }
+}
--- a/langtools/test/tools/sjavac/SJavac.java Fri Jun 27 20:32:12 2014 +0100
+++ b/langtools/test/tools/sjavac/SJavac.java Tue Jun 17 14:01:27 2014 +0200
@@ -23,7 +23,6 @@
import java.util.*;
import java.io.*;
-import java.net.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.nio.charset.*;
@@ -43,6 +42,9 @@
}
FileSystem defaultfs = FileSystems.getDefault();
+ String serverArg = "--server:"
+ + "portfile=testportfile,"
+ + "background=false";
// Where to put generated sources that will
// test aspects of sjavac, ie JTWork/scratch/gensrc
@@ -136,7 +138,7 @@
"private int b() { return A.DEFINITION; } native void foo(); }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
- "--server:portfile=testserver,background=false", "--log=debug");
+ serverArg, "--log=debug");
previous_bin_state = collectState(bin);
previous_headers_state = collectState(headers);
}
@@ -145,7 +147,7 @@
System.out.println("\nTesting that no change in sources implies no change in binaries.");
System.out.println("------------------------------------------------------------------");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
- "--server:portfile=testserver,background=false", "--log=debug");
+ serverArg, "--log=debug");
Map<String,Long> new_bin_state = collectState(bin);
verifyEqual(new_bin_state, previous_bin_state);
Map<String,Long> new_headers_state = collectState(headers);
@@ -158,7 +160,7 @@
System.out.println("-----------------------------------------");
removeFrom(gensrc, "alfa/omega/AA.java");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
- "--server:portfile=testserver,background=false", "--log=debug");
+ serverArg, "--log=debug");
Map<String,Long> new_bin_state = collectState(bin);
verifyThatFilesHaveBeenRemoved(previous_bin_state, new_bin_state,
"bin/alfa/omega/AA$1.class",
@@ -185,7 +187,7 @@
"public final static int DEFINITION = 18; public void aint() { } private void foo() { } }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
- "--server:portfile=testserver,background=false", "--log=debug");
+ serverArg, "--log=debug");
Map<String,Long> new_bin_state = collectState(bin);
verifyNewerFiles(previous_bin_state, new_bin_state,
@@ -211,7 +213,7 @@
"private int b() { return A.DEFINITION; } }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
- "--server:portfile=testserver,background=false", "--log=debug");
+ serverArg, "--log=debug");
Map<String,Long> new_bin_state = collectState(bin);
verifyNewerFiles(previous_bin_state, new_bin_state,
"bin/beta/B.class",
@@ -236,7 +238,7 @@
"@java.lang.annotation.Native final static int alfa = 42; }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
- "--server:portfile=testserver,background=false", "--log=debug");
+ serverArg, "--log=debug");
Map<String,Long> new_bin_state = collectState(bin);
verifyNewerFiles(previous_bin_state, new_bin_state,
"bin/beta/B.class",
@@ -262,7 +264,7 @@
"@java.lang.annotation.Native final static int alfa = 43; }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
- "--server:portfile=testserver,background=false", "--log=debug");
+ serverArg, "--log=debug");
Map<String,Long> new_bin_state = collectState(bin);
verifyNewerFiles(previous_bin_state, new_bin_state,
"bin/beta/B.class",
@@ -299,7 +301,7 @@
"package beta; public class B { }");
compile("-x", "beta", "gensrc", "gensrc2", "-d", "bin", "-h", "headers", "-j", "1",
- "--server:portfile=testserver,background=false");
+ serverArg);
Map<String,Long> new_bin_state = collectState(bin);
verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
"bin/alfa/omega/A.class",
@@ -310,7 +312,7 @@
System.out.println("----- Compile with exluded beta went well!");
delete(bin);
compileExpectFailure("gensrc", "gensrc2", "-d", "bin", "-h", "headers", "-j", "1",
- "--server:portfile=testserver,background=false");
+ serverArg);
System.out.println("----- Compile without exluded beta failed, as expected! Good!");
delete(bin);
@@ -341,7 +343,7 @@
compile("gensrc", "-x", "beta", "-sourcepath", "gensrc2",
"-sourcepath", "gensrc3", "-d", "bin", "-h", "headers", "-j", "1",
- "--server:portfile=testserver,background=false");
+ serverArg);
System.out.println("The first compile went well!");
Map<String,Long> new_bin_state = collectState(bin);
@@ -353,7 +355,7 @@
delete(bin);
compileExpectFailure("gensrc", "-sourcepath", "gensrc2", "-sourcepath", "gensrc3",
"-d", "bin", "-h", "headers", "-j", "1",
- "--server:portfile=testserver,background=false");
+ serverArg);
System.out.println("----- Compile without exluded beta failed, as expected! Good!");
delete(bin);
@@ -378,7 +380,7 @@
"package gamma; public class C { alfa.omega.A a; }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "3",
- "--server:portfile=testserver,background=false","--log=debug");
+ serverArg,"--log=debug");
Map<String,Long> new_bin_state = collectState(bin);
verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
"bin/alfa/omega/A.class",
@@ -407,7 +409,7 @@
"package beta; public class B { }");
compile("-x", "beta", "-src", "gensrc", "-x", "alfa/omega", "-sourcepath", "gensrc",
- "-d", "bin", "--server:portfile=testserver,background=false");
+ "-d", "bin", serverArg);
Map<String,Long> new_bin_state = collectState(bin);
verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
@@ -431,7 +433,7 @@
"}");
compile("gensrc", "-d", "bin", "-j", "1",
- "--server:portfile=testserver,background=false", "--log=debug");
+ serverArg, "--log=debug");
Map<String,Long> previous_bin_state = collectState(bin);
// Change pubapi of A, this should trigger a recompile of B.
@@ -443,7 +445,7 @@
"}");
compile("gensrc", "-d", "bin", "-j", "1",
- "--server:portfile=testserver,background=false", "--log=debug");
+ serverArg, "--log=debug");
Map<String,Long> new_bin_state = collectState(bin);
verifyNewerFiles(previous_bin_state, new_bin_state,