2 * Copyright 2000-2015 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.execution.testframework.autotest;
18 import com.intellij.execution.*;
19 import com.intellij.execution.configurations.RunConfiguration;
20 import com.intellij.execution.configurations.RunProfile;
21 import com.intellij.execution.impl.RunManagerImpl;
22 import com.intellij.execution.process.ProcessAdapter;
23 import com.intellij.execution.process.ProcessEvent;
24 import com.intellij.execution.process.ProcessHandler;
25 import com.intellij.execution.process.ProcessListener;
26 import com.intellij.execution.runners.ExecutionEnvironment;
27 import com.intellij.execution.runners.ExecutionUtil;
28 import com.intellij.execution.ui.RunContentDescriptor;
29 import com.intellij.execution.ui.RunContentManager;
30 import com.intellij.ide.DataManager;
31 import com.intellij.ide.scratch.ScratchFileService;
32 import com.intellij.ide.util.PropertiesComponent;
33 import com.intellij.openapi.actionSystem.LangDataKeys;
34 import com.intellij.openapi.application.ApplicationManager;
35 import com.intellij.openapi.application.ModalityState;
36 import com.intellij.openapi.components.*;
37 import com.intellij.openapi.fileEditor.FileEditorManager;
38 import com.intellij.openapi.project.Project;
39 import com.intellij.openapi.util.Condition;
40 import com.intellij.openapi.util.Key;
41 import com.intellij.openapi.vfs.VirtualFile;
42 import com.intellij.ui.content.Content;
43 import com.intellij.util.Consumer;
44 import com.intellij.util.ObjectUtils;
45 import com.intellij.util.containers.ContainerUtil;
46 import com.intellij.util.xmlb.annotations.AbstractCollection;
47 import com.intellij.util.xmlb.annotations.Attribute;
48 import com.intellij.util.xmlb.annotations.Tag;
49 import org.jetbrains.annotations.NotNull;
50 import org.jetbrains.annotations.Nullable;
53 import java.util.List;
60 name = "AutoTestManager",
61 storages = {@Storage(StoragePathMacros.WORKSPACE_FILE)}
63 public class AutoTestManager implements PersistentStateComponent<AutoTestManager.State> {
64 private static final String AUTO_TEST_MANAGER_DELAY = "auto.test.manager.delay";
65 private static final int AUTO_TEST_MANAGER_DELAY_DEFAULT = 3000;
67 private static final Key<ProcessListener> ON_TERMINATION_RESTARTER_KEY = Key.create("auto.test.manager.on.termination.restarter");
69 private final Project myProject;
70 private int myDelayMillis;
71 private DelayedDocumentWatcher myDocumentWatcher;
72 private final Set<RunProfile> myEnabledRunProfiles = ContainerUtil.newHashSet();
75 public static AutoTestManager getInstance(Project project) {
76 return ServiceManager.getService(project, AutoTestManager.class);
79 public AutoTestManager(@NotNull Project project) {
81 myDelayMillis = PropertiesComponent.getInstance(project).getInt(AUTO_TEST_MANAGER_DELAY, AUTO_TEST_MANAGER_DELAY_DEFAULT);
82 myDocumentWatcher = createWatcher();
86 private DelayedDocumentWatcher createWatcher() {
87 return new DelayedDocumentWatcher(myProject, myDelayMillis, new Consumer<Integer>() {
89 public void consume(Integer modificationStamp) {
90 restartAllAutoTests(modificationStamp);
92 }, new Condition<VirtualFile>() {
94 public boolean value(VirtualFile file) {
95 if (ScratchFileService.getInstance().getRootType(file) != null) {
98 // Vladimir.Krivosheev - I don't know, why AutoTestManager checks it, but old behavior is preserved
99 return FileEditorManager.getInstance(myProject).isFileOpen(file);
104 public void setAutoTestEnabled(@NotNull RunContentDescriptor descriptor, @NotNull ExecutionEnvironment environment, boolean enabled) {
105 Content content = descriptor.getAttachedContent();
106 if (content != null) {
108 myEnabledRunProfiles.add(environment.getRunProfile());
109 myDocumentWatcher.activate();
112 myEnabledRunProfiles.remove(environment.getRunProfile());
113 if (!hasEnabledAutoTests()) {
114 myDocumentWatcher.deactivate();
116 ProcessHandler processHandler = descriptor.getProcessHandler();
117 if (processHandler != null) {
118 clearRestarterListener(processHandler);
124 private boolean hasEnabledAutoTests() {
125 RunContentManager contentManager = ExecutionManager.getInstance(myProject).getContentManager();
126 for (RunContentDescriptor descriptor : contentManager.getAllDescriptors()) {
127 if (isAutoTestEnabledForDescriptor(descriptor)) {
134 public boolean isAutoTestEnabled(@NotNull RunContentDescriptor descriptor) {
135 return isAutoTestEnabledForDescriptor(descriptor);
138 private boolean isAutoTestEnabledForDescriptor(@NotNull RunContentDescriptor descriptor) {
139 Content content = descriptor.getAttachedContent();
140 if (content != null) {
141 ExecutionEnvironment environment = getCurrentEnvironment(content);
142 return environment != null && myEnabledRunProfiles.contains(environment.getRunProfile());
148 private static ExecutionEnvironment getCurrentEnvironment(@NotNull Content content) {
149 JComponent component = content.getComponent();
150 if (component == null) {
153 return LangDataKeys.EXECUTION_ENVIRONMENT.getData(DataManager.getInstance().getDataContext(component));
156 private static void clearRestarterListener(@NotNull ProcessHandler processHandler) {
157 ProcessListener restarterListener = ON_TERMINATION_RESTARTER_KEY.get(processHandler, null);
158 if (restarterListener != null) {
159 processHandler.removeProcessListener(restarterListener);
160 ON_TERMINATION_RESTARTER_KEY.set(processHandler, null);
164 private void restartAllAutoTests(int modificationStamp) {
165 RunContentManager contentManager = ExecutionManager.getInstance(myProject).getContentManager();
166 boolean active = false;
167 for (RunContentDescriptor descriptor : contentManager.getAllDescriptors()) {
168 if (isAutoTestEnabledForDescriptor(descriptor)) {
169 restartAutoTest(descriptor, modificationStamp, myDocumentWatcher);
174 myDocumentWatcher.deactivate();
178 private void restartAutoTest(@NotNull RunContentDescriptor descriptor,
179 int modificationStamp,
180 @NotNull DelayedDocumentWatcher documentWatcher) {
181 ProcessHandler processHandler = descriptor.getProcessHandler();
182 if (processHandler != null && !processHandler.isProcessTerminated()) {
183 scheduleRestartOnTermination(descriptor, processHandler, modificationStamp, documentWatcher);
190 private void scheduleRestartOnTermination(@NotNull final RunContentDescriptor descriptor,
191 @NotNull final ProcessHandler processHandler,
192 final int modificationStamp,
193 @NotNull final DelayedDocumentWatcher documentWatcher) {
194 ProcessListener restarterListener = ON_TERMINATION_RESTARTER_KEY.get(processHandler);
195 if (restarterListener != null) {
196 clearRestarterListener(processHandler);
198 restarterListener = new ProcessAdapter() {
200 public void processTerminated(ProcessEvent event) {
201 clearRestarterListener(processHandler);
202 ApplicationManager.getApplication().invokeLater(new Runnable() {
205 if (isAutoTestEnabledForDescriptor(descriptor) && documentWatcher.isUpToDate(modificationStamp)) {
209 }, ModalityState.any());
212 ON_TERMINATION_RESTARTER_KEY.set(processHandler, restarterListener);
213 processHandler.addProcessListener(restarterListener);
216 private static void restart(@NotNull RunContentDescriptor descriptor) {
217 descriptor.setActivateToolWindowWhenAdded(false);
218 descriptor.setReuseToolWindowActivation(true);
219 ExecutionUtil.restart(descriptor);
223 return myDelayMillis;
226 void setDelay(int delay) {
227 myDelayMillis = delay;
228 myDocumentWatcher.deactivate();
229 myDocumentWatcher = createWatcher();
230 if (hasEnabledAutoTests()) {
231 myDocumentWatcher.activate();
233 PropertiesComponent.getInstance(myProject).setValue(AUTO_TEST_MANAGER_DELAY, myDelayMillis, AUTO_TEST_MANAGER_DELAY_DEFAULT);
238 public State getState() {
239 State state = new State();
240 for (RunProfile profile : myEnabledRunProfiles) {
241 RunConfiguration runConfiguration = ObjectUtils.tryCast(profile, RunConfiguration.class);
242 if (runConfiguration != null) {
243 RunConfigurationDescriptor descriptor = new RunConfigurationDescriptor();
244 descriptor.myType = runConfiguration.getType().getId();
245 descriptor.myName = runConfiguration.getName();
246 state.myEnabledRunConfigurations.add(descriptor);
253 public void loadState(State state) {
254 List<RunConfiguration> configurations = ContainerUtil.newArrayList();
255 RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(myProject);
256 for (RunConfigurationDescriptor descriptor : state.myEnabledRunConfigurations) {
257 RunnerAndConfigurationSettings settings = runManager.findConfigurationByTypeAndName(descriptor.myType,
259 RunConfiguration configuration = settings != null ? settings.getConfiguration() : null;
260 if (configuration != null) {
261 configurations.add(configuration);
264 myEnabledRunProfiles.clear();
265 myEnabledRunProfiles.addAll(configurations);
269 @Tag("enabled-run-configurations")
270 @AbstractCollection(surroundWithTag = false)
271 List<RunConfigurationDescriptor> myEnabledRunConfigurations = ContainerUtil.newArrayList();
274 @Tag("run-configuration")
275 static class RunConfigurationDescriptor {