mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
optionally running java compiler in a forked process
This commit is contained in:
@@ -73,7 +73,10 @@ import com.intellij.openapi.vfs.newvfs.BulkFileListener;
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.FileNameCache;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import com.intellij.util.concurrency.SequentialTaskExecutor;
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
@@ -897,9 +900,6 @@ public class BuildManager implements ApplicationComponent{
|
||||
if (!Registry.is("compiler.process.use.memory.temp.cache")) {
|
||||
cmdLine.addParameter("-D"+ GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION + "=false");
|
||||
}
|
||||
if (Registry.is("compiler.process.use.external.javac")) {
|
||||
cmdLine.addParameter("-D"+ GlobalOptions.USE_EXTERNAL_JAVAC_OPTION);
|
||||
}
|
||||
|
||||
// javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language
|
||||
if (mySystemCharset != null) {
|
||||
@@ -941,7 +941,6 @@ public class BuildManager implements ApplicationComponent{
|
||||
cmdLine.addParameter(launcherClass.getName());
|
||||
|
||||
final List<String> cp = ClasspathBootstrap.getBuildProcessApplicationClasspath(true);
|
||||
cp.add(getJpsPluginSystemClassesPath());
|
||||
cp.addAll(myClasspathManager.getBuildProcessPluginsClasspath(project));
|
||||
if (isProfilingMode) {
|
||||
cp.add(new File(workDirectory, "yjp-controller-api-redist.jar").getPath());
|
||||
@@ -967,17 +966,6 @@ public class BuildManager implements ApplicationComponent{
|
||||
};
|
||||
}
|
||||
|
||||
private static String getJpsPluginSystemClassesPath() {
|
||||
File classesRoot = new File(PathUtil.getJarPathForClass(BuildManager.class));
|
||||
if (classesRoot.isDirectory()) {
|
||||
//running from sources: load classes from .../out/production/jps-plugin-system
|
||||
return new File(classesRoot.getParentFile(), "jps-plugin-system").getAbsolutePath();
|
||||
}
|
||||
else {
|
||||
return new File(classesRoot.getParentFile(), "rt/jps-plugin-system.jar").getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
public File getBuildSystemDirectory() {
|
||||
return new File(mySystemDirectory, SYSTEM_ROOT);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ package org.jetbrains.jps.api;
|
||||
*/
|
||||
public interface GlobalOptions {
|
||||
String USE_MEMORY_TEMP_CACHE_OPTION = "use.memory.temp.cache";
|
||||
String USE_EXTERNAL_JAVAC_OPTION = "use.external.javac.process";
|
||||
String GENERATE_CLASSPATH_INDEX_OPTION = "generate.classpath.index";
|
||||
String COMPILE_PARALLEL_OPTION = "compile.parallel";
|
||||
String COMPILE_PARALLEL_MAX_THREADS_OPTION = "compile.parallel.max.threads";
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.jetbrains.jps.service.SharedThreadPool;
|
||||
import java.io.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
@@ -214,7 +215,7 @@ public class BuildMain {
|
||||
public void run() {
|
||||
//noinspection finally
|
||||
try {
|
||||
ourEventLoopGroup.shutdownGracefully();
|
||||
ourEventLoopGroup.shutdownGracefully(0, 15, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
System.exit(0);
|
||||
|
||||
@@ -32,7 +32,7 @@ import net.n3.nanoxml.IXMLBuilder;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.java.JavaCompilingTool;
|
||||
import org.jetbrains.jps.builders.java.JavaSourceTransformer;
|
||||
import org.jetbrains.jps.javac.JavacServer;
|
||||
import org.jetbrains.jps.javac.ExternalJavacProcess;
|
||||
import org.jetbrains.jps.model.JpsModel;
|
||||
import org.jetbrains.jps.model.impl.JpsModelImpl;
|
||||
import org.jetbrains.jps.model.serialization.JpsProjectLoader;
|
||||
@@ -145,6 +145,8 @@ public class ClasspathBootstrap {
|
||||
cp.add(getResourcePath(NotNullVerifyingInstrumenter.class)); // not-null
|
||||
cp.add(getResourcePath(IXMLBuilder.class)); // nano-xml
|
||||
cp.add(getResourcePath(SequenceLock.class)); // jsr166
|
||||
cp.add(getJpsPluginSystemClassesPath().getAbsolutePath().replace('\\', '/'));
|
||||
|
||||
//don't forget to update layoutCommunityJps() in layouts.gant accordingly
|
||||
|
||||
if (!isLauncherUsed) {
|
||||
@@ -176,9 +178,9 @@ public class ClasspathBootstrap {
|
||||
}
|
||||
}
|
||||
|
||||
public static List<File> getJavacServerClasspath(String sdkHome, JavaCompilingTool compilingTool) {
|
||||
public static List<File> getExternalJavacProcessClasspath(String sdkHome, JavaCompilingTool compilingTool) {
|
||||
final Set<File> cp = new LinkedHashSet<File>();
|
||||
cp.add(getResourceFile(JavacServer.class)); // self
|
||||
cp.add(getResourceFile(ExternalJavacProcess.class)); // self
|
||||
// util
|
||||
for (String path : PathManager.getUtilClassPath()) {
|
||||
cp.add(new File(path));
|
||||
@@ -187,7 +189,8 @@ public class ClasspathBootstrap {
|
||||
cp.add(getResourceFile(JpsModelImpl.class)); // jps-model-impl
|
||||
cp.add(getResourceFile(Message.class)); // protobuf
|
||||
cp.add(getResourceFile(NetUtil.class)); // netty
|
||||
|
||||
cp.add(getJpsPluginSystemClassesPath());
|
||||
|
||||
final Class<StandardJavaFileManager> optimizedFileManagerClass = getOptimizedFileManagerClass();
|
||||
if (optimizedFileManagerClass != null) {
|
||||
cp.add(getResourceFile(optimizedFileManagerClass)); // optimizedFileManager, if applicable
|
||||
@@ -201,38 +204,33 @@ public class ClasspathBootstrap {
|
||||
LOG.info(th);
|
||||
}
|
||||
|
||||
final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (systemCompiler != null) {
|
||||
try {
|
||||
final String localJarPath = FileUtil.toSystemIndependentName(getResourceFile(systemCompiler.getClass()).getPath());
|
||||
final String localJavaHome = FileUtil.toSystemIndependentName(SystemProperties.getJavaHome());
|
||||
if (FileUtil.pathsEqual(localJavaHome, FileUtil.toSystemIndependentName(sdkHome))) {
|
||||
cp.add(new File(localJarPath));
|
||||
}
|
||||
else {
|
||||
// sdkHome is not the same as the sdk used to run this process
|
||||
final File candidate = new File(sdkHome, "lib/tools.jar");
|
||||
if (candidate.exists()) {
|
||||
cp.add(candidate);
|
||||
}
|
||||
else {
|
||||
// last resort
|
||||
String relPath = FileUtil.getRelativePath(localJavaHome, localJarPath, '/');
|
||||
try {
|
||||
final String localJavaHome = FileUtil.toSystemIndependentName(SystemProperties.getJavaHome());
|
||||
// sdkHome is not the same as the sdk used to run this process
|
||||
final File candidate = new File(sdkHome, "lib/tools.jar");
|
||||
if (candidate.exists()) {
|
||||
cp.add(candidate);
|
||||
}
|
||||
else {
|
||||
// last resort
|
||||
final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (systemCompiler != null) {
|
||||
final String localJarPath = FileUtil.toSystemIndependentName(getResourceFile(systemCompiler.getClass()).getPath());
|
||||
String relPath = FileUtil.getRelativePath(localJavaHome, localJarPath, '/');
|
||||
if (relPath != null) {
|
||||
if (relPath.contains("..")) {
|
||||
relPath = FileUtil.getRelativePath(FileUtil.toSystemIndependentName(new File(localJavaHome).getParent()), localJarPath, '/');
|
||||
}
|
||||
if (relPath != null) {
|
||||
if (relPath.contains("..")) {
|
||||
relPath = FileUtil.getRelativePath(FileUtil.toSystemIndependentName(new File(localJavaHome).getParent()), localJarPath, '/');
|
||||
}
|
||||
if (relPath != null) {
|
||||
final File targetFile = new File(sdkHome, relPath);
|
||||
cp.add(targetFile); // tools.jar
|
||||
}
|
||||
final File targetFile = new File(sdkHome, relPath);
|
||||
cp.add(targetFile); // tools.jar
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable th) {
|
||||
LOG.info(th);
|
||||
}
|
||||
}
|
||||
catch (Throwable th) {
|
||||
LOG.info(th);
|
||||
}
|
||||
|
||||
cp.addAll(compilingTool.getAdditionalClasspath());
|
||||
@@ -286,4 +284,16 @@ public class ClasspathBootstrap {
|
||||
public static File getResourceFile(Class aClass) {
|
||||
return new File(getResourcePath(aClass));
|
||||
}
|
||||
|
||||
private static File getJpsPluginSystemClassesPath() {
|
||||
File classesRoot = new File(getResourcePath(ClasspathBootstrap.class));
|
||||
if (classesRoot.isDirectory()) {
|
||||
//running from sources: load classes from .../out/production/jps-plugin-system
|
||||
return new File(classesRoot.getParentFile(), "jps-plugin-system");
|
||||
}
|
||||
else {
|
||||
return new File(classesRoot.getParentFile(), "rt/jps-plugin-system.jar");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import org.jetbrains.jps.ModuleChunk;
|
||||
import org.jetbrains.jps.TimingLog;
|
||||
import org.jetbrains.jps.api.CanceledStatus;
|
||||
import org.jetbrains.jps.api.GlobalOptions;
|
||||
import org.jetbrains.jps.api.RequestFuture;
|
||||
import org.jetbrains.jps.builders.*;
|
||||
import org.jetbrains.jps.builders.impl.BuildOutputConsumerImpl;
|
||||
import org.jetbrains.jps.builders.impl.BuildTargetChunk;
|
||||
@@ -50,12 +49,12 @@ import org.jetbrains.jps.builders.storage.SourceToOutputMapping;
|
||||
import org.jetbrains.jps.cmdline.BuildRunner;
|
||||
import org.jetbrains.jps.cmdline.ProjectDescriptor;
|
||||
import org.jetbrains.jps.incremental.fs.BuildFSState;
|
||||
import org.jetbrains.jps.incremental.java.ExternalJavacDescriptor;
|
||||
import org.jetbrains.jps.incremental.messages.*;
|
||||
import org.jetbrains.jps.incremental.storage.BuildTargetConfiguration;
|
||||
import org.jetbrains.jps.incremental.storage.OneToManyPathsMapping;
|
||||
import org.jetbrains.jps.incremental.storage.OutputToTargetRegistry;
|
||||
import org.jetbrains.jps.indices.ModuleExcludeIndex;
|
||||
import org.jetbrains.jps.javac.ExternalJavacServer;
|
||||
import org.jetbrains.jps.javac.JavacMain;
|
||||
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
|
||||
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration;
|
||||
@@ -313,17 +312,10 @@ public class IncProjectBuilder {
|
||||
pd.timestamps.getStorage().force();
|
||||
pd.dataManager.flush(false);
|
||||
}
|
||||
final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context);
|
||||
if (descriptor != null) {
|
||||
try {
|
||||
final RequestFuture future = descriptor.client.sendShutdownRequest();
|
||||
future.waitFor(500L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
finally {
|
||||
// ensure process is not running
|
||||
descriptor.process.destroyProcess();
|
||||
}
|
||||
ExternalJavacDescriptor.KEY.set(context, null);
|
||||
final ExternalJavacServer server = ExternalJavacServer.KEY.get(context);
|
||||
if (server != null) {
|
||||
server.stop();
|
||||
ExternalJavacServer.KEY.set(context, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.jps.incremental.java;
|
||||
|
||||
import com.intellij.execution.process.BaseOSProcessHandler;
|
||||
import org.jetbrains.jps.incremental.GlobalContextKey;
|
||||
import org.jetbrains.jps.javac.JavacServerClient;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/24/12
|
||||
*/
|
||||
public class ExternalJavacDescriptor {
|
||||
public static final GlobalContextKey<ExternalJavacDescriptor> KEY = GlobalContextKey.create("_external_javac_descriptor_");
|
||||
|
||||
public final BaseOSProcessHandler process;
|
||||
public final JavacServerClient client;
|
||||
|
||||
public ExternalJavacDescriptor(BaseOSProcessHandler process, JavacServerClient client) {
|
||||
this.process = process;
|
||||
this.client = client;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.jetbrains.jps.incremental.java;
|
||||
|
||||
import com.intellij.execution.process.BaseOSProcessHandler;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Key;
|
||||
@@ -32,8 +31,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
import org.jetbrains.jps.ProjectPaths;
|
||||
import org.jetbrains.jps.api.GlobalOptions;
|
||||
import org.jetbrains.jps.api.RequestFuture;
|
||||
import org.jetbrains.jps.builders.BuildRootIndex;
|
||||
import org.jetbrains.jps.builders.DirtyFilesHolder;
|
||||
import org.jetbrains.jps.builders.FileProcessor;
|
||||
@@ -63,13 +60,11 @@ import org.jetbrains.jps.model.module.JpsModule;
|
||||
import org.jetbrains.jps.model.module.JpsModuleType;
|
||||
import org.jetbrains.jps.service.JpsServiceManager;
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.*;
|
||||
import java.io.*;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
@@ -81,7 +76,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
public static final String BUILDER_NAME = "java";
|
||||
private static final String JAVA_EXTENSION = "java";
|
||||
private static final String DOT_JAVA_EXTENSION = "." + JAVA_EXTENSION;
|
||||
public static final boolean USE_EMBEDDED_JAVAC = System.getProperty(GlobalOptions.USE_EXTERNAL_JAVAC_OPTION) == null;
|
||||
private static final Key<Integer> JAVA_COMPILER_VERSION_KEY = Key.create("_java_compiler_version_");
|
||||
public static final Key<Boolean> IS_ENABLED = Key.create("_java_compiler_enabled_");
|
||||
private static final Key<JavaCompilingTool> COMPILING_TOOL = Key.create("_java_compiling_tool_");
|
||||
@@ -396,7 +390,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
try {
|
||||
final boolean rc;
|
||||
if (USE_EMBEDDED_JAVAC) {
|
||||
if (!shouldForkCompilerProcess(context, chunk, compilingTool)) {
|
||||
final Collection<File> _platformCp = calcEffectivePlatformCp(platformCp, options, compilingTool);
|
||||
if (_platformCp == null) {
|
||||
diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR,
|
||||
@@ -409,16 +403,18 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
);
|
||||
}
|
||||
else {
|
||||
final JavacServerClient client = ensureJavacServerLaunched(context, compilingTool);
|
||||
final RequestFuture<JavacServerResponseHandler> future = client.sendCompileRequest(
|
||||
options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer
|
||||
);
|
||||
while (!future.waitFor(100L, TimeUnit.MILLISECONDS)) {
|
||||
if (context.getCancelStatus().isCanceled()) {
|
||||
future.cancel(false);
|
||||
}
|
||||
// fork external javac
|
||||
final String sdkHome = getChunkSdkHome(chunk);
|
||||
if (sdkHome == null) {
|
||||
diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Cannot start javac process for " + chunk.getName() + ": unknown JDK home path.\nPlease check project configuration."));
|
||||
return true;
|
||||
}
|
||||
rc = future.getMessageHandler().isTerminatedSuccessfully();
|
||||
|
||||
final List<String> vmOptions = getCompilationVMOptions(context, compilingTool);
|
||||
final ExternalJavacServer server = ensureJavacServerStarted(context);
|
||||
rc = server.forkJavac(
|
||||
context, options, vmOptions, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, sdkHome, compilingTool
|
||||
);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -426,6 +422,20 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
counter.await();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldForkCompilerProcess(CompileContext context, ModuleChunk chunk, JavaCompilingTool tool) {
|
||||
final int compilerSdkVersion = getCompilerSdkVersion(context);
|
||||
if (compilerSdkVersion < 9) {
|
||||
// javac up to version 9 supports all previous releases
|
||||
return false;
|
||||
}
|
||||
final int chunkSdkVersion = getChunkSdkVersion(chunk);
|
||||
if (chunkSdkVersion < 0) {
|
||||
return false; // was not able to determine jdk version, assuming in-process compiler
|
||||
}
|
||||
// according to JEP 182: Retiring javac "one plus three back" policy
|
||||
return Math.abs(compilerSdkVersion - chunkSdkVersion) > 3;
|
||||
}
|
||||
|
||||
// If platformCp of the build process is the same as the target plafform, do not specify platformCp explicitly
|
||||
// this will allow javac to resolve against ct.sym file, which is required for the "compilation profiles" feature
|
||||
@@ -482,31 +492,16 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
});
|
||||
}
|
||||
|
||||
private static synchronized JavacServerClient ensureJavacServerLaunched(@NotNull CompileContext context, @NotNull JavaCompilingTool compilingTool) throws Exception {
|
||||
final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context);
|
||||
if (descriptor != null) {
|
||||
return descriptor.client;
|
||||
private static synchronized ExternalJavacServer ensureJavacServerStarted(@NotNull CompileContext context) throws Exception {
|
||||
ExternalJavacServer server = ExternalJavacServer.KEY.get(context);
|
||||
if (server != null) {
|
||||
return server;
|
||||
}
|
||||
// start server here
|
||||
final int port = findFreePort();
|
||||
final int heapSize = getJavacServerHeapSize(context);
|
||||
|
||||
// use the same jdk that used to run the build process
|
||||
final String javaHome = SystemProperties.getJavaHome();
|
||||
|
||||
final BaseOSProcessHandler processHandler = JavacServerBootstrap.launchJavacServer(
|
||||
javaHome, heapSize, port, Utils.getSystemRoot(), getCompilationVMOptions(context, compilingTool), compilingTool
|
||||
);
|
||||
final JavacServerClient client = new JavacServerClient();
|
||||
try {
|
||||
client.connect("127.0.0.1", port);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
processHandler.destroyProcess();
|
||||
throw new Exception("Failed to connect to external javac process: ", ex);
|
||||
}
|
||||
ExternalJavacDescriptor.KEY.set(context, new ExternalJavacDescriptor(processHandler, client));
|
||||
return client;
|
||||
final int listenPort = findFreePort();
|
||||
server = new ExternalJavacServer();
|
||||
server.start(listenPort);
|
||||
ExternalJavacServer.KEY.set(context, server);
|
||||
return server;
|
||||
}
|
||||
|
||||
private static int convertToNumber(String ver) {
|
||||
@@ -564,17 +559,10 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
return JavacServer.DEFAULT_SERVER_PORT;
|
||||
return ExternalJavacServer.DEFAULT_SERVER_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getJavacServerHeapSize(CompileContext context) {
|
||||
final JpsProject project = context.getProjectDescriptor().getProject();
|
||||
final JpsJavaCompilerConfiguration config = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project);
|
||||
final JpsJavaCompilerOptions options = config.getCurrentCompilerOptions();
|
||||
return options.MAXIMUM_HEAP_SIZE;
|
||||
}
|
||||
|
||||
private static final Key<List<String>> JAVAC_OPTIONS = Key.create("_javac_options_");
|
||||
private static final Key<List<String>> JAVAC_VM_OPTIONS = Key.create("_javac_vm_options_");
|
||||
private static final Key<String> USER_DEFINED_BYTECODE_TARGET = Key.create("_user_defined_bytecode_target_");
|
||||
@@ -628,19 +616,12 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
options.add(langLevel);
|
||||
}
|
||||
|
||||
JpsJavaCompilerConfiguration compilerConfiguration = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(
|
||||
context.getProjectDescriptor().getProject());
|
||||
String bytecodeTarget = null;
|
||||
int chunkSdkVersion = -1;
|
||||
for (JpsModule module : chunk.getModules()) {
|
||||
final JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
|
||||
if (sdk != null) {
|
||||
final int moduleSdkVersion = convertToNumber(sdk.getVersionString());
|
||||
if (moduleSdkVersion != 0 /*could determine the version*/&& (chunkSdkVersion < 0 || chunkSdkVersion > moduleSdkVersion)) {
|
||||
chunkSdkVersion = moduleSdkVersion;
|
||||
}
|
||||
}
|
||||
final JpsJavaCompilerConfiguration compilerConfiguration = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(
|
||||
context.getProjectDescriptor().getProject()
|
||||
);
|
||||
|
||||
String bytecodeTarget = null;
|
||||
for (JpsModule module : chunk.getModules()) {
|
||||
final String moduleTarget = compilerConfiguration.getByteCodeTargetLevel(module.getName());
|
||||
if (moduleTarget == null) {
|
||||
continue;
|
||||
@@ -662,6 +643,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
|
||||
final int compilerSdkVersion = getCompilerSdkVersion(context);
|
||||
final int chunkSdkVersion = getChunkSdkVersion(chunk);
|
||||
|
||||
if (bytecodeTarget != null) {
|
||||
options.add("-target");
|
||||
@@ -721,17 +703,19 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
|
||||
private static String getLanguageLevel(JpsModule module) {
|
||||
LanguageLevel level = JpsJavaExtensionService.getInstance().getLanguageLevel(module);
|
||||
if (level == null) return null;
|
||||
switch (level) {
|
||||
case JDK_1_3: return "1.3";
|
||||
case JDK_1_4: return "1.4";
|
||||
case JDK_1_5: return "1.5";
|
||||
case JDK_1_6: return "1.6";
|
||||
case JDK_1_7: return "1.7";
|
||||
case JDK_1_8: return "8";
|
||||
default: return null;
|
||||
final LanguageLevel level = JpsJavaExtensionService.getInstance().getLanguageLevel(module);
|
||||
if (level != null) {
|
||||
switch (level) {
|
||||
case JDK_1_3: return "1.3";
|
||||
case JDK_1_4: return "1.4";
|
||||
case JDK_1_5: return "1.5";
|
||||
case JDK_1_6: return "1.6";
|
||||
case JDK_1_7: return "1.7";
|
||||
case JDK_1_8: return "8";
|
||||
case JDK_1_9: return "9";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isEncodingSet(List<String> options) {
|
||||
@@ -743,7 +727,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static int getCompilerSdkVersion(CompileContext context) {
|
||||
final Integer cached = JAVA_COMPILER_VERSION_KEY.get(context);
|
||||
if (cached != null) {
|
||||
@@ -754,6 +737,30 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
return javaVersion;
|
||||
}
|
||||
|
||||
private static int getChunkSdkVersion(ModuleChunk chunk) {
|
||||
int chunkSdkVersion = -1;
|
||||
for (JpsModule module : chunk.getModules()) {
|
||||
final JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
|
||||
if (sdk != null) {
|
||||
final int moduleSdkVersion = convertToNumber(sdk.getVersionString());
|
||||
if (moduleSdkVersion != 0 /*could determine the version*/&& (chunkSdkVersion < 0 || chunkSdkVersion > moduleSdkVersion)) {
|
||||
chunkSdkVersion = moduleSdkVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunkSdkVersion;
|
||||
}
|
||||
|
||||
private static String getChunkSdkHome(ModuleChunk chunk) {
|
||||
for (JpsModule module : chunk.getModules()) {
|
||||
final JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
|
||||
if (sdk != null) {
|
||||
return sdk.getHomePath();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void loadCommonJavacOptions(@NotNull CompileContext context, @NotNull JavaCompilingTool compilingTool) {
|
||||
final List<String> options = new ArrayList<String>();
|
||||
final List<String> vmOptions = new ArrayList<String>();
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.jps.javac;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.MessageLite;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.incremental.BinaryContent;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
public class ExternalJavacMessageHandler {
|
||||
private final DiagnosticOutputConsumer myDiagnosticSink;
|
||||
private final OutputFileConsumer myOutputSink;
|
||||
@Nullable
|
||||
private final String myEncodingName;
|
||||
private volatile boolean myTerminatedSuccessfully;
|
||||
|
||||
public ExternalJavacMessageHandler(DiagnosticOutputConsumer diagnosticSink,
|
||||
OutputFileConsumer outputSink,
|
||||
@Nullable final String encodingName) {
|
||||
myDiagnosticSink = diagnosticSink;
|
||||
myOutputSink = outputSink;
|
||||
myEncodingName = encodingName;
|
||||
}
|
||||
|
||||
public boolean handleMessage(MessageLite message) {
|
||||
try {
|
||||
final JavacRemoteProto.Message msg = (JavacRemoteProto.Message)message;
|
||||
final JavacRemoteProto.Message.Type messageType = msg.getMessageType();
|
||||
|
||||
if (messageType == JavacRemoteProto.Message.Type.RESPONSE) {
|
||||
final JavacRemoteProto.Message.Response response = msg.getResponse();
|
||||
final JavacRemoteProto.Message.Response.Type responseType = response.getResponseType();
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_MESSAGE) {
|
||||
final JavacRemoteProto.Message.Response.CompileMessage compileMessage = response.getCompileMessage();
|
||||
final JavacRemoteProto.Message.Response.CompileMessage.Kind messageKind = compileMessage.getKind();
|
||||
|
||||
if (messageKind == JavacRemoteProto.Message.Response.CompileMessage.Kind.STD_OUT) {
|
||||
if (compileMessage.hasText()) {
|
||||
myDiagnosticSink.outputLineAvailable(compileMessage.getText());
|
||||
}
|
||||
}
|
||||
else {
|
||||
final String sourceUri = compileMessage.hasSourceUri()? compileMessage.getSourceUri() : null;
|
||||
final JavaFileObject srcFileObject = sourceUri != null? new DummyJavaFileObject(URI.create(sourceUri)) : null;
|
||||
myDiagnosticSink.report(new DummyDiagnostic(convertKind(messageKind), srcFileObject, compileMessage));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.OUTPUT_OBJECT) {
|
||||
final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
|
||||
final JavacRemoteProto.Message.Response.OutputObject.Kind kind = outputObject.getKind();
|
||||
|
||||
final String outputRoot = outputObject.hasOutputRoot()? outputObject.getOutputRoot() : null;
|
||||
final File outputRootFile = outputRoot != null? new File(outputRoot) : null;
|
||||
|
||||
final BinaryContent fileObjectContent;
|
||||
final ByteString content = outputObject.hasContent()? outputObject.getContent() : null;
|
||||
if (content != null) {
|
||||
final byte[] bytes = content.toByteArray();
|
||||
fileObjectContent = new BinaryContent(bytes, 0, bytes.length);
|
||||
}
|
||||
else {
|
||||
fileObjectContent = null;
|
||||
}
|
||||
|
||||
final String sourceUri = outputObject.hasSourceUri()? outputObject.getSourceUri() : null;
|
||||
final URI srcUri = sourceUri != null? URI.create(sourceUri) : null;
|
||||
final OutputFileObject fileObject = new OutputFileObject(
|
||||
null,
|
||||
outputRootFile,
|
||||
outputObject.hasRelativePath()? outputObject.getRelativePath() : null,
|
||||
new File(outputObject.getFilePath()),
|
||||
convertKind(kind),
|
||||
outputObject.hasClassName()? outputObject.getClassName() : null,
|
||||
srcUri,
|
||||
myEncodingName, fileObjectContent
|
||||
);
|
||||
|
||||
myOutputSink.save(fileObject);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.SRC_FILE_LOADED) {
|
||||
final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
|
||||
final File file = new File(outputObject.getFilePath());
|
||||
myDiagnosticSink.javaFileLoaded(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.CLASS_DATA) {
|
||||
final JavacRemoteProto.Message.Response.ClassData data = response.getClassData();
|
||||
final String className = data.getClassName();
|
||||
final Collection<String> imports = data.getImportStatementList();
|
||||
final Collection<String> staticImports = data.getStaticImportList();
|
||||
myDiagnosticSink.registerImports(className, imports, staticImports);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_COMPLETED) {
|
||||
if (response.hasCompletionStatus()) {
|
||||
myTerminatedSuccessfully = response.getCompletionStatus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Exception("Unsupported response type: " + responseType.name());
|
||||
}
|
||||
|
||||
if (messageType == JavacRemoteProto.Message.Type.FAILURE) {
|
||||
final JavacRemoteProto.Message.Failure failure = msg.getFailure();
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
if (failure.hasDescription()) {
|
||||
buf.append(failure.getDescription());
|
||||
}
|
||||
if (failure.hasStacktrace()) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append("\n");
|
||||
}
|
||||
buf.append(failure.getStacktrace());
|
||||
}
|
||||
myDiagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, buf.toString()));
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Exception("Unsupported message type: " + messageType.name());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
myDiagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTerminatedSuccessfully() {
|
||||
return myTerminatedSuccessfully;
|
||||
}
|
||||
|
||||
private static Diagnostic.Kind convertKind(JavacRemoteProto.Message.Response.CompileMessage.Kind kind) {
|
||||
switch (kind) {
|
||||
case ERROR: return Diagnostic.Kind.ERROR;
|
||||
case WARNING: return Diagnostic.Kind.WARNING;
|
||||
case MANDATORY_WARNING: return Diagnostic.Kind.MANDATORY_WARNING;
|
||||
case NOTE: return Diagnostic.Kind.NOTE;
|
||||
default : return Diagnostic.Kind.OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
private static OutputFileObject.Kind convertKind(JavacRemoteProto.Message.Response.OutputObject.Kind kind) {
|
||||
switch (kind) {
|
||||
case CLASS: return JavaFileObject.Kind.CLASS;
|
||||
case HTML: return JavaFileObject.Kind.HTML;
|
||||
case SOURCE: return JavaFileObject.Kind.SOURCE;
|
||||
default : return JavaFileObject.Kind.OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DummyDiagnostic implements Diagnostic<JavaFileObject> {
|
||||
|
||||
private final Kind myMessageKind;
|
||||
private final JavaFileObject mySrcFileObject;
|
||||
private final JavacRemoteProto.Message.Response.CompileMessage myCompileMessage;
|
||||
|
||||
public DummyDiagnostic(final Kind messageKind, JavaFileObject srcFileObject, JavacRemoteProto.Message.Response.CompileMessage compileMessage) {
|
||||
myMessageKind = messageKind;
|
||||
mySrcFileObject = srcFileObject;
|
||||
myCompileMessage = compileMessage;
|
||||
}
|
||||
|
||||
public Kind getKind() {
|
||||
return myMessageKind;
|
||||
}
|
||||
|
||||
public JavaFileObject getSource() {
|
||||
return mySrcFileObject;
|
||||
}
|
||||
|
||||
public long getPosition() {
|
||||
return myCompileMessage.hasProblemLocationOffset()? myCompileMessage.getProblemLocationOffset() : -1;
|
||||
}
|
||||
|
||||
public long getStartPosition() {
|
||||
return myCompileMessage.hasProblemBeginOffset()? myCompileMessage.getProblemBeginOffset() : -1;
|
||||
}
|
||||
|
||||
public long getEndPosition() {
|
||||
return myCompileMessage.hasProblemEndOffset()? myCompileMessage.getProblemEndOffset() : -1;
|
||||
}
|
||||
|
||||
public long getLineNumber() {
|
||||
return myCompileMessage.hasLine()? myCompileMessage.getLine() : -1;
|
||||
}
|
||||
|
||||
public long getColumnNumber() {
|
||||
return myCompileMessage.hasColumn()? myCompileMessage.getColumn() : -1;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getMessage(Locale locale) {
|
||||
return myCompileMessage.hasText()? myCompileMessage.getText() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+163
-159
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,18 +15,19 @@
|
||||
*/
|
||||
package org.jetbrains.jps.javac;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.group.ChannelGroup;
|
||||
import io.netty.channel.group.ChannelGroupFuture;
|
||||
import io.netty.channel.group.DefaultChannelGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.protobuf.ProtobufDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufEncoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
|
||||
import io.netty.util.concurrent.ImmediateEventExecutor;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import io.netty.util.internal.logging.Log4JLoggerFactory;
|
||||
import org.apache.log4j.ConsoleAppender;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.PatternLayout;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.api.CanceledStatus;
|
||||
import org.jetbrains.jps.builders.impl.java.JavacCompilerTool;
|
||||
@@ -37,85 +38,109 @@ import org.jetbrains.jps.service.SharedThreadPool;
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public class JavacServer {
|
||||
public static final int DEFAULT_SERVER_PORT = 7878;
|
||||
public static final String SERVER_SUCCESS_START_MESSAGE = "Javac server started successfully. Listening on port: ";
|
||||
public static final String SERVER_ERROR_START_MESSAGE = "Error starting Javac Server: ";
|
||||
public class ExternalJavacProcess {
|
||||
public static final String JPS_JAVA_COMPILING_TOOL_PROPERTY = "jps.java.compiling.tool";
|
||||
private final ChannelInitializer myChannelInitializer;
|
||||
private final EventLoopGroup myEventLoopGroup;
|
||||
private volatile ChannelFuture myConnectFuture;
|
||||
private volatile CancelHandler myCancelHandler;
|
||||
|
||||
private ChannelRegistrar myChannelRegistrar;
|
||||
|
||||
public void start(int listenPort) {
|
||||
final ServerBootstrap bootstrap = new ServerBootstrap().group(new NioEventLoopGroup(1, SharedThreadPool.getInstance())).channel(NioServerSocketChannel.class);
|
||||
bootstrap.childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
myChannelRegistrar = new ChannelRegistrar();
|
||||
final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler();
|
||||
bootstrap.childHandler(new ChannelInitializer() {
|
||||
static {
|
||||
org.apache.log4j.Logger root = org.apache.log4j.Logger.getRootLogger();
|
||||
if (!root.getAllAppenders().hasMoreElements()) {
|
||||
root.setLevel(Level.INFO);
|
||||
root.addAppender(new ConsoleAppender(new PatternLayout(PatternLayout.DEFAULT_CONVERSION_PATTERN)));
|
||||
}
|
||||
InternalLoggerFactory.setDefaultFactory(new Log4JLoggerFactory());
|
||||
}
|
||||
|
||||
public ExternalJavacProcess() {
|
||||
final JavacRemoteProto.Message msgDefaultInstance = JavacRemoteProto.Message.getDefaultInstance();
|
||||
|
||||
myEventLoopGroup = new NioEventLoopGroup(1, SharedThreadPool.getInstance());
|
||||
myChannelInitializer = new ChannelInitializer() {
|
||||
@Override
|
||||
protected void initChannel(Channel channel) throws Exception {
|
||||
channel.pipeline().addLast(myChannelRegistrar,
|
||||
new ProtobufVarint32FrameDecoder(),
|
||||
new ProtobufDecoder(JavacRemoteProto.Message.getDefaultInstance()),
|
||||
channel.pipeline().addLast(new ProtobufVarint32FrameDecoder(),
|
||||
new ProtobufDecoder(msgDefaultInstance),
|
||||
new ProtobufVarint32LengthFieldPrepender(),
|
||||
new ProtobufEncoder(),
|
||||
compilationRequestsHandler);
|
||||
new CompilationRequestsHandler()
|
||||
);
|
||||
}
|
||||
});
|
||||
myChannelRegistrar.add(bootstrap.bind(listenPort).syncUninterruptibly().channel());
|
||||
};
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
myChannelRegistrar.close().awaitUninterruptibly();
|
||||
}
|
||||
|
||||
|
||||
//static volatile long myGlobalStart;
|
||||
|
||||
public static void main(String[] args) {
|
||||
JavacServer server = null;
|
||||
try {
|
||||
int port = DEFAULT_SERVER_PORT;
|
||||
if (args.length > 0) {
|
||||
try {
|
||||
port = Integer.parseInt(args[0]);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.err.println("Error parsing port: " + e.getMessage());
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
server = new JavacServer();
|
||||
server.start(port);
|
||||
final JavacServer finalServer = server;
|
||||
Runtime.getRuntime().addShutdownHook(new Thread("Shutdown hook thread") {
|
||||
@Override
|
||||
public void run() {
|
||||
finalServer.stop();
|
||||
}
|
||||
});
|
||||
|
||||
System.out.println("Server classpath: " + System.getProperty("java.class.path"));
|
||||
System.err.println(SERVER_SUCCESS_START_MESSAGE + port);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
System.err.println(SERVER_ERROR_START_MESSAGE + e.getMessage());
|
||||
e.printStackTrace(System.err);
|
||||
//myGlobalStart = System.currentTimeMillis();
|
||||
UUID uuid = null;
|
||||
String host = null;
|
||||
int port = -1;
|
||||
if (args.length > 0) {
|
||||
try {
|
||||
if (server != null) {
|
||||
server.stop();
|
||||
}
|
||||
uuid = UUID.fromString(args[0]);
|
||||
}
|
||||
finally {
|
||||
catch (Exception e) {
|
||||
System.err.println("Error parsing session id: " + e.getMessage());
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
host = args[1];
|
||||
|
||||
try {
|
||||
port = Integer.parseInt(args[2]);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.err.println("Error parsing port: " + e.getMessage());
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.err.println("Insufficient parameters");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
final ExternalJavacProcess process = new ExternalJavacProcess();
|
||||
try {
|
||||
//final long connectStart = System.currentTimeMillis();
|
||||
if (process.connect(host, port)) {
|
||||
//final long connectEnd = System.currentTimeMillis();
|
||||
//System.err.println("Connected in " + (connectEnd - connectStart) + " ms; since start: " + (connectEnd - myGlobalStart));
|
||||
process.myConnectFuture.channel().writeAndFlush(
|
||||
JavacProtoUtil.toMessage(uuid, JavacProtoUtil.createRequestAckResponse())
|
||||
);
|
||||
}
|
||||
else {
|
||||
System.err.println("Failed to connect to parent process");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
throwable.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
public static JavacRemoteProto.Message compile(final ChannelHandlerContext context,
|
||||
private boolean connect(final String host, final int port) throws Throwable {
|
||||
final Bootstrap bootstrap = new Bootstrap().group(myEventLoopGroup).channel(NioSocketChannel.class).handler(myChannelInitializer);
|
||||
bootstrap.option(ChannelOption.TCP_NODELAY, true).option(ChannelOption.SO_KEEPALIVE, true);
|
||||
final ChannelFuture future = bootstrap.connect(host, port).syncUninterruptibly();
|
||||
if (future.isSuccess()) {
|
||||
myConnectFuture = future;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static JavacRemoteProto.Message compile(final ChannelHandlerContext context,
|
||||
final UUID sessionId,
|
||||
List<String> options,
|
||||
Collection<File> files,
|
||||
@@ -124,6 +149,8 @@ public class JavacServer {
|
||||
Collection<File> sourcePath,
|
||||
Map<File, Set<File>> outs,
|
||||
final CanceledStatus canceledStatus) {
|
||||
//final long compileStart = System.currentTimeMillis();
|
||||
//System.err.println("Compile start; since global start: " + (compileStart - myGlobalStart));
|
||||
final DiagnosticOutputConsumer diagnostic = new DiagnosticOutputConsumer() {
|
||||
@Override
|
||||
public void javaFileLoaded(File file) {
|
||||
@@ -157,7 +184,8 @@ public class JavacServer {
|
||||
|
||||
try {
|
||||
JavaCompilingTool tool = getCompilingTool();
|
||||
final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus, tool);
|
||||
final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus,
|
||||
tool);
|
||||
return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createBuildCompletedResponse(rc));
|
||||
}
|
||||
catch (Throwable e) {
|
||||
@@ -165,8 +193,12 @@ public class JavacServer {
|
||||
e.printStackTrace(System.err);
|
||||
return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createFailure(e.getMessage(), e));
|
||||
}
|
||||
//finally {
|
||||
// final long compileEnd = System.currentTimeMillis();
|
||||
// System.err.println("Compiled in " + (compileEnd - compileStart) + " ms; since global start: " + (compileEnd - myGlobalStart));
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
private static JavaCompilingTool getCompilingTool() {
|
||||
String property = System.getProperty(JPS_JAVA_COMPILING_TOOL_PROPERTY);
|
||||
if (property != null) {
|
||||
@@ -178,24 +210,6 @@ public class JavacServer {
|
||||
return new JavacCompilerTool();
|
||||
}
|
||||
|
||||
private final Set<CancelHandler> myCancelHandlers = Collections.synchronizedSet(new HashSet<CancelHandler>());
|
||||
|
||||
public void cancelBuilds() {
|
||||
synchronized (myCancelHandlers) {
|
||||
for (CancelHandler handler : myCancelHandlers) {
|
||||
handler.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<File> toFiles(List<String> paths) {
|
||||
final List<File> files = new ArrayList<File>(paths.size());
|
||||
for (String path : paths) {
|
||||
files.add(new File(path));
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
private class CompilationRequestsHandler extends SimpleChannelInboundHandler<JavacRemoteProto.Message> {
|
||||
@Override
|
||||
@@ -210,52 +224,50 @@ public class JavacServer {
|
||||
final JavacRemoteProto.Message.Request request = message.getRequest();
|
||||
final JavacRemoteProto.Message.Request.Type requestType = request.getRequestType();
|
||||
if (requestType == JavacRemoteProto.Message.Request.Type.COMPILE) {
|
||||
final List<String> options = request.getOptionList();
|
||||
final List<File> files = toFiles(request.getFileList());
|
||||
final List<File> cp = toFiles(request.getClasspathList());
|
||||
final List<File> platformCp = toFiles(request.getPlatformClasspathList());
|
||||
final List<File> srcPath = toFiles(request.getSourcepathList());
|
||||
if (myCancelHandler == null) { // if not running yet
|
||||
final List<String> options = request.getOptionList();
|
||||
final List<File> files = toFiles(request.getFileList());
|
||||
final List<File> cp = toFiles(request.getClasspathList());
|
||||
final List<File> platformCp = toFiles(request.getPlatformClasspathList());
|
||||
final List<File> srcPath = toFiles(request.getSourcepathList());
|
||||
|
||||
final Map<File, Set<File>> outs = new HashMap<File, Set<File>>();
|
||||
for (JavacRemoteProto.Message.Request.OutputGroup outputGroup : request.getOutputList()) {
|
||||
final Set<File> srcRoots = new HashSet<File>();
|
||||
for (String root : outputGroup.getSourceRootList()) {
|
||||
srcRoots.add(new File(root));
|
||||
final Map<File, Set<File>> outs = new HashMap<File, Set<File>>();
|
||||
for (JavacRemoteProto.Message.Request.OutputGroup outputGroup : request.getOutputList()) {
|
||||
final Set<File> srcRoots = new HashSet<File>();
|
||||
for (String root : outputGroup.getSourceRootList()) {
|
||||
srcRoots.add(new File(root));
|
||||
}
|
||||
outs.put(new File(outputGroup.getOutputRoot()), srcRoots);
|
||||
}
|
||||
outs.put(new File(outputGroup.getOutputRoot()), srcRoots);
|
||||
|
||||
final CancelHandler cancelHandler = new CancelHandler();
|
||||
myCancelHandler = cancelHandler;
|
||||
SharedThreadPool.getInstance().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
context.channel().writeAndFlush(
|
||||
compile(context, sessionId, options, files, cp, platformCp, srcPath, outs, cancelHandler)
|
||||
).awaitUninterruptibly();
|
||||
}
|
||||
finally {
|
||||
myCancelHandler = null;
|
||||
ExternalJavacProcess.this.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final CancelHandler cancelHandler = new CancelHandler();
|
||||
myCancelHandlers.add(cancelHandler);
|
||||
SharedThreadPool.getInstance().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
context.channel()
|
||||
.writeAndFlush(compile(context, sessionId, options, files, cp, platformCp, srcPath, outs, cancelHandler));
|
||||
}
|
||||
finally {
|
||||
myCancelHandlers.remove(cancelHandler);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (requestType == JavacRemoteProto.Message.Request.Type.CANCEL){
|
||||
cancelBuilds();
|
||||
reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createRequestAckResponse());
|
||||
cancelBuild();
|
||||
}
|
||||
else if (requestType == JavacRemoteProto.Message.Request.Type.SHUTDOWN){
|
||||
cancelBuilds();
|
||||
cancelBuild();
|
||||
new Thread("StopThread") {
|
||||
@Override
|
||||
public void run() {
|
||||
//noinspection finally
|
||||
try {
|
||||
JavacServer.this.stop();
|
||||
}
|
||||
finally {
|
||||
System.exit(0);
|
||||
}
|
||||
ExternalJavacProcess.this.stop();
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
@@ -274,46 +286,38 @@ public class JavacServer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
private static final class ChannelRegistrar extends ChannelInboundHandlerAdapter {
|
||||
private final ChannelGroup openChannels = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
|
||||
|
||||
public boolean isEmpty() {
|
||||
return openChannels.isEmpty();
|
||||
}
|
||||
|
||||
public void add(@NotNull Channel serverChannel) {
|
||||
assert serverChannel instanceof ServerChannel;
|
||||
openChannels.add(serverChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext context) throws Exception {
|
||||
// we don't need to remove channel on close - ChannelGroup do it
|
||||
openChannels.add(context.channel());
|
||||
|
||||
super.channelActive(context);
|
||||
}
|
||||
|
||||
public ChannelGroupFuture close() {
|
||||
EventLoopGroup eventLoopGroup = null;
|
||||
for (Channel channel : openChannels) {
|
||||
if (channel instanceof ServerChannel) {
|
||||
eventLoopGroup = channel.eventLoop().parent();
|
||||
break;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
try {
|
||||
//final long stopStart = System.currentTimeMillis();
|
||||
//System.err.println("Exiting. Since global start " + (stopStart - myGlobalStart));
|
||||
final ChannelFuture future = myConnectFuture;
|
||||
if (future != null) {
|
||||
future.channel().close().await();
|
||||
}
|
||||
myEventLoopGroup.shutdownGracefully(0, 15, TimeUnit.SECONDS).await();
|
||||
//final long stopEnd = System.currentTimeMillis();
|
||||
//System.err.println("Stop completed in " + (stopEnd - stopStart) + "ms; since global start: " + ((stopEnd - myGlobalStart)));
|
||||
System.exit(0);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
ChannelGroupFuture future;
|
||||
try {
|
||||
future = openChannels.close();
|
||||
}
|
||||
finally {
|
||||
assert eventLoopGroup != null;
|
||||
eventLoopGroup.shutdownGracefully();
|
||||
}
|
||||
return future;
|
||||
private static List<File> toFiles(List<String> paths) {
|
||||
final List<File> files = new ArrayList<File>(paths.size());
|
||||
for (String path : paths) {
|
||||
files.add(new File(path));
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
public void cancelBuild() {
|
||||
final CancelHandler cancelHandler = myCancelHandler;
|
||||
if (cancelHandler != null) {
|
||||
cancelHandler.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,4 +336,4 @@ public class JavacServer {
|
||||
return myIsCanceled;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.jps.javac;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.group.ChannelGroup;
|
||||
import io.netty.channel.group.ChannelGroupFuture;
|
||||
import io.netty.channel.group.DefaultChannelGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.protobuf.ProtobufDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufEncoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
|
||||
import io.netty.util.AttributeKey;
|
||||
import io.netty.util.concurrent.ImmediateEventExecutor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.java.JavaCompilingTool;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.GlobalContextKey;
|
||||
import org.jetbrains.jps.incremental.Utils;
|
||||
import org.jetbrains.jps.model.JpsProject;
|
||||
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
|
||||
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration;
|
||||
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerOptions;
|
||||
import org.jetbrains.jps.service.SharedThreadPool;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public class ExternalJavacServer {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.javac.ExternalJavacServer");
|
||||
public static final GlobalContextKey<ExternalJavacServer> KEY = GlobalContextKey.create("_external_javac_server_");
|
||||
|
||||
public static final int DEFAULT_SERVER_PORT = 7878;
|
||||
private static final AttributeKey<JavacProcessDescriptor> SESSION_DESCRIPTOR = AttributeKey.valueOf("ExternalJavacServer.JavacProcessDescriptor");
|
||||
|
||||
private ChannelRegistrar myChannelRegistrar;
|
||||
private final Map<UUID, JavacProcessDescriptor> myMessageHandlers = new HashMap<UUID, JavacProcessDescriptor>();
|
||||
private int myListenPort = DEFAULT_SERVER_PORT;
|
||||
|
||||
public void start(int listenPort) {
|
||||
final ServerBootstrap bootstrap = new ServerBootstrap().group(new NioEventLoopGroup(1, SharedThreadPool.getInstance())).channel(NioServerSocketChannel.class);
|
||||
bootstrap.childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
myChannelRegistrar = new ChannelRegistrar();
|
||||
final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler();
|
||||
bootstrap.childHandler(new ChannelInitializer() {
|
||||
@Override
|
||||
protected void initChannel(Channel channel) throws Exception {
|
||||
channel.pipeline().addLast(myChannelRegistrar,
|
||||
new ProtobufVarint32FrameDecoder(),
|
||||
new ProtobufDecoder(JavacRemoteProto.Message.getDefaultInstance()),
|
||||
new ProtobufVarint32LengthFieldPrepender(),
|
||||
new ProtobufEncoder(),
|
||||
compilationRequestsHandler);
|
||||
}
|
||||
});
|
||||
myChannelRegistrar.add(bootstrap.bind(listenPort).syncUninterruptibly().channel());
|
||||
myListenPort = listenPort;
|
||||
}
|
||||
|
||||
private static int getExternalJavacHeapSize(CompileContext context) {
|
||||
final JpsProject project = context.getProjectDescriptor().getProject();
|
||||
final JpsJavaCompilerConfiguration config = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project);
|
||||
final JpsJavaCompilerOptions options = config.getCurrentCompilerOptions();
|
||||
return options.MAXIMUM_HEAP_SIZE;
|
||||
}
|
||||
|
||||
|
||||
public boolean forkJavac(CompileContext context, List<String> options,
|
||||
List<String> vmOptions, Collection<File> files,
|
||||
Collection<File> classpath,
|
||||
Collection<File> platformCp,
|
||||
Collection<File> sourcePath,
|
||||
Map<File, Set<File>> outs,
|
||||
DiagnosticOutputConsumer diagnosticSink,
|
||||
OutputFileConsumer outputSink,
|
||||
final String javaHome, final JavaCompilingTool compilingTool) {
|
||||
final ExternalJavacMessageHandler rh = new ExternalJavacMessageHandler(diagnosticSink, outputSink, getEncodingName(options));
|
||||
final JavacRemoteProto.Message.Request request = JavacProtoUtil.createCompilationRequest(options, files, classpath, platformCp, sourcePath, outs);
|
||||
final UUID uuid = UUID.randomUUID();
|
||||
final JavacProcessDescriptor processDescriptor = new JavacProcessDescriptor(uuid, rh, request);
|
||||
synchronized (myMessageHandlers) {
|
||||
myMessageHandlers.put(uuid, processDescriptor);
|
||||
}
|
||||
try {
|
||||
final JavacServerBootstrap.ExternalJavacProcessHandler processHandler = JavacServerBootstrap.launchExternalJavacProcess(
|
||||
uuid, javaHome, getExternalJavacHeapSize(context), myListenPort, Utils.getSystemRoot(), vmOptions, compilingTool
|
||||
);
|
||||
|
||||
while (!processDescriptor.waitFor(300L)) {
|
||||
if (processHandler.isProcessTerminated() && processDescriptor.channel == null && processHandler.getExitCode() != 0) {
|
||||
// process terminated abnormally and no communication took place
|
||||
processDescriptor.setDone();
|
||||
break;
|
||||
}
|
||||
if (context.getCancelStatus().isCanceled()) {
|
||||
processDescriptor.cancelBuild();
|
||||
}
|
||||
}
|
||||
|
||||
return rh.isTerminatedSuccessfully();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.info(e);
|
||||
diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage()));
|
||||
}
|
||||
finally {
|
||||
unregisterMessageHandler(uuid);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void unregisterMessageHandler(UUID uuid) {
|
||||
final JavacProcessDescriptor descriptor;
|
||||
synchronized (myMessageHandlers) {
|
||||
descriptor = myMessageHandlers.remove(uuid);
|
||||
}
|
||||
if (descriptor != null) {
|
||||
descriptor.setDone();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEncodingName(List<String> options) {
|
||||
boolean found = false;
|
||||
for (String option : options) {
|
||||
if (found) {
|
||||
return option;
|
||||
}
|
||||
if ("-encoding".equalsIgnoreCase(option)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
myChannelRegistrar.close().awaitUninterruptibly();
|
||||
}
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
private class CompilationRequestsHandler extends SimpleChannelInboundHandler<JavacRemoteProto.Message> {
|
||||
@Override
|
||||
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
|
||||
JavacProcessDescriptor descriptor = ctx.attr(SESSION_DESCRIPTOR).get();
|
||||
if (descriptor != null) {
|
||||
descriptor.setDone();
|
||||
}
|
||||
super.channelUnregistered(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead0(final ChannelHandlerContext context, JavacRemoteProto.Message message) throws Exception {
|
||||
JavacProcessDescriptor descriptor = context.attr(SESSION_DESCRIPTOR).get();
|
||||
|
||||
UUID sessionId;
|
||||
if (descriptor == null) {
|
||||
// this is the first message for this session, so fill session data with missing info
|
||||
sessionId = JavacProtoUtil.fromProtoUUID(message.getSessionId());
|
||||
|
||||
descriptor = myMessageHandlers.get(sessionId);
|
||||
if (descriptor != null) {
|
||||
descriptor.channel = context.channel();
|
||||
context.attr(SESSION_DESCRIPTOR).set(descriptor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sessionId = descriptor.sessionId;
|
||||
}
|
||||
|
||||
final ExternalJavacMessageHandler handler = descriptor != null? descriptor.handler : null;
|
||||
|
||||
final JavacRemoteProto.Message.Type messageType = message.getMessageType();
|
||||
|
||||
JavacRemoteProto.Message reply = null;
|
||||
try {
|
||||
if (messageType == JavacRemoteProto.Message.Type.RESPONSE) {
|
||||
final JavacRemoteProto.Message.Response response = message.getResponse();
|
||||
final JavacRemoteProto.Message.Response.Type responseType = response.getResponseType();
|
||||
if (handler != null) {
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.REQUEST_ACK) {
|
||||
final JavacRemoteProto.Message.Request request = descriptor.request;
|
||||
if (request != null) {
|
||||
reply = JavacProtoUtil.toMessage(sessionId, request);
|
||||
descriptor.request = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
final boolean terminateOk = handler.handleMessage(message);
|
||||
if (terminateOk) {
|
||||
descriptor.setDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createCancelRequest());
|
||||
}
|
||||
}
|
||||
else {
|
||||
reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createFailure("Unsupported message: " + messageType.name(), null));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (reply != null) {
|
||||
context.channel().writeAndFlush(reply);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
private static final class ChannelRegistrar extends ChannelInboundHandlerAdapter {
|
||||
private final ChannelGroup openChannels = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
|
||||
|
||||
public boolean isEmpty() {
|
||||
return openChannels.isEmpty();
|
||||
}
|
||||
|
||||
public void add(@NotNull Channel serverChannel) {
|
||||
assert serverChannel instanceof ServerChannel;
|
||||
openChannels.add(serverChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext context) throws Exception {
|
||||
// we don't need to remove channel on close - ChannelGroup do it
|
||||
openChannels.add(context.channel());
|
||||
super.channelActive(context);
|
||||
}
|
||||
|
||||
public ChannelGroupFuture close() {
|
||||
EventLoopGroup eventLoopGroup = null;
|
||||
for (Channel channel : openChannels) {
|
||||
if (channel instanceof ServerChannel) {
|
||||
eventLoopGroup = channel.eventLoop().parent();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ChannelGroupFuture future;
|
||||
try {
|
||||
future = openChannels.close();
|
||||
}
|
||||
finally {
|
||||
assert eventLoopGroup != null;
|
||||
eventLoopGroup.shutdownGracefully(0, 15, TimeUnit.SECONDS);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
||||
private static class JavacProcessDescriptor {
|
||||
@NotNull
|
||||
final UUID sessionId;
|
||||
@NotNull
|
||||
final ExternalJavacMessageHandler handler;
|
||||
volatile JavacRemoteProto.Message.Request request;
|
||||
volatile Channel channel;
|
||||
private final Semaphore myDone = new Semaphore();
|
||||
|
||||
public JavacProcessDescriptor(@NotNull UUID sessionId, @NotNull ExternalJavacMessageHandler handler, @NotNull JavacRemoteProto.Message.Request request) {
|
||||
this.sessionId = sessionId;
|
||||
this.handler = handler;
|
||||
this.request = request;
|
||||
myDone.down();
|
||||
}
|
||||
|
||||
public void cancelBuild() {
|
||||
if (channel != null) {
|
||||
channel.writeAndFlush(JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createCancelRequest()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setDone() {
|
||||
myDone.up();
|
||||
}
|
||||
|
||||
|
||||
public boolean waitFor(long timeout) {
|
||||
return myDone.waitFor(timeout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,11 +20,9 @@ import com.intellij.execution.process.ProcessAdapter;
|
||||
import com.intellij.execution.process.ProcessEvent;
|
||||
import com.intellij.execution.process.ProcessOutputTypes;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import org.jetbrains.jps.builders.java.JavaCompilingTool;
|
||||
import org.jetbrains.jps.cmdline.ClasspathBootstrap;
|
||||
import org.jetbrains.jps.service.SharedThreadPool;
|
||||
@@ -32,6 +30,7 @@ import org.jetbrains.jps.service.SharedThreadPool;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
@@ -40,15 +39,15 @@ import java.util.concurrent.Future;
|
||||
*/
|
||||
public class JavacServerBootstrap {
|
||||
|
||||
public static BaseOSProcessHandler launchJavacServer(String sdkHomePath,
|
||||
int heapSize,
|
||||
int port,
|
||||
File workingDir,
|
||||
List<String> vmOptions,
|
||||
JavaCompilingTool compilingTool) throws Exception {
|
||||
public static ExternalJavacProcessHandler launchExternalJavacProcess(UUID uuid, String sdkHomePath,
|
||||
int heapSize,
|
||||
int port,
|
||||
File workingDir,
|
||||
List<String> vmOptions,
|
||||
JavaCompilingTool compilingTool) throws Exception {
|
||||
final List<String> cmdLine = new ArrayList<String>();
|
||||
appendParam(cmdLine, getVMExecutablePath(sdkHomePath));
|
||||
appendParam(cmdLine, "-XX:MaxPermSize=150m");
|
||||
//appendParam(cmdLine, "-XX:MaxPermSize=150m");
|
||||
//appendParam(cmdLine, "-XX:ReservedCodeCacheSize=64m");
|
||||
appendParam(cmdLine, "-Djava.awt.headless=true");
|
||||
final int xms = heapSize / 2;
|
||||
@@ -59,7 +58,7 @@ public class JavacServerBootstrap {
|
||||
|
||||
// debugging
|
||||
//appendParam(cmdLine, "-XX:+HeapDumpOnOutOfMemoryError");
|
||||
//appendParam(cmdLine, "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5009");
|
||||
//appendParam(cmdLine, "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5009");
|
||||
|
||||
// javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language
|
||||
final String encoding = System.getProperty("file.encoding");
|
||||
@@ -83,18 +82,20 @@ public class JavacServerBootstrap {
|
||||
appendParam(cmdLine, "-Duser.region=" + region);
|
||||
}
|
||||
|
||||
appendParam(cmdLine, "-D" + JavacServer.JPS_JAVA_COMPILING_TOOL_PROPERTY + "=" + compilingTool.getId());
|
||||
appendParam(cmdLine, "-D" + ExternalJavacProcess.JPS_JAVA_COMPILING_TOOL_PROPERTY + "=" + compilingTool.getId());
|
||||
|
||||
// this will disable standard extensions to ensure javac is loaded from the right tools.jar
|
||||
appendParam(cmdLine, "-Djava.ext.dirs=");
|
||||
|
||||
|
||||
appendParam(cmdLine, "-Dlog4j.defaultInitOverride=true");
|
||||
|
||||
for (String option : vmOptions) {
|
||||
appendParam(cmdLine, option);
|
||||
}
|
||||
|
||||
appendParam(cmdLine, "-classpath");
|
||||
|
||||
final List<File> cp = ClasspathBootstrap.getJavacServerClasspath(sdkHomePath, compilingTool);
|
||||
final List<File> cp = ClasspathBootstrap.getExternalJavacProcessClasspath(sdkHomePath, compilingTool);
|
||||
final StringBuilder classpath = new StringBuilder();
|
||||
for (File file : cp) {
|
||||
if (classpath.length() > 0) {
|
||||
@@ -104,7 +105,9 @@ public class JavacServerBootstrap {
|
||||
}
|
||||
appendParam(cmdLine, classpath.toString());
|
||||
|
||||
appendParam(cmdLine, org.jetbrains.jps.javac.JavacServer.class.getName());
|
||||
appendParam(cmdLine, org.jetbrains.jps.javac.ExternalJavacProcess.class.getName());
|
||||
appendParam(cmdLine, uuid.toString());
|
||||
appendParam(cmdLine, "127.0.0.1");
|
||||
appendParam(cmdLine, Integer.toString(port));
|
||||
|
||||
workingDir.mkdirs();
|
||||
@@ -115,68 +118,31 @@ public class JavacServerBootstrap {
|
||||
builder.directory(workingDir);
|
||||
|
||||
final Process process = builder.start();
|
||||
final BaseOSProcessHandler processHandler = new BaseOSProcessHandler(process, null, null) {
|
||||
@Override
|
||||
protected Future<?> executeOnPooledThread(Runnable task) {
|
||||
return SharedThreadPool.getInstance().executeOnPooledThread(task);
|
||||
}
|
||||
};
|
||||
configureProcessHandler(processHandler);
|
||||
|
||||
return processHandler;
|
||||
}
|
||||
|
||||
private static void configureProcessHandler(final BaseOSProcessHandler processHandler) throws Exception {
|
||||
final ExternalJavacProcessHandler processHandler = new ExternalJavacProcessHandler(process);
|
||||
processHandler.addProcessListener(new ProcessAdapter() {
|
||||
@Override
|
||||
public void processTerminated(ProcessEvent event) {
|
||||
processHandler.setExitCode(event.getExitCode());
|
||||
}
|
||||
|
||||
public void onTextAvailable(ProcessEvent event, Key outputType) {
|
||||
final String text = event.getText();
|
||||
if (!StringUtil.isEmptyOrSpaces(text)) {
|
||||
if (outputType == ProcessOutputTypes.STDOUT) {
|
||||
System.out.print("JAVAC_SERVER: " + text);
|
||||
System.out.print("JAVAC_PROCESS: " + text);
|
||||
}
|
||||
else if (outputType == ProcessOutputTypes.STDERR){
|
||||
System.err.print("JAVAC_SERVER: " + text);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
final Semaphore semaphore = new Semaphore();
|
||||
semaphore.down();
|
||||
final Ref<String> serverStartMessage = new Ref<String>(null);
|
||||
processHandler.addProcessListener(new ProcessAdapter() {
|
||||
public void processTerminated(ProcessEvent event) {
|
||||
try {
|
||||
processHandler.removeProcessListener(this);
|
||||
}
|
||||
finally {
|
||||
semaphore.up();
|
||||
}
|
||||
}
|
||||
|
||||
public void onTextAvailable(ProcessEvent event, Key outputType) {
|
||||
if (outputType == ProcessOutputTypes.STDERR) {
|
||||
final String text = event.getText();
|
||||
if (text != null && (text.contains(JavacServer.SERVER_SUCCESS_START_MESSAGE) || text.contains(JavacServer.SERVER_ERROR_START_MESSAGE))) {
|
||||
try {
|
||||
processHandler.removeProcessListener(this);
|
||||
serverStartMessage.set(text);
|
||||
}
|
||||
finally {
|
||||
semaphore.up();
|
||||
}
|
||||
else if (outputType == ProcessOutputTypes.STDERR) {
|
||||
System.err.print("JAVAC_PROCESS: " + text);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
processHandler.startNotify();
|
||||
semaphore.waitFor();
|
||||
|
||||
final String startupMsg = serverStartMessage.get();
|
||||
if (startupMsg == null || !startupMsg.contains(JavacServer.SERVER_SUCCESS_START_MESSAGE)) {
|
||||
throw new Exception("Server startup failed: " + startupMsg);
|
||||
}
|
||||
return processHandler;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void appendParam(List<String> cmdLine, String param) {
|
||||
if (SystemInfo.isWindows) {
|
||||
if (param.contains("\"")) {
|
||||
@@ -192,4 +158,25 @@ public class JavacServerBootstrap {
|
||||
public static String getVMExecutablePath(String sdkHome) {
|
||||
return sdkHome + "/bin/java";
|
||||
}
|
||||
|
||||
public static class ExternalJavacProcessHandler extends BaseOSProcessHandler {
|
||||
private volatile int myExitCode;
|
||||
|
||||
ExternalJavacProcessHandler(Process process) {
|
||||
super(process, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Future<?> executeOnPooledThread(Runnable task) {
|
||||
return SharedThreadPool.getInstance().executeOnPooledThread(task);
|
||||
}
|
||||
|
||||
void setExitCode(int exitCode) {
|
||||
myExitCode = exitCode;
|
||||
}
|
||||
|
||||
public int getExitCode() {
|
||||
return myExitCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.jps.javac;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.api.RequestFuture;
|
||||
import org.jetbrains.jps.client.SimpleProtobufClient;
|
||||
import org.jetbrains.jps.client.UUIDGetter;
|
||||
import org.jetbrains.jps.service.SharedThreadPool;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
public class JavacServerClient extends SimpleProtobufClient<JavacServerResponseHandler>{
|
||||
|
||||
public JavacServerClient() {
|
||||
super(JavacRemoteProto.Message.getDefaultInstance(), SharedThreadPool.getInstance(), new UUIDGetter() {
|
||||
@Override
|
||||
@NotNull
|
||||
public UUID getSessionUUID(@NotNull JavacRemoteProto.Message message) {
|
||||
final JavacRemoteProto.Message.UUID uuid = message.getSessionId();
|
||||
return new UUID(uuid.getMostSigBits(), uuid.getLeastSigBits());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public RequestFuture<JavacServerResponseHandler> sendCompileRequest(List<String> options, Collection<File> files, Collection<File> classpath, Collection<File> platformCp, Collection<File> sourcePath, Map<File, Set<File>> outs, DiagnosticOutputConsumer diagnosticSink, OutputFileConsumer outputSink) {
|
||||
final JavacServerResponseHandler rh = new JavacServerResponseHandler(diagnosticSink, outputSink, getEncodingName(options));
|
||||
final JavacRemoteProto.Message.Request request = JavacProtoUtil.createCompilationRequest(options, files, classpath, platformCp, sourcePath, outs);
|
||||
return sendRequest(request, rh, new RequestFuture.CancelAction<JavacServerResponseHandler>() {
|
||||
@Override
|
||||
public void cancel(RequestFuture<JavacServerResponseHandler> javacServerResponseHandlerRequestFuture) throws Exception {
|
||||
sendRequest(JavacProtoUtil.createCancelRequest(), null, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public RequestFuture sendShutdownRequest() {
|
||||
return sendRequest(JavacProtoUtil.createShutdownRequest(), null, null);
|
||||
}
|
||||
|
||||
private RequestFuture<JavacServerResponseHandler> sendRequest(final JavacRemoteProto.Message.Request request, final JavacServerResponseHandler responseHandler, final RequestFuture.CancelAction<JavacServerResponseHandler> cancelAction) {
|
||||
final UUID requestId = UUID.randomUUID();
|
||||
return sendMessage(requestId, JavacProtoUtil.toMessage(requestId, request), responseHandler, cancelAction);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEncodingName(List<String> options) {
|
||||
boolean found = false;
|
||||
for (String option : options) {
|
||||
if (found) {
|
||||
return option;
|
||||
}
|
||||
if ("-encoding".equalsIgnoreCase(option)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.jps.javac;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.MessageLite;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.client.ProtobufResponseHandler;
|
||||
import org.jetbrains.jps.incremental.BinaryContent;
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
public class JavacServerResponseHandler implements ProtobufResponseHandler{
|
||||
private final DiagnosticOutputConsumer myDiagnosticSink;
|
||||
private final OutputFileConsumer myOutputSink;
|
||||
@Nullable
|
||||
private final String myEncodingName;
|
||||
private volatile boolean myTerminatedSuccessfully;
|
||||
|
||||
public JavacServerResponseHandler(DiagnosticOutputConsumer diagnosticSink, OutputFileConsumer outputSink, @Nullable final String encodingName) {
|
||||
myDiagnosticSink = diagnosticSink;
|
||||
myOutputSink = outputSink;
|
||||
myEncodingName = encodingName;
|
||||
}
|
||||
|
||||
public boolean handleMessage(MessageLite message) throws Exception {
|
||||
final JavacRemoteProto.Message msg = (JavacRemoteProto.Message)message;
|
||||
final JavacRemoteProto.Message.Type messageType = msg.getMessageType();
|
||||
|
||||
if (messageType == JavacRemoteProto.Message.Type.RESPONSE) {
|
||||
final JavacRemoteProto.Message.Response response = msg.getResponse();
|
||||
final JavacRemoteProto.Message.Response.Type responseType = response.getResponseType();
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_MESSAGE) {
|
||||
final JavacRemoteProto.Message.Response.CompileMessage compileMessage = response.getCompileMessage();
|
||||
final JavacRemoteProto.Message.Response.CompileMessage.Kind messageKind = compileMessage.getKind();
|
||||
|
||||
if (messageKind == JavacRemoteProto.Message.Response.CompileMessage.Kind.STD_OUT) {
|
||||
if (compileMessage.hasText()) {
|
||||
myDiagnosticSink.outputLineAvailable(compileMessage.getText());
|
||||
}
|
||||
}
|
||||
else {
|
||||
final String sourceUri = compileMessage.hasSourceUri()? compileMessage.getSourceUri() : null;
|
||||
final JavaFileObject srcFileObject = sourceUri != null? new DummyJavaFileObject(URI.create(sourceUri)) : null;
|
||||
myDiagnosticSink.report(new DummyDiagnostic(convertKind(messageKind), srcFileObject, compileMessage));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.OUTPUT_OBJECT) {
|
||||
final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
|
||||
final JavacRemoteProto.Message.Response.OutputObject.Kind kind = outputObject.getKind();
|
||||
|
||||
final String outputRoot = outputObject.hasOutputRoot()? outputObject.getOutputRoot() : null;
|
||||
final File outputRootFile = outputRoot != null? new File(outputRoot) : null;
|
||||
|
||||
final BinaryContent fileObjectContent;
|
||||
final ByteString content = outputObject.hasContent()? outputObject.getContent() : null;
|
||||
if (content != null) {
|
||||
final byte[] bytes = content.toByteArray();
|
||||
fileObjectContent = new BinaryContent(bytes, 0, bytes.length);
|
||||
}
|
||||
else {
|
||||
fileObjectContent = null;
|
||||
}
|
||||
|
||||
final String sourceUri = outputObject.hasSourceUri()? outputObject.getSourceUri() : null;
|
||||
final URI srcUri = sourceUri != null? URI.create(sourceUri) : null;
|
||||
final OutputFileObject fileObject = new OutputFileObject(
|
||||
null,
|
||||
outputRootFile,
|
||||
outputObject.hasRelativePath()? outputObject.getRelativePath() : null,
|
||||
new File(outputObject.getFilePath()),
|
||||
convertKind(kind),
|
||||
outputObject.hasClassName()? outputObject.getClassName() : null,
|
||||
srcUri,
|
||||
myEncodingName, fileObjectContent
|
||||
);
|
||||
|
||||
myOutputSink.save(fileObject);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.SRC_FILE_LOADED) {
|
||||
final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
|
||||
final File file = new File(outputObject.getFilePath());
|
||||
myDiagnosticSink.javaFileLoaded(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.CLASS_DATA) {
|
||||
final JavacRemoteProto.Message.Response.ClassData data = response.getClassData();
|
||||
final String className = data.getClassName();
|
||||
final Collection<String> imports = data.getImportStatementList();
|
||||
final Collection<String> staticImports = data.getStaticImportList();
|
||||
myDiagnosticSink.registerImports(className, imports, staticImports);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_COMPLETED) {
|
||||
if (response.hasCompletionStatus()) {
|
||||
myTerminatedSuccessfully = response.getCompletionStatus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (responseType == JavacRemoteProto.Message.Response.Type.REQUEST_ACK) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Exception("Unsupported response type: " + responseType.name());
|
||||
}
|
||||
|
||||
if (messageType == JavacRemoteProto.Message.Type.FAILURE) {
|
||||
final JavacRemoteProto.Message.Failure failure = msg.getFailure();
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
if (failure.hasDescription()) {
|
||||
buf.append(failure.getDescription());
|
||||
}
|
||||
if (failure.hasStacktrace()) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append("\n");
|
||||
}
|
||||
buf.append(failure.getStacktrace());
|
||||
}
|
||||
myDiagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, buf.toString()));
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Exception("Unsupported message type: " + messageType.name());
|
||||
}
|
||||
|
||||
public boolean isTerminatedSuccessfully() {
|
||||
return myTerminatedSuccessfully;
|
||||
}
|
||||
|
||||
private static Diagnostic.Kind convertKind(JavacRemoteProto.Message.Response.CompileMessage.Kind kind) {
|
||||
switch (kind) {
|
||||
case ERROR: return Diagnostic.Kind.ERROR;
|
||||
case WARNING: return Diagnostic.Kind.WARNING;
|
||||
case MANDATORY_WARNING: return Diagnostic.Kind.MANDATORY_WARNING;
|
||||
case NOTE: return Diagnostic.Kind.NOTE;
|
||||
default : return Diagnostic.Kind.OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
private static OutputFileObject.Kind convertKind(JavacRemoteProto.Message.Response.OutputObject.Kind kind) {
|
||||
switch (kind) {
|
||||
case CLASS: return JavaFileObject.Kind.CLASS;
|
||||
case HTML: return JavaFileObject.Kind.HTML;
|
||||
case SOURCE: return JavaFileObject.Kind.SOURCE;
|
||||
default : return JavaFileObject.Kind.OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
public void sessionTerminated() {
|
||||
}
|
||||
|
||||
private static class DummyDiagnostic implements Diagnostic<JavaFileObject> {
|
||||
|
||||
private final Kind myMessageKind;
|
||||
private final JavaFileObject mySrcFileObject;
|
||||
private final JavacRemoteProto.Message.Response.CompileMessage myCompileMessage;
|
||||
|
||||
public DummyDiagnostic(final Kind messageKind, JavaFileObject srcFileObject, JavacRemoteProto.Message.Response.CompileMessage compileMessage) {
|
||||
myMessageKind = messageKind;
|
||||
mySrcFileObject = srcFileObject;
|
||||
myCompileMessage = compileMessage;
|
||||
}
|
||||
|
||||
public Kind getKind() {
|
||||
return myMessageKind;
|
||||
}
|
||||
|
||||
public JavaFileObject getSource() {
|
||||
return mySrcFileObject;
|
||||
}
|
||||
|
||||
public long getPosition() {
|
||||
return myCompileMessage.hasProblemLocationOffset()? myCompileMessage.getProblemLocationOffset() : -1;
|
||||
}
|
||||
|
||||
public long getStartPosition() {
|
||||
return myCompileMessage.hasProblemBeginOffset()? myCompileMessage.getProblemBeginOffset() : -1;
|
||||
}
|
||||
|
||||
public long getEndPosition() {
|
||||
return myCompileMessage.hasProblemEndOffset()? myCompileMessage.getProblemEndOffset() : -1;
|
||||
}
|
||||
|
||||
public long getLineNumber() {
|
||||
return myCompileMessage.hasLine()? myCompileMessage.getLine() : -1;
|
||||
}
|
||||
|
||||
public long getColumnNumber() {
|
||||
return myCompileMessage.hasColumn()? myCompileMessage.getColumn() : -1;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getMessage(Locale locale) {
|
||||
return myCompileMessage.hasText()? myCompileMessage.getText() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,5 +19,5 @@ package org.jetbrains.jps.model.java;
|
||||
* @author nik
|
||||
*/
|
||||
public enum LanguageLevel {
|
||||
JDK_1_3, JDK_1_4, JDK_1_5, JDK_1_6, JDK_1_7, JDK_1_8
|
||||
JDK_1_3, JDK_1_4, JDK_1_5, JDK_1_6, JDK_1_7, JDK_1_8, JDK_1_9
|
||||
}
|
||||
|
||||
@@ -191,9 +191,6 @@ compiler.process.use.memory.temp.cache=true
|
||||
compiler.process.use.memory.temp.cache.description=Store temporary data in memory for faster compilation;\
|
||||
requires larger heap size for the build process. If parallel build is enabled, the option is ignored and temp data is always stored in memory.
|
||||
|
||||
compiler.process.use.external.javac=false
|
||||
compiler.process.use.external.javac.description=Run javac compiler in a separate process (allows to run build process with smaller heap size).
|
||||
|
||||
compiler.process.debug.port=-1
|
||||
|
||||
compiler.automake.trigger.delay=300
|
||||
|
||||
Reference in New Issue
Block a user