diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index 147dcd6e2039..dd13cc50702d 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -86,6 +86,7 @@ import com.intellij.util.Function; import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.ThrowableRunnable; import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.concurrency.SequentialTaskExecutor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.MultiMap; @@ -104,6 +105,7 @@ import org.jetbrains.jps.incremental.Utils; import javax.swing.*; import java.io.*; import java.util.*; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope; @@ -443,22 +445,36 @@ public class CompileDriver { final BuildManager buildManager = BuildManager.getInstance(); buildManager.cancelAutoMakeTasks(myProject); return buildManager.scheduleBuild(myProject, compileContext.isRebuild(), compileContext.isMake(), scopes, paths, builderParams, new DefaultMessageHandler(myProject) { + private final SequentialTaskExecutor myContextUpdater = new SequentialTaskExecutor(new Executor() { + @Override + public void execute(Runnable command) { + ApplicationManager.getApplication().executeOnPooledThread(command); + } + }); + @Override public void buildStarted(UUID sessionId) { } @Override - public void sessionTerminated(UUID sessionId) { + public void sessionTerminated(final UUID sessionId) { if (compileContext.shouldUpdateProblemsView()) { - final ProblemsView view = ProblemsViewImpl.SERVICE.getInstance(myProject); - view.clearProgress(); - view.clearOldMessages(compileContext.getCompileScope(), sessionId); + myContextUpdater.execute(new Runnable() { + @Override + public void run() { + if (!myProject.isDisposed()) { + final ProblemsView view = ProblemsViewImpl.SERVICE.getInstance(myProject); + view.clearProgress(); + view.clearOldMessages(compileContext.getCompileScope(), sessionId); + } + } + }); } } @Override public void handleFailure(UUID sessionId, CmdlineRemoteProto.Message.Failure failure) { - compileContext.addMessage(CompilerMessageCategory.ERROR, failure.getDescription(), null, -1, -1); + submitMessage(CompilerMessageCategory.ERROR, failure.getDescription(), null, -1, -1); final String trace = failure.getStacktrace(); if (trace != null) { LOG.info(trace); @@ -471,9 +487,10 @@ public class CompileDriver { protected void handleCompileMessage(UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage.CompileMessage message) { final CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind kind = message.getKind(); //System.out.println(compilerMessage.getText()); + final String messageText = message.getText(); if (kind == CmdlineRemoteProto.Message.BuilderMessage.CompileMessage.Kind.PROGRESS) { final ProgressIndicator indicator = compileContext.getProgressIndicator(); - indicator.setText(message.getText()); + indicator.setText(messageText); if (message.hasDone()) { indicator.setFraction(message.getDone()); } @@ -489,12 +506,19 @@ public class CompileDriver { final long line = message.hasLine() ? message.getLine() : -1; final long column = message.hasColumn() ? message.getColumn() : -1; final String srcUrl = sourceFilePath != null ? VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, sourceFilePath) : null; - compileContext.addMessage( - category, message.getText(), srcUrl, (int)line, (int)column - ); + submitMessage(category, messageText, srcUrl, (int)line, (int)column); } } + private void submitMessage(final CompilerMessageCategory category, final String messageText, final String srcUrl, final int line, final int column) { + myContextUpdater.execute(new Runnable() { + @Override + public void run() { + compileContext.addMessage(category, messageText, srcUrl, line, column); + } + }); + } + @Override protected void handleBuildEvent(UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage.BuildEvent event) { final CmdlineRemoteProto.Message.BuilderMessage.BuildEvent.Type eventType = event.getEventType(); diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index 6fb2c80e3d80..50cd59e5b758 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -506,16 +506,25 @@ public class BuildManager implements ApplicationComponent{ CmdlineProtoUtil.createForceCompileRequest(projectPath, scopes, paths, userData, globals, currentFSChanges); } - myMessageDispatcher.registerBuildMessageHandler(sessionId, handler, params); + myMessageDispatcher.registerBuildMessageHandler(sessionId, new BuilderMessageHandlerWrapper(handler) { + @Override + public void sessionTerminated(UUID sessionId) { + try { + super.sessionTerminated(sessionId); + } + finally { + future.setDone(); + } + } + }, params); try { projectTaskQueue.submit(new Runnable() { @Override public void run() { + ExecutionException execFailure = null; try { if (project.isDisposed()) { - myMessageDispatcher.unregisterBuildMessageHandler(sessionId); - handler.sessionTerminated(sessionId); return; } myBuildsInProgress.put(projectPath, future); @@ -528,14 +537,6 @@ public class BuildManager implements ApplicationComponent{ }; final StringBuilder stdErrOutput = new StringBuilder(); processHandler.addProcessListener(new ProcessAdapter() { - @Override - public void processTerminated(ProcessEvent event) { - final BuilderMessageHandler handler = myMessageDispatcher.unregisterBuildMessageHandler(sessionId); - if (handler != null) { - handler.sessionTerminated(sessionId); - } - } - @Override public void onTextAvailable(ProcessEvent event, Key outputType) { // re-translate builder's output to idea.log @@ -561,30 +562,39 @@ public class BuildManager implements ApplicationComponent{ else { msg.append("unknown error"); } - future.getMessageHandler().handleFailure(sessionId, CmdlineProtoUtil.createFailure(msg.toString(), null)); + handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(msg.toString(), null)); } } else { - future.getMessageHandler().handleFailure(sessionId, CmdlineProtoUtil.createFailure("Disconnected from build process", null)); + handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure("Disconnected from build process", null)); } } catch (ExecutionException e) { - myMessageDispatcher.unregisterBuildMessageHandler(sessionId); - handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e)); - handler.sessionTerminated(sessionId); + execFailure = e; } finally { myBuildsInProgress.remove(projectPath); - future.setDone(); + if (myMessageDispatcher.getAssociatedChannel(sessionId) == null) { + // either the connection has never been established (process not started or execution failed), or no messages were sent from the launched process. + // in this case the session cannot be unregistered by the message dispatcher + final BuilderMessageHandler unregistered = myMessageDispatcher.unregisterBuildMessageHandler(sessionId); + if (unregistered != null) { + if (execFailure != null) { + unregistered.handleFailure(sessionId, CmdlineProtoUtil.createFailure(execFailure.getMessage(), execFailure)); + } + unregistered.sessionTerminated(sessionId); + } + } } } }); } catch (Throwable e) { - myMessageDispatcher.unregisterBuildMessageHandler(sessionId); - handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e)); - handler.sessionTerminated(sessionId); - future.setDone(); + final BuilderMessageHandler unregistered = myMessageDispatcher.unregisterBuildMessageHandler(sessionId); + if (unregistered != null) { + unregistered.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e)); + unregistered.sessionTerminated(sessionId); + } } } }); @@ -905,6 +915,34 @@ public class BuildManager implements ApplicationComponent{ return builder.toString(); } + private static class BuilderMessageHandlerWrapper implements BuilderMessageHandler { + private final DefaultMessageHandler myHandler; + + public BuilderMessageHandlerWrapper(DefaultMessageHandler handler) { + myHandler = handler; + } + + @Override + public void buildStarted(UUID sessionId) { + myHandler.buildStarted(sessionId); + } + + @Override + public void handleBuildMessage(Channel channel, UUID sessionId, CmdlineRemoteProto.Message.BuilderMessage msg) { + myHandler.handleBuildMessage(channel, sessionId, msg); + } + + @Override + public void handleFailure(UUID sessionId, CmdlineRemoteProto.Message.Failure failure) { + myHandler.handleFailure(sessionId, failure); + } + + @Override + public void sessionTerminated(UUID sessionId) { + myHandler.sessionTerminated(sessionId); + } + } + private class ProjectWatcher extends ProjectManagerAdapter { private final Map myConnections = new HashMap(); diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java index 5b089127a738..0c49759f6405 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java @@ -61,14 +61,14 @@ class BuildMessageDispatcher extends SimpleChannelHandler { @Nullable public Channel getConnectedChannel(final UUID sessionId) { + final Channel channel = getAssociatedChannel(sessionId); + return channel != null && channel.isConnected()? channel : null; + } + + @Nullable + public Channel getAssociatedChannel(final UUID sessionId) { final SessionData data = myMessageHandlers.get(sessionId); - if (data != null) { - final Channel channel = data.channel; - if (channel != null && channel.isConnected()) { - return channel; - } - } - return null; + return data != null? data.channel : null; }