source: josm/trunk/src/org/openstreetmap/josm/data/osm/history/History.java@ 16581

Last change on this file since 16581 was 16445, checked in by simon04, 4 years ago

see #19251 - Java 8: use Stream

  • Property svn:eol-style set to native
File size: 9.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm.history;
3
4import java.text.MessageFormat;
5import java.util.ArrayList;
6import java.util.Comparator;
7import java.util.Date;
8import java.util.List;
9import java.util.stream.Collectors;
10
11import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
12import org.openstreetmap.josm.data.osm.PrimitiveId;
13import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
14import org.openstreetmap.josm.tools.CheckParameterUtil;
15
16/**
17 * Represents the history of an OSM primitive. The history consists
18 * of a list of object snapshots with a specific version.
19 * @since 1670
20 */
21public class History {
22
23 @FunctionalInterface
24 private interface FilterPredicate {
25 boolean matches(HistoryOsmPrimitive primitive);
26 }
27
28 private static History filter(History history, FilterPredicate predicate) {
29 List<HistoryOsmPrimitive> out = history.versions.stream()
30 .filter(predicate::matches)
31 .collect(Collectors.toList());
32 return new History(history.id, history.type, out);
33 }
34
35 /** the list of object snapshots */
36 private final List<HistoryOsmPrimitive> versions;
37 /** the object id */
38 private final long id;
39 /** the object type */
40 private final OsmPrimitiveType type;
41
42 /**
43 * Creates a new history for an OSM primitive.
44 *
45 * @param id the id. &gt; 0 required.
46 * @param type the primitive type. Must not be null.
47 * @param versions a list of versions. Can be null.
48 * @throws IllegalArgumentException if id &lt;= 0
49 * @throws IllegalArgumentException if type is null
50 */
51 protected History(long id, OsmPrimitiveType type, List<HistoryOsmPrimitive> versions) {
52 if (id <= 0)
53 throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0 expected, got {1}", "id", id));
54 CheckParameterUtil.ensureParameterNotNull(type, "type");
55 this.id = id;
56 this.type = type;
57 this.versions = new ArrayList<>();
58 if (versions != null) {
59 this.versions.addAll(versions);
60 }
61 }
62
63 /**
64 * Returns a new copy of this history, sorted in ascending order.
65 * @return a new copy of this history, sorted in ascending order
66 */
67 public History sortAscending() {
68 List<HistoryOsmPrimitive> copy = new ArrayList<>(versions);
69 copy.sort(Comparator.naturalOrder());
70 return new History(id, type, copy);
71 }
72
73 /**
74 * Returns a new copy of this history, sorted in descending order.
75 * @return a new copy of this history, sorted in descending order
76 */
77 public History sortDescending() {
78 List<HistoryOsmPrimitive> copy = new ArrayList<>(versions);
79 copy.sort(Comparator.reverseOrder());
80 return new History(id, type, copy);
81 }
82
83 /**
84 * Returns a new partial copy of this history, from the given date
85 * @param fromDate the starting date
86 * @return a new partial copy of this history, from the given date
87 */
88 public History from(final Date fromDate) {
89 return filter(this, primitive -> primitive.getTimestamp().compareTo(fromDate) >= 0);
90 }
91
92 /**
93 * Returns a new partial copy of this history, until the given date
94 * @param untilDate the end date
95 * @return a new partial copy of this history, until the given date
96 */
97 public History until(final Date untilDate) {
98 return filter(this, primitive -> primitive.getTimestamp().compareTo(untilDate) <= 0);
99 }
100
101 /**
102 * Returns a new partial copy of this history, between the given dates
103 * @param fromDate the starting date
104 * @param untilDate the end date
105 * @return a new partial copy of this history, between the given dates
106 */
107 public History between(Date fromDate, Date untilDate) {
108 return this.from(fromDate).until(untilDate);
109 }
110
111 /**
112 * Returns a new partial copy of this history, from the given version number
113 * @param fromVersion the starting version number
114 * @return a new partial copy of this history, from the given version number
115 */
116 public History from(final long fromVersion) {
117 return filter(this, primitive -> primitive.getVersion() >= fromVersion);
118 }
119
120 /**
121 * Returns a new partial copy of this history, to the given version number
122 * @param untilVersion the ending version number
123 * @return a new partial copy of this history, to the given version number
124 */
125 public History until(final long untilVersion) {
126 return filter(this, primitive -> primitive.getVersion() <= untilVersion);
127 }
128
129 /**
130 * Returns a new partial copy of this history, betwwen the given version numbers
131 * @param fromVersion the starting version number
132 * @param untilVersion the ending version number
133 * @return a new partial copy of this history, between the given version numbers
134 */
135 public History between(long fromVersion, long untilVersion) {
136 return this.from(fromVersion).until(untilVersion);
137 }
138
139 /**
140 * Returns a new partial copy of this history, for the given user id
141 * @param uid the user id
142 * @return a new partial copy of this history, for the given user id
143 */
144 public History forUserId(final long uid) {
145 return filter(this, primitive -> primitive.getUser() != null && primitive.getUser().getId() == uid);
146 }
147
148 /**
149 * Replies the primitive id for this history.
150 *
151 * @return the primitive id
152 * @see #getPrimitiveId
153 * @see #getType
154 */
155 public long getId() {
156 return id;
157 }
158
159 /**
160 * Replies the primitive id for this history.
161 *
162 * @return the primitive id
163 * @see #getId
164 */
165 public PrimitiveId getPrimitiveId() {
166 return new SimplePrimitiveId(id, type);
167 }
168
169 /**
170 * Determines if this history contains a specific version number.
171 * @param version the version number to look for
172 * @return {@code true} if this history contains {@code version}, {@code false} otherwise
173 */
174 public boolean contains(long version) {
175 return versions.stream().anyMatch(primitive -> primitive.matches(id, version));
176 }
177
178 /**
179 * Replies the history primitive with version <code>version</code>. null,
180 * if no such primitive exists.
181 *
182 * @param version the version
183 * @return the history primitive with version <code>version</code>
184 */
185 public HistoryOsmPrimitive getByVersion(long version) {
186 return versions.stream()
187 .filter(primitive -> primitive.matches(id, version))
188 .findFirst().orElse(null);
189 }
190
191 /**
192 * Replies the history primitive at given <code>date</code>. null,
193 * if no such primitive exists.
194 *
195 * @param date the date
196 * @return the history primitive at given <code>date</code>
197 */
198 public HistoryOsmPrimitive getByDate(Date date) {
199 History h = sortAscending();
200
201 if (h.versions.isEmpty())
202 return null;
203 if (h.get(0).getTimestamp().compareTo(date) > 0)
204 return null;
205 for (int i = 1; i < h.versions.size(); i++) {
206 if (h.get(i-1).getTimestamp().compareTo(date) <= 0
207 && h.get(i).getTimestamp().compareTo(date) >= 0)
208 return h.get(i);
209 }
210 return h.getLatest();
211 }
212
213 /**
214 * Replies the history primitive at index <code>idx</code>.
215 *
216 * @param idx the index
217 * @return the history primitive at index <code>idx</code>
218 * @throws IndexOutOfBoundsException if index out or range
219 */
220 public HistoryOsmPrimitive get(int idx) {
221 if (idx < 0 || idx >= versions.size())
222 throw new IndexOutOfBoundsException(MessageFormat.format(
223 "Parameter ''{0}'' in range 0..{1} expected. Got ''{2}''.", "idx", versions.size()-1, idx));
224 return versions.get(idx);
225 }
226
227 /**
228 * Replies the earliest entry of this history.
229 * @return the earliest entry of this history
230 */
231 public HistoryOsmPrimitive getEarliest() {
232 if (isEmpty())
233 return null;
234 return sortAscending().versions.get(0);
235 }
236
237 /**
238 * Replies the latest entry of this history.
239 * @return the latest entry of this history
240 */
241 public HistoryOsmPrimitive getLatest() {
242 if (isEmpty())
243 return null;
244 return sortDescending().versions.get(0);
245 }
246
247 /**
248 * Replies the number of versions.
249 * @return the number of versions
250 */
251 public int getNumVersions() {
252 return versions.size();
253 }
254
255 /**
256 * Returns true if this history contains no version.
257 * @return {@code true} if this history contains no version, {@code false} otherwise
258 */
259 public final boolean isEmpty() {
260 return versions.isEmpty();
261 }
262
263 /**
264 * Replies the primitive type for this history.
265 * @return the primitive type
266 * @see #getId
267 */
268 public OsmPrimitiveType getType() {
269 return type;
270 }
271
272 @Override
273 public String toString() {
274 StringBuilder result = new StringBuilder("History ["
275 + (type != null ? ("type=" + type + ", ") : "") + "id=" + id);
276 if (versions != null) {
277 result.append(", versions=\n");
278 for (HistoryOsmPrimitive v : versions) {
279 result.append('\t').append(v).append(",\n");
280 }
281 }
282 result.append(']');
283 return result.toString();
284 }
285}
Note: See TracBrowser for help on using the repository browser.