source: josm/trunk/src/org/openstreetmap/josm/data/osm/ChangesetCache.java@ 12841

Last change on this file since 12841 was 12767, checked in by Don-vip, 7 years ago

see #15229 - see #15182 - do not longer fire ChangesetCacheEvent in EDT - now up to listeners to run their code in it if required

  • Property svn:eol-style set to native
File size: 8.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm;
3
4import java.util.ArrayList;
5import java.util.Collection;
6import java.util.HashMap;
7import java.util.HashSet;
8import java.util.List;
9import java.util.Map;
10import java.util.Set;
11import java.util.concurrent.CopyOnWriteArrayList;
12import java.util.stream.Collectors;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
16import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
17import org.openstreetmap.josm.data.UserIdentityManager;
18import org.openstreetmap.josm.tools.SubclassFilteredCollection;
19
20/**
21 * ChangesetCache is global in-memory cache for changesets downloaded from
22 * an OSM API server. The unique instance is available as singleton, see
23 * {@link #getInstance()}.
24 *
25 * Clients interested in cache updates can register for {@link ChangesetCacheEvent}s
26 * using {@link #addChangesetCacheListener(ChangesetCacheListener)}. They can use
27 * {@link #removeChangesetCacheListener(ChangesetCacheListener)} to unregister as
28 * cache event listener.
29 *
30 * The cache itself listens to {@link java.util.prefs.PreferenceChangeEvent}s. It
31 * clears itself if the OSM API URL is changed in the preferences.
32 *
33 */
34public final class ChangesetCache implements PreferenceChangedListener {
35 /** the unique instance */
36 private static final ChangesetCache INSTANCE = new ChangesetCache();
37
38 /** the cached changesets */
39 private final Map<Integer, Changeset> cache = new HashMap<>();
40
41 final CopyOnWriteArrayList<ChangesetCacheListener> listeners = new CopyOnWriteArrayList<>();
42
43 /**
44 * Constructs a new {@code ChangesetCache}.
45 */
46 private ChangesetCache() {
47 Main.pref.addPreferenceChangeListener(this);
48 }
49
50 /**
51 * Replies the unique instance of the cache
52 * @return the unique instance of the cache
53 */
54 public static ChangesetCache getInstance() {
55 return INSTANCE;
56 }
57
58 /**
59 * Add a changeset cache listener.
60 * @param listener changeset cache listener to add
61 */
62 public void addChangesetCacheListener(ChangesetCacheListener listener) {
63 if (listener != null) {
64 listeners.addIfAbsent(listener);
65 }
66 }
67
68 /**
69 * Remove a changeset cache listener.
70 * @param listener changeset cache listener to remove
71 */
72 public void removeChangesetCacheListener(ChangesetCacheListener listener) {
73 if (listener != null) {
74 listeners.remove(listener);
75 }
76 }
77
78 private void fireChangesetCacheEvent(final ChangesetCacheEvent e) {
79 for (ChangesetCacheListener l: listeners) {
80 l.changesetCacheUpdated(e);
81 }
82 }
83
84 private void update(Changeset cs, DefaultChangesetCacheEvent e) {
85 if (cs == null) return;
86 if (cs.isNew()) return;
87 Changeset inCache = cache.get(cs.getId());
88 if (inCache != null) {
89 inCache.mergeFrom(cs);
90 e.rememberUpdatedChangeset(inCache);
91 } else {
92 e.rememberAddedChangeset(cs);
93 cache.put(cs.getId(), cs);
94 }
95 }
96
97 /**
98 * Update a single changeset.
99 * @param cs changeset to update
100 */
101 public void update(Changeset cs) {
102 DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
103 update(cs, e);
104 fireChangesetCacheEvent(e);
105 }
106
107 /**
108 * Update a collection of changesets.
109 * @param changesets changesets to update
110 */
111 public void update(Collection<Changeset> changesets) {
112 if (changesets == null || changesets.isEmpty()) return;
113 DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
114 for (Changeset cs: changesets) {
115 update(cs, e);
116 }
117 fireChangesetCacheEvent(e);
118 }
119
120 /**
121 * Determines if the cache contains an entry for given changeset identifier.
122 * @param id changeset id
123 * @return {@code true} if the cache contains an entry for {@code id}
124 */
125 public boolean contains(int id) {
126 if (id <= 0) return false;
127 return cache.get(id) != null;
128 }
129
130 /**
131 * Determines if the cache contains an entry for given changeset.
132 * @param cs changeset
133 * @return {@code true} if the cache contains an entry for {@code cs}
134 */
135 public boolean contains(Changeset cs) {
136 if (cs == null) return false;
137 if (cs.isNew()) return false;
138 return contains(cs.getId());
139 }
140
141 /**
142 * Returns the entry for given changeset identifier.
143 * @param id changeset id
144 * @return the entry for given changeset identifier, or null
145 */
146 public Changeset get(int id) {
147 return cache.get(id);
148 }
149
150 /**
151 * Returns the list of changesets contained in the cache.
152 * @return the list of changesets contained in the cache
153 */
154 public Set<Changeset> getChangesets() {
155 return new HashSet<>(cache.values());
156 }
157
158 private void remove(int id, DefaultChangesetCacheEvent e) {
159 if (id <= 0) return;
160 Changeset cs = cache.get(id);
161 if (cs == null) return;
162 cache.remove(id);
163 e.rememberRemovedChangeset(cs);
164 }
165
166 /**
167 * Remove the entry for the given changeset identifier.
168 * A {@link ChangesetCacheEvent} is fired.
169 * @param id changeset id
170 */
171 public void remove(int id) {
172 DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
173 remove(id, e);
174 if (!e.isEmpty()) {
175 fireChangesetCacheEvent(e);
176 }
177 }
178
179 /**
180 * Remove the entry for the given changeset.
181 * A {@link ChangesetCacheEvent} is fired.
182 * @param cs changeset
183 */
184 public void remove(Changeset cs) {
185 if (cs == null) return;
186 if (cs.isNew()) return;
187 remove(cs.getId());
188 }
189
190 /**
191 * Removes the changesets in <code>changesets</code> from the cache.
192 * A {@link ChangesetCacheEvent} is fired.
193 *
194 * @param changesets the changesets to remove. Ignored if null.
195 */
196 public void remove(Collection<Changeset> changesets) {
197 if (changesets == null) return;
198 DefaultChangesetCacheEvent evt = new DefaultChangesetCacheEvent(this);
199 for (Changeset cs : changesets) {
200 if (cs == null || cs.isNew()) {
201 continue;
202 }
203 remove(cs.getId(), evt);
204 }
205 if (!evt.isEmpty()) {
206 fireChangesetCacheEvent(evt);
207 }
208 }
209
210 /**
211 * Returns the number of changesets contained in the cache.
212 * @return the number of changesets contained in the cache
213 */
214 public int size() {
215 return cache.size();
216 }
217
218 /**
219 * Clears the cache.
220 */
221 public void clear() {
222 DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
223 for (Changeset cs: cache.values()) {
224 e.rememberRemovedChangeset(cs);
225 }
226 cache.clear();
227 fireChangesetCacheEvent(e);
228 }
229
230 /**
231 * Replies the list of open changesets.
232 * @return The list of open changesets
233 */
234 public List<Changeset> getOpenChangesets() {
235 return cache.values().stream()
236 .filter(Changeset::isOpen)
237 .collect(Collectors.toList());
238 }
239
240 /**
241 * If the current user {@link UserIdentityManager#isAnonymous() is known}, the {@link #getOpenChangesets() open changesets}
242 * for the {@link UserIdentityManager#isCurrentUser(User) current user} are returned. Otherwise,
243 * the unfiltered {@link #getOpenChangesets() open changesets} are returned.
244 *
245 * @return a list of changesets
246 */
247 public List<Changeset> getOpenChangesetsForCurrentUser() {
248 if (UserIdentityManager.getInstance().isAnonymous()) {
249 return getOpenChangesets();
250 } else {
251 return new ArrayList<>(SubclassFilteredCollection.filter(getOpenChangesets(),
252 object -> UserIdentityManager.getInstance().isCurrentUser(object.getUser())));
253 }
254 }
255
256 /* ------------------------------------------------------------------------- */
257 /* interface PreferenceChangedListener */
258 /* ------------------------------------------------------------------------- */
259 @Override
260 public void preferenceChanged(PreferenceChangeEvent e) {
261 if (e.getKey() == null || !"osm-server.url".equals(e.getKey()))
262 return;
263
264 // clear the cache when the API url changes
265 if (e.getOldValue() == null || e.getNewValue() == null || !e.getOldValue().equals(e.getNewValue())) {
266 clear();
267 }
268 }
269}
Note: See TracBrowser for help on using the repository browser.