some annotations added
[idea/community.git] / platform / platform-api / src / com / intellij / execution / process / OSProcessHandler.java
1 /*
2  * Copyright 2000-2012 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.execution.process;
17
18 import com.intellij.execution.ExecutionException;
19 import com.intellij.execution.configurations.GeneralCommandLine;
20 import com.intellij.execution.configurations.PtyCommandLine;
21 import com.intellij.openapi.application.Application;
22 import com.intellij.openapi.application.ApplicationManager;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.vfs.CharsetToolkit;
25 import com.intellij.openapi.vfs.encoding.EncodingManager;
26 import org.jetbrains.annotations.NotNull;
27 import org.jetbrains.annotations.Nullable;
28
29 import java.nio.charset.Charset;
30 import java.util.concurrent.Future;
31
32 public class OSProcessHandler extends BaseOSProcessHandler {
33   private static final Logger LOG = Logger.getInstance("#com.intellij.execution.process.OSProcessHandler");
34   private boolean myHasPty = false;
35
36   private boolean myDestroyRecursively = true;
37
38   public OSProcessHandler(@NotNull GeneralCommandLine commandLine) throws ExecutionException {
39     this(commandLine.createProcess(), commandLine.getCommandLineString(), CharsetToolkit.UTF8_CHARSET);
40     setHasPty(commandLine instanceof PtyCommandLine);
41   }
42
43   public OSProcessHandler(@NotNull final Process process) {
44     this(process, null);
45   }
46
47   public OSProcessHandler(@NotNull final Process process, @Nullable final String commandLine) {
48     this(process, commandLine, EncodingManager.getInstance().getDefaultCharset());
49   }
50
51   public OSProcessHandler(@NotNull final Process process, @Nullable final String commandLine, @Nullable final Charset charset) {
52     super(process, commandLine, charset);
53   }
54
55   protected OSProcessHandler(@NotNull final OSProcessHandler base) {
56     this(base.myProcess, base.myCommandLine);
57   }
58
59   @Override
60   protected Future<?> executeOnPooledThread(Runnable task) {
61     final Application application = ApplicationManager.getApplication();
62
63     if (application != null) {
64       return application.executeOnPooledThread(task);
65     }
66
67     return super.executeOnPooledThread(task);
68   }
69
70   protected boolean shouldDestroyProcessRecursively() {
71     // Override this method if you want to kill process recursively (whole process try) by default
72     // such behaviour is better than default java one, which doesn't kill children processes
73     return myDestroyRecursively;
74   }
75
76   public void setShouldDestroyProcessRecursively(boolean destroyRecursively) {
77     myDestroyRecursively = destroyRecursively;
78   }
79
80   @Override
81   protected void doDestroyProcess() {
82     // Override this method if you want to customize default destroy behaviour, e.g.
83     // if you want use some soft-kill.
84     final Process process = getProcess();
85     if (shouldDestroyProcessRecursively() && processCanBeKilledByOS(process)) {
86       killProcessTree(process);
87     }
88     else {
89       process.destroy();
90     }
91   }
92
93   public static boolean processCanBeKilledByOS(Process process) {
94     return !(process instanceof SelfKiller);
95   }
96
97   /**
98    * Kill the whole process tree.
99    *
100    * @param process Process
101    * @return True if process tree has been successfully killed.
102    */
103   protected boolean killProcessTree(@NotNull Process process) {
104     LOG.debug("killing process tree");
105     final boolean destroyed = OSProcessManager.getInstance().killProcessTree(process);
106     if (!destroyed) {
107       LOG.warn("Cannot kill process tree. Trying to destroy process using Java API. Cmdline:\n" + myCommandLine);
108       process.destroy();
109     }
110     return destroyed;
111   }
112
113   /**
114    * In case of pty this process handler will use blocking read. The value should be set before
115    * startNotify invocation. It is set by default in case of using GeneralCommandLine based constructor.
116    *
117    * @param hasPty true if process is pty based
118    */
119   public void setHasPty(boolean hasPty) {
120     myHasPty = hasPty;
121   }
122
123   @Override
124   protected boolean useNonBlockingRead() {
125     if (myHasPty) {
126       // blocking read in case of pty based process
127       return false;
128     }
129     else {
130       return super.useNonBlockingRead();
131     }
132   }
133 }