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

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

javadoc

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