1 package com
.intellij
.lifecycle
;
3 import com
.intellij
.openapi
.application
.ApplicationManager
;
4 import com
.intellij
.openapi
.application
.ModalityState
;
5 import com
.intellij
.openapi
.application
.Application
;
6 import com
.intellij
.openapi
.application
.impl
.LaterInvocator
;
7 import com
.intellij
.openapi
.components
.ServiceManager
;
8 import com
.intellij
.openapi
.diagnostic
.Logger
;
9 import com
.intellij
.openapi
.progress
.ProcessCanceledException
;
10 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
11 import com
.intellij
.openapi
.progress
.ProgressManager
;
12 import com
.intellij
.openapi
.project
.Project
;
13 import com
.intellij
.openapi
.project
.ProjectManager
;
14 import com
.intellij
.openapi
.project
.ProjectManagerListener
;
15 import com
.intellij
.openapi
.util
.Condition
;
16 import com
.intellij
.openapi
.util
.Pair
;
17 import com
.intellij
.openapi
.util
.Ref
;
18 import com
.intellij
.util
.concurrency
.Semaphore
;
19 import org
.jetbrains
.annotations
.NonNls
;
20 import org
.jetbrains
.annotations
.NotNull
;
22 import java
.util
.ArrayList
;
23 import java
.util
.HashMap
;
24 import java
.util
.List
;
27 public class PeriodicalTasksCloser
implements ProjectManagerListener
{
28 private final static Logger LOG
= Logger
.getInstance("#com.intellij.lifecycle.PeriodicalTasksCloser");
29 private final static Object ourLock
= new Object();
30 private final List
<Pair
<String
, Runnable
>> myInterrupters
;
31 private final static Map
<Project
, Boolean
> myStates
= new HashMap
<Project
, Boolean
>();
33 private PeriodicalTasksCloser(final Project project
, final ProjectManager projectManager
) {
34 myInterrupters
= new ArrayList
<Pair
<String
, Runnable
>>();
35 projectManager
.addProjectManagerListener(project
, this);
38 public static PeriodicalTasksCloser
getInstance(final Project project
) {
39 return ServiceManager
.getService(project
, PeriodicalTasksCloser
.class);
42 public void register(final String name
, final Runnable runnable
) {
43 myInterrupters
.add(new Pair
<String
, Runnable
>(name
, runnable
));
46 public void projectOpened(Project project
) {
47 synchronized (ourLock
) {
48 myStates
.put(project
, Boolean
.TRUE
);
52 public boolean canCloseProject(Project project
) {
56 public void projectClosed(Project project
) {
57 synchronized (ourLock
) {
58 myStates
.remove(project
);
62 public void projectClosing(Project project
) {
63 synchronized (ourLock
) {
64 myStates
.put(project
, Boolean
.FALSE
);
66 ProgressManager
.getInstance().runProcessWithProgressSynchronously(new Runnable() {
68 final ProgressIndicator indicator
= ProgressManager
.getInstance().getProgressIndicator();
69 for (Pair
<String
, Runnable
> pair
: myInterrupters
) {
70 if (indicator
!= null) {
71 indicator
.setText(pair
.getFirst());
72 indicator
.checkCanceled();
74 pair
.getSecond().run();
77 }, "Please wait for safe shutdown of periodical tasks...", true, project
);
80 public static<T
> T
safeGetComponent(@NotNull final Project project
, final Class
<T
> componentClass
) throws ProcessCanceledException
{
83 component
= project
.getComponent(componentClass
);
86 if (t
instanceof NullPointerException
) {
87 } else if (t
instanceof AssertionError
) {
91 throw new ProcessCanceledException();
93 synchronized (ourLock
) {
94 final Boolean state
= myStates
.get(project
);
95 // if project is already closed and project key is already removed from map - then it should have thrown an exception in the block above
96 // so ok to just check for 'closing' stage here
97 if (state
!= null && ! Boolean
.TRUE
.equals(state
)) {
98 throw new ProcessCanceledException();
104 public static void invokeAndWaitInterruptedWhenClosing(final Project project
, final Runnable runnable
, final ModalityState modalityState
) {
105 final Ref
<Boolean
> start
= new Ref
<Boolean
>(Boolean
.TRUE
);
106 final Application application
= ApplicationManager
.getApplication();
107 LOG
.assertTrue(! application
.isDispatchThread());
109 final Semaphore semaphore
= new Semaphore();
111 Runnable runnable1
= new Runnable() {
122 public String
toString() {
123 return "PeriodicalTaskCloser's invoke and wait [" + runnable
.toString() + "]";
126 LaterInvocator
.invokeLater(runnable1
, modalityState
, new Condition
<Object
>() {
127 public boolean value(Object o
) {
128 synchronized (start
) {
129 return ! start
.get();
135 if (semaphore
.waitFor(1000)) {
138 final Ref
<Boolean
> fire
= new Ref
<Boolean
>();
139 synchronized (ourLock
) {
140 final Boolean state
= myStates
.get(project
);
141 if (! Boolean
.TRUE
.equals(state
)) {
142 fire
.set(Boolean
.TRUE
);
144 if (Boolean
.TRUE
.equals(fire
.get())) {
145 synchronized (start
) {
146 start
.set(Boolean
.FALSE
);