1
2
3
4 package de.powerstat.validation.containers;
5
6
7 import java.time.OffsetDateTime;
8 import java.time.format.DateTimeFormatter;
9 import java.util.Map;
10 import java.util.NoSuchElementException;
11 import java.util.Objects;
12 import java.util.Set;
13 import java.util.SortedMap;
14 import java.util.concurrent.ConcurrentSkipListMap;
15
16
17
18
19
20
21
22
23
24 public class HistoryOf<T>
25 {
26
27
28
29 private final SortedMap<OffsetDateTime, T> history = new ConcurrentSkipListMap<>();
30
31
32
33
34
35 public HistoryOf()
36 {
37 super();
38 }
39
40
41
42
43
44
45
46
47 @Override
48 public int hashCode()
49 {
50 if (this.history.isEmpty())
51 {
52 return 0;
53 }
54 return Objects.hash(this.getLatestEntry());
55 }
56
57
58
59
60
61
62
63
64
65
66 @Override
67 public boolean equals(final Object obj)
68 {
69 if (this == obj)
70 {
71 return true;
72 }
73 if (!(obj instanceof HistoryOf<?>))
74
75 {
76 return false;
77 }
78 final HistoryOf<T> other = (HistoryOf<T>)obj;
79 if ((this.history.isEmpty()) || (other.history.isEmpty()))
80 {
81 return ((this.history.isEmpty()) && (other.history.isEmpty()));
82 }
83 return this.getLatestEntry().equals(other.getLatestEntry());
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97 @Override
98 public String toString()
99 {
100 final var builder = new StringBuilder();
101 builder.append("HistoryOf<>[");
102 final int initLength = builder.length();
103 for (final Map.Entry<OffsetDateTime, T> entry : this.history.entrySet())
104 {
105 builder.append(entry.getKey().format(DateTimeFormatter.ISO_DATE_TIME));
106 builder.append('=');
107 builder.append(entry.getValue());
108 builder.append(", ");
109 }
110 if (builder.length() > initLength)
111 {
112 builder.setLength(builder.length() - 2);
113 }
114 builder.append(']');
115 return builder.toString();
116 }
117
118
119
120
121
122
123
124 public boolean isEmpty()
125 {
126 return this.history.isEmpty();
127 }
128
129
130
131
132
133
134
135
136
137
138
139 public void addEntry(final OffsetDateTime since, final T entry)
140 {
141 Objects.requireNonNull(since, "since");
142 Objects.requireNonNull(entry, "entry");
143 if (since.isAfter(OffsetDateTime.now()))
144 {
145 throw new IndexOutOfBoundsException("since lies in the future!");
146 }
147 if ((!this.history.isEmpty()) && entry.equals(this.getLatestEntry()))
148 {
149 throw new IllegalArgumentException("entry is already latest in HistoryOf!");
150 }
151 this.history.put(since, entry);
152 }
153
154
155
156
157
158
159
160
161 public T getFirstEntry()
162 {
163 return this.history.get(this.history.firstKey());
164 }
165
166
167
168
169
170
171
172
173 public T getLatestEntry()
174 {
175 return this.history.get(this.history.lastKey());
176 }
177
178
179
180
181
182
183
184
185 public T getPreviousEntry()
186 {
187 final Set<OffsetDateTime> keys = this.history.keySet();
188 OffsetDateTime previous = this.history.firstKey();
189 OffsetDateTime latest = this.history.firstKey();
190 for (final OffsetDateTime key : keys)
191 {
192 if (!latest.equals(key))
193 {
194 if (!previous.equals(latest))
195 {
196 previous = latest;
197 }
198 latest = key;
199 }
200 }
201 return this.history.get(previous);
202 }
203
204
205
206
207
208
209
210 public SortedMap<OffsetDateTime, T> getHistory()
211 {
212 return new ConcurrentSkipListMap<>(this.history);
213 }
214
215 }