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

Last change on this file since 11177 was 11115, checked in by simon04, 8 years ago

fix #13785 - Use streams, add unit tests (patch by alno, modified)

  • Property svn:eol-style set to native
File size: 7.1 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 /**
42 * Replies the unique instance of the cache
43 *
44 * @return the unique instance of the cache
45 */
46 public static ChangesetCache getInstance() {
47 return instance;
48 }
49
50 /** the cached changesets */
51 private final Map<Integer, Changeset> cache = new HashMap<>();
52
53 private final CopyOnWriteArrayList<ChangesetCacheListener> listeners = new CopyOnWriteArrayList<>();
54
55 private ChangesetCache() {
56 Main.pref.addPreferenceChangeListener(this);
57 }
58
59 public void addChangesetCacheListener(ChangesetCacheListener listener) {
60 if (listener != null) {
61 listeners.addIfAbsent(listener);
62 }
63 }
64
65 public void removeChangesetCacheListener(ChangesetCacheListener listener) {
66 if (listener != null) {
67 listeners.remove(listener);
68 }
69 }
70
71 private void fireChangesetCacheEvent(final ChangesetCacheEvent e) {
72 GuiHelper.runInEDT(() -> {
73 for (ChangesetCacheListener l: listeners) {
74 l.changesetCacheUpdated(e);
75 }
76 });
77 }
78
79 private void update(Changeset cs, DefaultChangesetCacheEvent e) {
80 if (cs == null) return;
81 if (cs.isNew()) return;
82 Changeset inCache = cache.get(cs.getId());
83 if (inCache != null) {
84 inCache.mergeFrom(cs);
85 e.rememberUpdatedChangeset(inCache);
86 } else {
87 e.rememberAddedChangeset(cs);
88 cache.put(cs.getId(), cs);
89 }
90 }
91
92 public void update(Changeset cs) {
93 DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
94 update(cs, e);
95 fireChangesetCacheEvent(e);
96 }
97
98 public void update(Collection<Changeset> changesets) {
99 if (changesets == null || changesets.isEmpty()) return;
100 DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
101 for (Changeset cs: changesets) {
102 update(cs, e);
103 }
104 fireChangesetCacheEvent(e);
105 }
106
107 public boolean contains(int id) {
108 if (id <= 0) return false;
109 return cache.get(id) != null;
110 }
111
112 public boolean contains(Changeset cs) {
113 if (cs == null) return false;
114 if (cs.isNew()) return false;
115 return contains(cs.getId());
116 }
117
118 public Changeset get(int id) {
119 return cache.get(id);
120 }
121
122 public Set<Changeset> getChangesets() {
123 return new HashSet<>(cache.values());
124 }
125
126 private void remove(int id, DefaultChangesetCacheEvent e) {
127 if (id <= 0) return;
128 Changeset cs = cache.get(id);
129 if (cs == null) return;
130 cache.remove(id);
131 e.rememberRemovedChangeset(cs);
132 }
133
134 public void remove(int id) {
135 DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
136 remove(id, e);
137 if (!e.isEmpty()) {
138 fireChangesetCacheEvent(e);
139 }
140 }
141
142 public void remove(Changeset cs) {
143 if (cs == null) return;
144 if (cs.isNew()) return;
145 remove(cs.getId());
146 }
147
148 /**
149 * Removes the changesets in <code>changesets</code> from the cache. A
150 * {@link ChangesetCacheEvent} is fired.
151 *
152 * @param changesets the changesets to remove. Ignored if null.
153 */
154 public void remove(Collection<Changeset> changesets) {
155 if (changesets == null) return;
156 DefaultChangesetCacheEvent evt = new DefaultChangesetCacheEvent(this);
157 for (Changeset cs : changesets) {
158 if (cs == null || cs.isNew()) {
159 continue;
160 }
161 remove(cs.getId(), evt);
162 }
163 if (!evt.isEmpty()) {
164 fireChangesetCacheEvent(evt);
165 }
166 }
167
168 public int size() {
169 return cache.size();
170 }
171
172 public void clear() {
173 DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
174 for (Changeset cs: cache.values()) {
175 e.rememberRemovedChangeset(cs);
176 }
177 cache.clear();
178 fireChangesetCacheEvent(e);
179 }
180
181 /**
182 * Replies the list of open changesets.
183 * @return The list of open changesets
184 */
185 public List<Changeset> getOpenChangesets() {
186 return cache.values().stream()
187 .filter(Changeset::isOpen)
188 .collect(Collectors.toList());
189 }
190
191 /**
192 * If the current user {@link JosmUserIdentityManager#isAnonymous() is known}, the {@link #getOpenChangesets() open changesets}
193 * for the {@link JosmUserIdentityManager#isCurrentUser(User) current user} are returned. Otherwise,
194 * the unfiltered {@link #getOpenChangesets() open changesets} are returned.
195 *
196 * @return a list of changesets
197 */
198 public List<Changeset> getOpenChangesetsForCurrentUser() {
199 if (JosmUserIdentityManager.getInstance().isAnonymous()) {
200 return getOpenChangesets();
201 } else {
202 return new ArrayList<>(SubclassFilteredCollection.filter(getOpenChangesets(),
203 object -> JosmUserIdentityManager.getInstance().isCurrentUser(object.getUser())));
204 }
205 }
206
207 /* ------------------------------------------------------------------------- */
208 /* interface PreferenceChangedListener */
209 /* ------------------------------------------------------------------------- */
210 @Override
211 public void preferenceChanged(PreferenceChangeEvent e) {
212 if (e.getKey() == null || !"osm-server.url".equals(e.getKey()))
213 return;
214
215 // clear the cache when the API url changes
216 if (e.getOldValue() == null || e.getNewValue() == null || !e.getOldValue().equals(e.getNewValue())) {
217 clear();
218 }
219 }
220}
Note: See TracBrowser for help on using the repository browser.