IDEA-70152 close piped writer before closing reader [rev=andrey.zaytsev]
authorEugene Kudelevsky <Eugene.Kudelevsky@jetbrains.com>
Thu, 23 Jun 2011 16:48:50 +0000 (20:48 +0400)
committerEugene Kudelevsky <Eugene.Kudelevsky@jetbrains.com>
Thu, 23 Jun 2011 16:48:50 +0000 (20:48 +0400)
platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java
platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleListener.java [new file with mode: 0644]
plugins/android/src/org/jetbrains/android/logcat/AndroidLogcatToolWindowView.java
plugins/android/src/org/jetbrains/android/logcat/AndroidLogcatUtil.java
plugins/android/src/org/jetbrains/android/run/AndroidDebugRunner.java

index 7afb1c3dceb2dbc517bde793dc3d40bc0d6a2ac0..020a6448325e5f0a8234479857ab23ba8c27aecd 100644 (file)
@@ -50,6 +50,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.io.*;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -74,6 +75,8 @@ public abstract class LogConsoleBase extends AdditionalTabComponent implements L
   private final boolean myBuildInActions;
   private LogFilterModel myModel;
 
+  private final List<LogConsoleListener> myListeners = new ArrayList<LogConsoleListener>();
+
   private FilterComponent myFilter = new FilterComponent("LOG_FILTER_HISTORY", 5) {
     public void filter() {
       final Task.Backgroundable task = new Task.Backgroundable(myProject, APPLYING_FILTER_TITLE) {
@@ -285,6 +288,10 @@ public abstract class LogConsoleBase extends AdditionalTabComponent implements L
   }
 
   private void stopRunning(boolean checkActive) {
+    if (!checkActive) {
+      fireLoggingWillBeStopped();
+    }
+
     if (myReaderThread != null && myReaderThread.myReader != null) {
       if (!checkActive) {
         myReaderThread.stopRunning();
@@ -480,6 +487,16 @@ public abstract class LogConsoleBase extends AdditionalTabComponent implements L
     myProcessHandler.notifyTextAvailable(text, outputType);
   }
 
+  public void addListener(LogConsoleListener listener) {
+    myListeners.add(listener);
+  }
+
+  private void fireLoggingWillBeStopped() {
+    for (LogConsoleListener listener : myListeners) {
+      listener.loggingWillBeStopped();
+    }
+  }
+
   private static class LightProcessHandler extends ProcessHandler {
     protected void destroyProcessImpl() {
       throw new UnsupportedOperationException();
diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleListener.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleListener.java
new file mode 100644 (file)
index 0000000..e7770b5
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2000-2011 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 com.intellij.diagnostic.logging;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public interface LogConsoleListener {
+  void loggingWillBeStopped();
+}
index b583bee0f3d6ab16f4fc4080ccd6a671aeeff88f..6fcc445d2a31e3e08d80b0ef9e71afaa5003fb7c 100644 (file)
@@ -19,6 +19,7 @@ import com.android.ddmlib.AndroidDebugBridge;
 import com.android.ddmlib.IDevice;
 import com.android.ddmlib.Log;
 import com.intellij.diagnostic.logging.LogConsoleBase;
+import com.intellij.diagnostic.logging.LogConsoleListener;
 import com.intellij.diagnostic.logging.LogFilterModel;
 import com.intellij.facet.ProjectFacetManager;
 import com.intellij.openapi.Disposable;
@@ -27,6 +28,7 @@ import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Pair;
 import org.jetbrains.android.actions.AndroidEnableDdmsAction;
 import org.jetbrains.android.facet.AndroidFacet;
 import org.jetbrains.android.sdk.AndroidPlatform;
@@ -41,6 +43,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.io.IOException;
 import java.io.Reader;
+import java.io.Writer;
 import java.util.List;
 
 /**
@@ -58,7 +61,9 @@ public abstract class AndroidLogcatToolWindowView implements Disposable {
   private volatile IDevice myDevice;
   private final Object myLock = new Object();
   private final LogConsoleBase myLogConsole;
+
   private volatile Reader myCurrentReader;
+  private volatile Writer myCurrentWriter;
 
   private final AndroidDebugBridge.IDeviceChangeListener myDeviceChangeListener = new AndroidDebugBridge.IDeviceChangeListener() {
     public void deviceConnected(IDevice device) {
@@ -142,6 +147,19 @@ public abstract class AndroidLogcatToolWindowView implements Disposable {
         return AndroidLogcatToolWindowView.this.isActive();
       }
     };
+    myLogConsole.addListener(new LogConsoleListener() {
+      @Override
+      public void loggingWillBeStopped() {
+        if (myCurrentWriter != null) {
+          try {
+            myCurrentWriter.close();
+          }
+          catch (IOException e) {
+            LOG.error(e);
+          }
+        }
+      }
+    });
     mySearchComponentWrapper.add(myLogConsole.getSearchComponent());
     JComponent consoleComponent = myLogConsole.getComponent();
     DefaultActionGroup group = new DefaultActionGroup();
@@ -184,6 +202,14 @@ public abstract class AndroidLogcatToolWindowView implements Disposable {
     if (myDevice != device) {
       synchronized (myLock) {
         myDevice = device;
+        if (myCurrentWriter != null) {
+          try {
+            myCurrentWriter.close();
+          }
+          catch (IOException e) {
+            LOG.error(e);
+          }
+        }
         if (myCurrentReader != null) {
           try {
             myCurrentReader.close();
@@ -193,7 +219,15 @@ public abstract class AndroidLogcatToolWindowView implements Disposable {
           }
         }
         if (device != null) {
-          myCurrentReader = AndroidLogcatUtil.startLoggingThread(myProject, device, false, myLogConsole);
+          final Pair<Reader,Writer> pair = AndroidLogcatUtil.startLoggingThread(myProject, device, false, myLogConsole);
+          if (pair != null) {
+            myCurrentReader = pair.first;
+            myCurrentWriter = pair.second;
+          }
+          else {
+            myCurrentReader = null;
+            myCurrentWriter = null;
+          }
         }
       }
     }
index d9aabcfd248db2966089b3cb457a6efa21989996..5d38f73b56e171dcfb059ae9a4eebeb0d64f3aa9 100644 (file)
@@ -23,6 +23,7 @@ import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Pair;
 import com.intellij.util.ui.UIUtil;
 import org.jetbrains.android.run.LoggingReceiver;
 import org.jetbrains.android.util.AndroidBundle;
@@ -31,10 +32,7 @@ import org.jetbrains.android.util.AndroidUtils;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.io.IOException;
-import java.io.PipedReader;
-import java.io.PipedWriter;
-import java.io.Reader;
+import java.io.*;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -99,7 +97,7 @@ public class AndroidLogcatUtil {
   }
 
   @Nullable
-  public static Reader startLoggingThread(final Project project,
+  public static Pair<Reader, Writer> startLoggingThread(final Project project,
                                           final IDevice device,
                                           final boolean clearLogcat,
                                           @NotNull final LogConsoleBase console) {
@@ -155,6 +153,6 @@ public class AndroidLogcatUtil {
         });
       }
     });
-    return logReader;
+    return new Pair<Reader, Writer>(logReader, logWriter);
   }
 }
index 6d21ae5749beec58901cebbee6098e7f1250f1d8..4dc384827c679fe2ecfa733ab68bd2c8f1443bfc 100644 (file)
@@ -20,6 +20,7 @@ import com.intellij.debugger.engine.RemoteDebugProcessHandler;
 import com.intellij.debugger.ui.DebuggerPanelsManager;
 import com.intellij.debugger.ui.DebuggerSessionTab;
 import com.intellij.diagnostic.logging.LogConsoleBase;
+import com.intellij.diagnostic.logging.LogConsoleListener;
 import com.intellij.execution.*;
 import com.intellij.execution.configurations.*;
 import com.intellij.execution.executors.DefaultDebugExecutor;
@@ -34,8 +35,10 @@ import com.intellij.execution.ui.RunContentDescriptor;
 import com.intellij.execution.ui.RunContentManager;
 import com.intellij.execution.ui.layout.LayoutViewOptions;
 import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Pair;
 import com.intellij.psi.PsiClass;
 import org.jetbrains.android.dom.manifest.Instrumentation;
 import org.jetbrains.android.dom.manifest.Manifest;
@@ -47,7 +50,9 @@ import org.jetbrains.android.util.AndroidUtils;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import java.io.IOException;
 import java.io.Reader;
+import java.io.Writer;
 
 import static com.intellij.execution.process.ProcessOutputTypes.STDERR;
 
@@ -55,6 +60,8 @@ import static com.intellij.execution.process.ProcessOutputTypes.STDERR;
  * @author coyote
  */
 public class AndroidDebugRunner extends DefaultProgramRunner {
+  private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.run.AndroidDebugRunner");
+
   private static final Key<RunContentDescriptor> ANDROID_PROCESS_HANDLER = new Key<RunContentDescriptor>("ANDROID_PROCESS_HANDLER");
   private static final Object myReaderLock = new Object();
 
@@ -236,7 +243,9 @@ public class AndroidDebugRunner extends DefaultProgramRunner {
           RunProfile profile = myEnvironment.getRunProfile();
           assert profile instanceof AndroidRunConfigurationBase;
           final Reader[] readerWrapper = new Reader[1];
+          final Writer[] writerWrapper = new Writer[1];
           String logcatTabTitle = AndroidBundle.message("android.logcat.tab.title");
+
           LogConsoleBase console = sessionTab.addLogConsole(logcatTabTitle, new AndroidLoggingReader() {
             @NotNull
             protected Object getLock() {
@@ -247,9 +256,33 @@ public class AndroidDebugRunner extends DefaultProgramRunner {
               return readerWrapper[0];
             }
           }, 0, AndroidUtils.ANDROID_ICON);
+
+          console.addListener(new LogConsoleListener() {
+            @Override
+            public void loggingWillBeStopped() {
+              final Writer writer = writerWrapper[0];
+              if (writer != null) {
+                try {
+                  writer.close();
+                }
+                catch (IOException e) {
+                  LOG.error(e);
+                }
+              }
+            }
+          });
+
           synchronized (myReaderLock) {
-            readerWrapper[0] =
+            final Pair<Reader,Writer> pair =
               AndroidLogcatUtil.startLoggingThread(myProject, device, ((AndroidRunConfigurationBase)profile).CLEAR_LOGCAT, console);
+            if (pair != null) {
+              readerWrapper[0] = pair.first;
+              writerWrapper[0] = pair.second;
+            }
+            else {
+              readerWrapper[0] = null;
+              writerWrapper[0] = null;
+            }
           }
           if (!(profile instanceof AndroidTestRunConfiguration)) {
             String logcatContentId = DebuggerSessionTab.getLogContentId(logcatTabTitle);