jsr-299 libs and facets
[idea/community.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / LazyRefreshingSelfQueue.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.vcs.changes;
17
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.progress.ProgressIndicator;
20 import com.intellij.openapi.progress.ProgressManager;
21 import com.intellij.openapi.util.Computable;
22 import com.intellij.openapi.util.Pair;
23 import com.intellij.util.Consumer;
24 import org.jetbrains.annotations.NotNull;
25
26 import java.util.*;
27
28 /**
29  * need to update:
30  * 1. if TS is null
31  * 2. if checker returns TRUE -> those whose timestamp is older than required
32  *
33  */
34 public class LazyRefreshingSelfQueue<T> {
35   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.LazyRefreshingSelfQueue");
36
37   private final long myUpdateInterval;
38   // head is old. tail is new
39   private final LinkedList<Pair<Long, T>> myQueue;
40   private final Set<T> myInProgress;
41   private final Computable<Boolean> myShouldUpdateOldChecker;
42   private final Consumer<T> myUpdater;
43   private final Object myLock;
44
45   public LazyRefreshingSelfQueue(final long updateInterval, final Computable<Boolean> shouldUpdateOldChecker, final Consumer<T> updater) {
46     myUpdateInterval = updateInterval;
47     myShouldUpdateOldChecker = shouldUpdateOldChecker;
48     myUpdater = updater;
49     myQueue = new LinkedList<Pair<Long, T>>();
50     myInProgress = new HashSet<T>();
51     myLock = new Object();
52   }
53
54   public void addRequest(@NotNull final T t) {
55     synchronized (myLock) {
56       myQueue.addFirst(new Pair<Long,T>(null, t));
57     }
58   }
59
60   public void addRequests(final Collection<T> values) {
61     synchronized (myLock) {
62       for (T value : values) {
63         myQueue.addFirst(new Pair<Long,T>(null, value));
64       }
65     }
66   }
67
68   public void forceRemove(@NotNull final T t) {
69     synchronized (myLock) {
70       for (Iterator<Pair<Long, T>> iterator = myQueue.iterator(); iterator.hasNext();) {
71         final Pair<Long, T> pair = iterator.next();
72         if (t.equals(pair.getSecond())) {
73           iterator.remove();
74         }
75       }
76       myInProgress.remove(t);
77     }
78   }
79
80   // called by outside timer or something
81   public void updateStep(@NotNull final ProgressIndicator pi) {
82     final List<T> dirty = new LinkedList<T>();
83
84     final long startTime = System.currentTimeMillis() - myUpdateInterval;
85     boolean onlyAbsolute = true;
86     // check if we have some old items at all - if not, we would not check if repository latest revision had changed and will save time
87     synchronized (myLock) {
88       for (Pair<Long, T> pair : myQueue) {
89         if (pair.getFirst() != null) {
90           onlyAbsolute = pair.getFirst() > startTime;
91           break;
92         }
93       }
94     }
95
96     // do not ask under lock
97     final Boolean shouldUpdateOld = onlyAbsolute ? false : myShouldUpdateOldChecker.compute();
98
99     synchronized (myLock) {
100       // get absolute
101       while (! myQueue.isEmpty()) {
102         pi.checkCanceled();
103         final Pair<Long, T> pair = myQueue.get(0);
104         if (pair.getFirst() == null) {
105           dirty.add(myQueue.removeFirst().getSecond());
106         } else {
107           break;
108         }
109       }
110       if (Boolean.TRUE.equals(shouldUpdateOld) && (! myQueue.isEmpty())) {
111         while (! myQueue.isEmpty()) {
112           final Pair<Long, T> pair = myQueue.get(0);
113           if (pair.getFirst() < startTime) {
114             myQueue.removeFirst();
115             dirty.add(pair.getSecond());
116           } else {
117             break;
118           }
119         }
120       }
121
122       myInProgress.addAll(dirty);
123     }
124
125     LOG.debug("found something to update: " + (! dirty.isEmpty()));
126     for (T t : dirty) {
127       ProgressManager.checkCanceled();
128       myUpdater.consume(t);
129       synchronized (myLock) {
130         if (myInProgress.remove(t)) {
131           myQueue.addLast(new Pair<Long,T>(System.currentTimeMillis(), t));
132         }
133       }
134     }
135   }
136 }