IDEA-25467 (CVS is set to Offline mode on project open) - integration to trunk
[fedora-idea.git] / platform / vcs-impl / src / com / intellij / lifecycle / PeriodicalTasksCloser.java
blob61777c564b4bd8cafc939f83bb0db929ea7179e0
1 /*
2 * Copyright 2000-2009 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.lifecycle;
18 import com.intellij.openapi.application.Application;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.application.ModalityState;
21 import com.intellij.openapi.application.impl.LaterInvocator;
22 import com.intellij.openapi.components.ServiceManager;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.progress.ProcessCanceledException;
25 import com.intellij.openapi.progress.ProgressIndicator;
26 import com.intellij.openapi.progress.ProgressManager;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.project.ProjectManager;
29 import com.intellij.openapi.project.ProjectManagerListener;
30 import com.intellij.openapi.util.Condition;
31 import com.intellij.openapi.util.Pair;
32 import com.intellij.openapi.util.Ref;
33 import com.intellij.util.concurrency.Semaphore;
34 import org.jetbrains.annotations.NonNls;
35 import org.jetbrains.annotations.NotNull;
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Map;
42 public class PeriodicalTasksCloser implements ProjectManagerListener {
43 private final static Logger LOG = Logger.getInstance("#com.intellij.lifecycle.PeriodicalTasksCloser");
44 private final static Object ourLock = new Object();
45 private final List<Pair<String, Runnable>> myInterrupters;
46 private final static Map<Project, Boolean> myStates = new HashMap<Project, Boolean>();
47 private final Project myProject;
49 private PeriodicalTasksCloser(final Project project, final ProjectManager projectManager) {
50 myProject = project;
51 myInterrupters = new ArrayList<Pair<String, Runnable>>();
52 projectManager.addProjectManagerListener(project, this);
55 public static PeriodicalTasksCloser getInstance(final Project project) {
56 return ServiceManager.getService(project, PeriodicalTasksCloser.class);
59 public boolean register(final String name, final Runnable runnable) {
60 synchronized (ourLock) {
61 if (Boolean.FALSE.equals(myStates.get(myProject))) {
62 return false;
64 myInterrupters.add(new Pair<String, Runnable>(name, runnable));
65 return true;
69 public void projectOpened(Project project) {
70 synchronized (ourLock) {
71 myStates.put(project, Boolean.TRUE);
75 public boolean canCloseProject(Project project) {
76 return true;
79 public void projectClosed(Project project) {
80 synchronized (ourLock) {
81 myStates.remove(project);
85 public void projectClosing(Project project) {
86 synchronized (ourLock) {
87 myStates.put(project, Boolean.FALSE);
89 ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
90 public void run() {
91 final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
92 final List<Pair<String, Runnable>> list;
93 synchronized (ourLock) {
94 list = myInterrupters;
96 for (Pair<String, Runnable> pair : list) {
97 if (indicator != null) {
98 indicator.setText(pair.getFirst());
99 indicator.checkCanceled();
101 pair.getSecond().run();
104 }, "Please wait for safe shutdown of periodical tasks...", true, project);
107 public static<T> T safeGetComponent(@NotNull final Project project, final Class<T> componentClass) throws ProcessCanceledException {
108 final T component;
109 try {
110 component = project.getComponent(componentClass);
112 catch (Throwable t) {
113 if (t instanceof NullPointerException) {
114 } else if (t instanceof AssertionError) {
115 } else {
116 LOG.info(t);
118 throw new ProcessCanceledException();
120 synchronized (ourLock) {
121 final Boolean state = myStates.get(project);
122 // if project is already closed and project key is already removed from map - then it should have thrown an exception in the block above
123 // so ok to just check for 'closing' stage here
124 if (state != null && ! Boolean.TRUE.equals(state)) {
125 throw new ProcessCanceledException();
127 return component;
131 public static void invokeAndWaitInterruptedWhenClosing(final Project project, final Runnable runnable, final ModalityState modalityState) {
132 final Ref<Boolean> start = new Ref<Boolean>(Boolean.TRUE);
133 final Application application = ApplicationManager.getApplication();
134 LOG.assertTrue(! application.isDispatchThread());
136 final Semaphore semaphore = new Semaphore();
137 semaphore.down();
138 Runnable runnable1 = new Runnable() {
139 public void run() {
140 try {
141 runnable.run();
143 finally {
144 semaphore.up();
148 @NonNls
149 public String toString() {
150 return "PeriodicalTaskCloser's invoke and wait [" + runnable.toString() + "]";
153 LaterInvocator.invokeLater(runnable1, modalityState, new Condition<Object>() {
154 public boolean value(Object o) {
155 synchronized (start) {
156 return ! start.get();
161 while (true) {
162 if (semaphore.waitFor(1000)) {
163 return;
165 final Ref<Boolean> fire = new Ref<Boolean>();
166 if (project != null) {
167 synchronized (ourLock) {
168 final Boolean state = myStates.get(project);
169 if (! Boolean.TRUE.equals(state)) {
170 fire.set(Boolean.TRUE);
172 if (Boolean.TRUE.equals(fire.get())) {
173 synchronized (start) {
174 start.set(Boolean.FALSE);
175 return;