Merge branch 'master' of git.labs.intellij.net:idea/community
[idea/community.git] / platform / platform-api / src / com / intellij / openapi / progress / AbstractTaskQueue.java
1 /*
2  * Copyright 2000-2009 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.openapi.progress;
17
18 import com.intellij.openapi.application.ApplicationManager;
19 import com.intellij.openapi.diagnostic.Logger;
20
21 import java.util.LinkedList;
22 import java.util.Queue;
23
24 @SomeQueue
25 public abstract class AbstractTaskQueue<T> {
26   private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.AbstractTaskQueue");
27
28   private final Object myLock;
29   private final Queue<T> myQueue;
30   private boolean myActive;
31   protected final Runnable myQueueWorker;
32
33   public AbstractTaskQueue() {
34     myLock = new Object();
35     myQueue = new LinkedList<T>();
36     myActive = false;
37     myQueueWorker = new MyWorker();
38   }
39
40   /**
41    * !!! done under lock! (to allow single failures when putting into the execution queue)
42    * Should run {@link #myQueueWorker}
43    */
44   protected abstract void runMe();
45   protected abstract void runStuff(T stuff);
46
47   public void run(final T stuff) {
48     if (ApplicationManager.getApplication().isUnitTestMode()) {
49       runStuff(stuff);
50       return;
51     }
52     boolean impulseGiven = false;
53     synchronized (myLock) {
54       try {
55         myQueue.add(stuff);
56         if (! myActive) {
57           runMe();
58           impulseGiven = true;
59         }
60       } catch (Throwable t) {
61         LOG.info(t);
62         throw t instanceof RuntimeException ? ((RuntimeException) t) : new RuntimeException(t);
63       } finally {
64         if ((! myActive) && impulseGiven) {
65           myActive = true;
66         }
67       }
68     }
69   }
70
71   private class MyWorker implements Runnable {
72     public void run() {
73       while (true) {
74         try {
75           final T stuff;
76           synchronized (myLock) {
77             stuff = myQueue.poll();
78           }
79           // each task is executed only once, once it has been taken from the queue..
80           runStuff(stuff);
81         } catch (Throwable t) {
82           LOG.info(t);
83         } finally {
84           synchronized (myLock) {
85             if (myQueue.isEmpty()) {
86               myActive = false;
87               return;
88             }
89           }
90         }
91       }
92     }
93   }
94 }