diff --git a/platform/platform-impl/src/org/jetbrains/io/ChannelExceptionHandler.java b/platform/platform-impl/src/org/jetbrains/io/ChannelExceptionHandler.java index 478a3fa35de7..3a026164b4ae 100644 --- a/platform/platform-impl/src/org/jetbrains/io/ChannelExceptionHandler.java +++ b/platform/platform-impl/src/org/jetbrains/io/ChannelExceptionHandler.java @@ -19,6 +19,7 @@ import com.intellij.openapi.diagnostic.Logger; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; +import org.jetbrains.annotations.NotNull; import java.net.ConnectException; @@ -31,6 +32,7 @@ public final class ChannelExceptionHandler extends ChannelHandlerAdapter { private ChannelExceptionHandler() { } + @NotNull public static ChannelHandler getInstance() { return INSTANCE; } diff --git a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java index 644cb35dacc6..fe91cde1ed72 100644 --- a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java +++ b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java @@ -63,12 +63,13 @@ public final class NettyUtil { } } - public static Channel connectClient(Bootstrap bootstrap, InetSocketAddress remoteAddress, ActionCallback asyncResult) { + @Nullable + public static Channel connectClient(@NotNull Bootstrap bootstrap, @NotNull InetSocketAddress remoteAddress, @Nullable ActionCallback asyncResult) { return connect(bootstrap, remoteAddress, asyncResult, DEFAULT_CONNECT_ATTEMPT_COUNT); } @Nullable - public static Channel connect(@NotNull Bootstrap bootstrap, @NotNull InetSocketAddress remoteAddress, @NotNull ActionCallback asyncResult, int maxAttemptCount) { + public static Channel connect(@NotNull Bootstrap bootstrap, @NotNull InetSocketAddress remoteAddress, @Nullable ActionCallback asyncResult, int maxAttemptCount) { try { int attemptCount = 0; @@ -85,7 +86,9 @@ public final class NettyUtil { else { @SuppressWarnings("ThrowableResultOfMethodCallIgnored") Throwable cause = future.cause(); - asyncResult.reject("Cannot connect: " + (cause == null ? "unknown error" : cause.getMessage())); + if (asyncResult != null) { + asyncResult.reject("Cannot connect: " + (cause == null ? "unknown error" : cause.getMessage())); + } return null; } } @@ -104,7 +107,9 @@ public final class NettyUtil { Thread.sleep(attemptCount * MIN_START_TIME); } else { - asyncResult.reject("Cannot connect: " + e.getMessage()); + if (asyncResult != null) { + asyncResult.reject("Cannot connect: " + e.getMessage()); + } return null; } } @@ -115,7 +120,9 @@ public final class NettyUtil { return channel; } catch (Throwable e) { - asyncResult.reject("Cannot connect: " + e.getMessage()); + if (asyncResult != null) { + asyncResult.reject("Cannot connect: " + e.getMessage()); + } return null; } } diff --git a/xml/impl/src/org/jetbrains/builtInWebServer/BuiltInWebServer.java b/xml/impl/src/org/jetbrains/builtInWebServer/BuiltInWebServer.java index 2dc24ba01706..b9a68518b364 100644 --- a/xml/impl/src/org/jetbrains/builtInWebServer/BuiltInWebServer.java +++ b/xml/impl/src/org/jetbrains/builtInWebServer/BuiltInWebServer.java @@ -110,7 +110,7 @@ public final class BuiltInWebServer extends HttpRequestHandler { else { projectName = host; } - return doProcess(request, context.channel(), projectName); + return doProcess(request, context, projectName); } public static boolean isOwnHostName(@NotNull String host) { @@ -135,7 +135,7 @@ public final class BuiltInWebServer extends HttpRequestHandler { } } - private static boolean doProcess(@NotNull FullHttpRequest request, @NotNull Channel channel, @Nullable String projectName) { + private static boolean doProcess(@NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context, @Nullable String projectName) { final String decodedPath = URLUtil.unescapePercentSequences(UriUtil.trimParameters(request.uri())); int offset; boolean emptyPath; @@ -163,7 +163,7 @@ public final class BuiltInWebServer extends HttpRequestHandler { } // we must redirect "jsdebug" to "jsdebug/" as nginx does, otherwise browser will treat it as file instead of directory, so, relative path will not work - WebServerPathHandler.redirectToDirectory(request, channel, projectName); + WebServerPathHandler.redirectToDirectory(request, context.channel(), projectName); return true; } @@ -172,7 +172,7 @@ public final class BuiltInWebServer extends HttpRequestHandler { for (WebServerPathHandler pathHandler : WebServerPathHandler.EP_NAME.getExtensions()) { try { - if (pathHandler.process(path, project, request, channel, projectName, decodedPath, isCustomHost)) { + if (pathHandler.process(path, project, request, context, projectName, decodedPath, isCustomHost)) { return true; } } diff --git a/xml/impl/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.java b/xml/impl/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.java index 1b4acb07556f..64843964f740 100644 --- a/xml/impl/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.java +++ b/xml/impl/src/org/jetbrains/builtInWebServer/DefaultWebServerPathHandler.java @@ -18,6 +18,7 @@ package org.jetbrains.builtInWebServer; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpResponseStatus; import org.jetbrains.annotations.NotNull; @@ -29,10 +30,11 @@ final class DefaultWebServerPathHandler extends WebServerPathHandler { public boolean process(@NotNull String path, @NotNull Project project, @NotNull FullHttpRequest request, - @NotNull Channel channel, + @NotNull ChannelHandlerContext context, @Nullable String projectName, @NotNull String decodedRawPath, boolean isCustomHost) { + Channel channel = context.channel(); WebServerPathToFileManager pathToFileManager = WebServerPathToFileManager.getInstance(project); VirtualFile result = pathToFileManager.pathToFileCache.getIfPresent(path); boolean indexUsed = false; diff --git a/xml/impl/src/org/jetbrains/builtInWebServer/NetService.java b/xml/impl/src/org/jetbrains/builtInWebServer/NetService.java new file mode 100644 index 000000000000..ed2648021029 --- /dev/null +++ b/xml/impl/src/org/jetbrains/builtInWebServer/NetService.java @@ -0,0 +1,183 @@ +package org.jetbrains.builtInWebServer; + +import com.intellij.concurrency.JobScheduler; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.filters.TextConsoleBuilder; +import com.intellij.execution.filters.TextConsoleBuilderFactory; +import com.intellij.execution.process.OSProcessHandler; +import com.intellij.execution.process.ProcessAdapter; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.ui.ConsoleView; +import com.intellij.execution.ui.ConsoleViewContentType; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.AsyncResult; +import com.intellij.openapi.util.AsyncValueLoader; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowAnchor; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.ui.content.ContentFactory; +import com.intellij.util.Consumer; +import com.intellij.util.net.NetUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.io.NettyUtil; + +import javax.swing.*; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +public abstract class NetService implements Disposable { + protected static final Logger LOG = Logger.getInstance(NetService.class); + + protected final Project project; + + protected final AsyncValueLoader processHandler = new AsyncValueLoader() { + @Override + protected boolean isCancelOnReject() { + return true; + } + + @Nullable + private OSProcessHandler doGetProcessHandler(int port) { + try { + return createProcessHandler(project, port); + } + catch (ExecutionException e) { + LOG.error(e); + return null; + } + } + + @Override + protected void load(@NotNull final AsyncResult result) throws IOException { + final int port = NetUtils.findAvailableSocketPort(); + final OSProcessHandler processHandler = doGetProcessHandler(port); + if (processHandler == null) { + result.setRejected(); + return; + } + + result.doWhenRejected(new Runnable() { + @Override + public void run() { + processHandler.destroyProcess(); + } + }); + + final MyProcessAdapter processListener = new MyProcessAdapter(); + processHandler.addProcessListener(processListener); + processHandler.startNotify(); + + if (result.isRejected()) { + return; + } + + JobScheduler.getScheduler().schedule(new Runnable() { + @Override + public void run() { + if (result.isRejected()) { + return; + } + + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + if (!result.isRejected()) { + try { + connectToProcess(result, port, processHandler, processListener); + } + catch (Throwable e) { + result.setRejected(); + LOG.error(e); + } + } + } + }); + } + }, NettyUtil.MIN_START_TIME, TimeUnit.MILLISECONDS); + } + + @Override + protected void disposeResult(@NotNull OSProcessHandler processHandler) { + try { + closeProcessConnections(); + } + finally { + processHandler.destroyProcess(); + } + } + }; + + private ConsoleView console; + + protected NetService(@NotNull Project project) { + this.project = project; + } + + @Nullable + protected abstract OSProcessHandler createProcessHandler(Project project, int port) throws ExecutionException; + + protected void connectToProcess(@NotNull AsyncResult asyncResult, int port, @NotNull OSProcessHandler processHandler, @NotNull Consumer errorOutputConsumer) { + asyncResult.setDone(processHandler); + } + + protected abstract void closeProcessConnections(); + + @Override + public void dispose() { + processHandler.reset(); + } + + protected void configureConsole(@NotNull TextConsoleBuilder consoleBuilder) { + } + + @NotNull + protected abstract String getConsoleToolWindowId(); + + @NotNull + protected abstract Icon getConsoleToolWindowIcon(); + + private final class MyProcessAdapter extends ProcessAdapter implements Consumer { + private void createConsole() { + TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project); + configureConsole(consoleBuilder); + console = consoleBuilder.getConsole(); + + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + ToolWindow toolWindow = ToolWindowManager.getInstance(project).registerToolWindow(getConsoleToolWindowId(), false, ToolWindowAnchor.BOTTOM, project, true); + toolWindow.setIcon(getConsoleToolWindowIcon()); + toolWindow.getContentManager().addContent(ContentFactory.SERVICE.getInstance().createContent(console.getComponent(), "", false)); + } + }, project.getDisposed()); + } + + @Override + public void onTextAvailable(ProcessEvent event, Key outputType) { + print(event.getText(), ConsoleViewContentType.getConsoleViewType(outputType)); + } + + private void print(String text, ConsoleViewContentType contentType) { + if (console == null) { + createConsole(); + } + console.print(text, contentType); + } + + @Override + public void processTerminated(ProcessEvent event) { + processHandler.reset(); + print(getConsoleToolWindowId() + " terminated\n", ConsoleViewContentType.SYSTEM_OUTPUT); + } + + @Override + public void consume(String message) { + print(message, ConsoleViewContentType.ERROR_OUTPUT); + } + } +} \ No newline at end of file diff --git a/xml/impl/src/org/jetbrains/builtInWebServer/SingleConnectionNetService.java b/xml/impl/src/org/jetbrains/builtInWebServer/SingleConnectionNetService.java new file mode 100644 index 000000000000..300f44bf4281 --- /dev/null +++ b/xml/impl/src/org/jetbrains/builtInWebServer/SingleConnectionNetService.java @@ -0,0 +1,42 @@ +package org.jetbrains.builtInWebServer; + +import com.intellij.execution.process.OSProcessHandler; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.AsyncResult; +import com.intellij.util.Consumer; +import com.intellij.util.net.NetUtils; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.io.NettyUtil; + +import java.net.InetSocketAddress; + +public abstract class SingleConnectionNetService extends NetService { + protected volatile Channel processChannel; + + protected SingleConnectionNetService(@NotNull Project project) { + super(project); + } + + protected abstract void configureBootstrap(@NotNull Bootstrap bootstrap, @NotNull Consumer errorOutputConsumer); + + @Override + protected void connectToProcess(@NotNull AsyncResult asyncResult, int port, @NotNull OSProcessHandler processHandler, @NotNull Consumer errorOutputConsumer) { + Bootstrap bootstrap = NettyUtil.oioClientBootstrap(); + configureBootstrap(bootstrap, errorOutputConsumer); + processChannel = NettyUtil.connectClient(bootstrap, new InetSocketAddress(NetUtils.getLoopbackAddress(), port), asyncResult); + if (processChannel != null) { + asyncResult.setDone(processHandler); + } + } + + @Override + protected void closeProcessConnections() { + Channel currentProcessChannel = processChannel; + if (currentProcessChannel != null) { + processChannel = null; + NettyUtil.closeAndReleaseFactory(currentProcessChannel); + } + } +} \ No newline at end of file diff --git a/xml/impl/src/org/jetbrains/builtInWebServer/WebServerPathHandler.java b/xml/impl/src/org/jetbrains/builtInWebServer/WebServerPathHandler.java index 807c3b31b49a..05d931f76b58 100644 --- a/xml/impl/src/org/jetbrains/builtInWebServer/WebServerPathHandler.java +++ b/xml/impl/src/org/jetbrains/builtInWebServer/WebServerPathHandler.java @@ -19,6 +19,7 @@ import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VfsUtil; import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,7 +39,7 @@ public abstract class WebServerPathHandler { public abstract boolean process(@NotNull String path, @NotNull Project project, @NotNull FullHttpRequest request, - @NotNull Channel channel, + @NotNull ChannelHandlerContext context, @Nullable String projectName, @NotNull String decodedRawPath, boolean isCustomHost); diff --git a/xml/impl/src/org/jetbrains/builtInWebServer/WebServerPathHandlerAdapter.java b/xml/impl/src/org/jetbrains/builtInWebServer/WebServerPathHandlerAdapter.java index a1f1e1790195..fd0a737c0089 100644 --- a/xml/impl/src/org/jetbrains/builtInWebServer/WebServerPathHandlerAdapter.java +++ b/xml/impl/src/org/jetbrains/builtInWebServer/WebServerPathHandlerAdapter.java @@ -16,22 +16,22 @@ package org.jetbrains.builtInWebServer; import com.intellij.openapi.project.Project; -import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.FullHttpRequest; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public abstract class WebServerPathHandlerAdapter extends WebServerPathHandler { - protected abstract boolean process(@NotNull String path, @NotNull Project project, @NotNull FullHttpRequest request, @NotNull Channel channel); + protected abstract boolean process(@NotNull String path, @NotNull Project project, @NotNull FullHttpRequest request, @NotNull ChannelHandlerContext context); @Override public final boolean process(@NotNull String path, @NotNull Project project, @NotNull FullHttpRequest request, - @NotNull Channel channel, + @NotNull ChannelHandlerContext context, @Nullable String projectName, @NotNull String decodedRawPath, boolean isCustomHost) { - return process(path, project, request, channel); + return process(path, project, request, context); } } \ No newline at end of file diff --git a/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java b/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java index 4a83b637500e..977d33e641da 100644 --- a/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java +++ b/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java @@ -8,6 +8,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.io.Responses; import org.jetbrains.io.SimpleChannelInboundHandlerAdapter; @@ -17,7 +18,7 @@ import static org.jetbrains.io.fastCgi.FastCgiService.LOG; public class FastCgiChannelHandler extends SimpleChannelInboundHandlerAdapter { private final ConcurrentIntObjectMap requestToChannel; - public FastCgiChannelHandler(ConcurrentIntObjectMap channel) { + public FastCgiChannelHandler(@NotNull ConcurrentIntObjectMap channel) { requestToChannel = channel; } diff --git a/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiService.java b/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiService.java index 54f13c6c8ea1..098403ab6cb8 100644 --- a/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiService.java +++ b/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiService.java @@ -1,151 +1,61 @@ package org.jetbrains.io.fastCgi; -import com.intellij.concurrency.JobScheduler; -import com.intellij.execution.filters.TextConsoleBuilder; -import com.intellij.execution.filters.TextConsoleBuilderFactory; -import com.intellij.execution.process.OSProcessHandler; -import com.intellij.execution.process.ProcessAdapter; -import com.intellij.execution.process.ProcessEvent; -import com.intellij.execution.ui.ConsoleView; -import com.intellij.execution.ui.ConsoleViewContentType; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.AsyncResult; -import com.intellij.openapi.util.AsyncValueLoader; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowAnchor; -import com.intellij.openapi.wm.ToolWindowManager; -import com.intellij.ui.content.ContentFactory; import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.StripedLockIntObjectConcurrentHashMap; -import com.intellij.util.net.NetUtils; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.handler.codec.http.HttpResponseStatus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.builtInWebServer.SingleConnectionNetService; import org.jetbrains.io.ChannelExceptionHandler; import org.jetbrains.io.NettyUtil; import org.jetbrains.io.Responses; -import javax.swing.*; -import java.io.IOException; -import java.net.InetSocketAddress; import java.util.List; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; // todo send FCGI_ABORT_REQUEST if client channel disconnected -public abstract class FastCgiService implements Disposable { +public abstract class FastCgiService extends SingleConnectionNetService { static final Logger LOG = Logger.getInstance(FastCgiService.class); - protected final Project project; - private final AtomicInteger requestIdCounter = new AtomicInteger(); - private final StripedLockIntObjectConcurrentHashMap requests = new StripedLockIntObjectConcurrentHashMap(); + protected final StripedLockIntObjectConcurrentHashMap requests = new StripedLockIntObjectConcurrentHashMap(); - private volatile Channel fastCgiChannel; - - protected final AsyncValueLoader processHandler = new AsyncValueLoader() { - @Override - protected boolean isCancelOnReject() { - return true; - } - - @Override - protected void load(@NotNull final AsyncResult result) throws IOException { - final int port = NetUtils.findAvailableSocketPort(); - final OSProcessHandler processHandler = createProcessHandler(project, port); - if (processHandler == null) { - result.setRejected(); - return; - } - - result.doWhenRejected(new Runnable() { - @Override - public void run() { - processHandler.destroyProcess(); - } - }); - - final MyProcessAdapter processListener = new MyProcessAdapter(); - processHandler.addProcessListener(processListener); - processHandler.startNotify(); - - if (result.isRejected()) { - return; - } - - JobScheduler.getScheduler().schedule(new Runnable() { - @Override - public void run() { - if (result.isRejected()) { - return; - } - - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - if (!result.isRejected()) { - try { - connectToProcess(result, port, processHandler, processListener); - } - catch (Throwable e) { - result.setRejected(); - LOG.error(e); - } - } - } - }); - } - }, NettyUtil.MIN_START_TIME, TimeUnit.MILLISECONDS); - } - - @Override - protected void disposeResult(@NotNull OSProcessHandler processHandler) { - try { - Channel currentFastCgiChannel = fastCgiChannel; - if (currentFastCgiChannel != null) { - fastCgiChannel = null; - NettyUtil.closeAndReleaseFactory(currentFastCgiChannel); - } - processHandler.destroyProcess(); - } - finally { - requestIdCounter.set(0); - if (!requests.isEmpty()) { - List waitingClients = ContainerUtil.toList(requests.elements()); - requests.clear(); - for (Channel channel : waitingClients) { - try { - if (channel.isActive()) { - Responses.sendStatus(HttpResponseStatus.BAD_GATEWAY, channel); - } - } - catch (Throwable e) { - NettyUtil.log(e, LOG); - } - } - } - } - } - }; - - private ConsoleView console; - - protected FastCgiService(Project project) { - this.project = project; + public FastCgiService(@NotNull Project project) { + super(project); } - protected abstract OSProcessHandler createProcessHandler(Project project, int port); + @Override + protected void closeProcessConnections() { + try { + super.closeProcessConnections(); + } + finally { + requestIdCounter.set(0); + if (!requests.isEmpty()) { + List waitingClients = ContainerUtil.toList(requests.elements()); + requests.clear(); + for (Channel channel : waitingClients) { + try { + if (channel.isActive()) { + Responses.sendStatus(HttpResponseStatus.BAD_GATEWAY, channel); + } + } + catch (Throwable e) { + NettyUtil.log(e, LOG); + } + } + } + } + } - private void connectToProcess(final AsyncResult asyncResult, final int port, final OSProcessHandler processHandler, final Consumer errorOutputConsumer) { - Bootstrap bootstrap = NettyUtil.oioClientBootstrap(); + @Override + protected void configureBootstrap(@NotNull Bootstrap bootstrap, @NotNull final Consumer errorOutputConsumer) { final FastCgiChannelHandler fastCgiChannelHandler = new FastCgiChannelHandler(requests); bootstrap.handler(new ChannelInitializer() { @Override @@ -153,23 +63,19 @@ public abstract class FastCgiService implements Disposable { channel.pipeline().addLast(new FastCgiDecoder(errorOutputConsumer), fastCgiChannelHandler, ChannelExceptionHandler.getInstance()); } }); - fastCgiChannel = NettyUtil.connectClient(bootstrap, new InetSocketAddress(NetUtils.getLoopbackAddress(), port), asyncResult); - if (fastCgiChannel != null) { - asyncResult.setDone(processHandler); - } } public void send(final FastCgiRequest fastCgiRequest, final ByteBuf content) { content.retain(); if (processHandler.has()) { - fastCgiRequest.writeToServerChannel(content, fastCgiChannel); + fastCgiRequest.writeToServerChannel(content, processChannel); } else { processHandler.get().doWhenDone(new Runnable() { @Override public void run() { - fastCgiRequest.writeToServerChannel(content, fastCgiChannel); + fastCgiRequest.writeToServerChannel(content, processChannel); } }).doWhenRejected(new Runnable() { @Override @@ -193,57 +99,4 @@ public abstract class FastCgiService implements Disposable { requests.put(requestId, channel); return requestId; } - - @Override - public void dispose() { - processHandler.reset(); - } - - protected abstract void buildConsole(@NotNull TextConsoleBuilder consoleBuilder); - - @NotNull - protected abstract String getConsoleToolWindowId(); - - @NotNull - protected abstract Icon getConsoleToolWindowIcon(); - - private final class MyProcessAdapter extends ProcessAdapter implements Consumer { - private void createConsole() { - TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project); - buildConsole(consoleBuilder); - console = consoleBuilder.getConsole(); - - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - ToolWindow toolWindow = ToolWindowManager.getInstance(project).registerToolWindow(getConsoleToolWindowId(), false, ToolWindowAnchor.BOTTOM, project, true); - toolWindow.setIcon(getConsoleToolWindowIcon()); - toolWindow.getContentManager().addContent(ContentFactory.SERVICE.getInstance().createContent(console.getComponent(), "", false)); - } - }, project.getDisposed()); - } - - @Override - public void onTextAvailable(ProcessEvent event, Key outputType) { - print(event.getText(), ConsoleViewContentType.getConsoleViewType(outputType)); - } - - private void print(String text, ConsoleViewContentType contentType) { - if (console == null) { - createConsole(); - } - console.print(text, contentType); - } - - @Override - public void processTerminated(ProcessEvent event) { - processHandler.reset(); - print(getConsoleToolWindowId() + " terminated\n", ConsoleViewContentType.SYSTEM_OUTPUT); - } - - @Override - public void consume(String message) { - print(message, ConsoleViewContentType.ERROR_OUTPUT); - } - } } \ No newline at end of file