MATSIM
EventFingerprint.java
Go to the documentation of this file.
1 package org.matsim.utils.eventsfilecomparison;
2 
3 import it.unimi.dsi.fastutil.floats.FloatArrayList;
4 import it.unimi.dsi.fastutil.floats.FloatList;
5 import it.unimi.dsi.fastutil.objects.Object2IntMap;
6 import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
8 
9 import java.io.DataInputStream;
10 import java.io.DataOutputStream;
11 import java.io.IOException;
12 import java.io.UncheckedIOException;
13 import java.nio.charset.StandardCharsets;
14 import java.security.MessageDigest;
15 import java.security.NoSuchAlgorithmException;
16 import java.util.Arrays;
17 import java.util.Map;
18 
30 public final class EventFingerprint {
31 
35  static final int HEADER_V1 = 0x46502f31;
36 
37  final FloatList timeArray;
38  final Object2IntMap<String> eventTypeCounter;
39  final byte[] hash;
40 
44  private final MessageDigest digest;
45 
46  private EventFingerprint(FloatList timeArray, Object2IntMap<String> eventTypeCounter, byte[] hash) {
47  this.timeArray = timeArray;
48  this.eventTypeCounter = eventTypeCounter;
49  this.hash = hash;
50  this.digest = null;
51  }
52 
54  this.timeArray = new FloatArrayList();
55  this.eventTypeCounter = new Object2IntOpenHashMap<>();
56  this.hash = new byte[20];
57 
58  try {
59  digest = MessageDigest.getInstance("SHA-1");
60  } catch (NoSuchAlgorithmException e) {
61  throw new IllegalStateException("Hashing not supported;");
62  }
63  }
64 
65  public static void write(String filePath, EventFingerprint eventFingerprint) {
66  try (DataOutputStream dataOutputStream = new DataOutputStream(IOUtils.getOutputStream(IOUtils.getFileUrl(filePath), false))) {
67  // Write header and version
68  dataOutputStream.writeInt(EventFingerprint.HEADER_V1);
69 
70  // Write time array size and elements
71  dataOutputStream.writeInt(eventFingerprint.timeArray.size());
72  for (float time : eventFingerprint.timeArray) {
73  dataOutputStream.writeFloat(time);
74  }
75 
76  // Write event type counter map size and elements
77  dataOutputStream.writeInt(eventFingerprint.eventTypeCounter.size());
78  for (Map.Entry<String, Integer> entry : eventFingerprint.eventTypeCounter.entrySet()) {
79  dataOutputStream.writeUTF(entry.getKey());
80  dataOutputStream.writeInt(entry.getValue());
81  }
82 
83  // Hash should always be computed at this point
84  assert !Arrays.equals(eventFingerprint.hash, new byte[20]) : "Hash was not computed";
85 
86  // Write byte hash
87  dataOutputStream.write(eventFingerprint.hash);
88 
89  } catch (IOException e) {
90  throw new UncheckedIOException(e);
91  }
92  }
93 
94  public static EventFingerprint read(String fingerprintPath) throws IOException {
95  EventFingerprint eventFingerprint;
96 
97  try (DataInputStream dataInputStream = new DataInputStream(IOUtils.getInputStream(IOUtils.getFileUrl(fingerprintPath)))) {
98  // Read header and version
99  int fileHeader = dataInputStream.readInt();
100 
101  if (fileHeader != EventFingerprint.HEADER_V1) {
102  throw new IllegalArgumentException("Invalid fingerprint file header");
103  }
104 
105  // Read time array
106  int timeArraySize = dataInputStream.readInt();
107  FloatList timeArray = new FloatArrayList();
108  for (int i = 0; i < timeArraySize; i++) {
109  timeArray.add(dataInputStream.readFloat());
110  }
111 
112  // Read event type counter map
113  int eventTypeCounterSize = dataInputStream.readInt();
114  Object2IntMap<String> eventTypeCounter = new Object2IntOpenHashMap<>();
115  for (int i = 0; i < eventTypeCounterSize; i++) {
116  String eventType = dataInputStream.readUTF();
117  int count = dataInputStream.readInt();
118  eventTypeCounter.put(eventType, count);
119  }
120 
121  // Read string hash
122  byte[] hash = dataInputStream.readNBytes(20);
123 
124  // Create EventFingerprint object
125  eventFingerprint = new EventFingerprint(timeArray, eventTypeCounter, hash);
126  }
127 
128  return eventFingerprint;
129  }
130 
131  void addTimeStamp(double timestamp) {
132  timeArray.add((float) timestamp);
133  }
134 
135  void addEventType(String str) {
136  // Increment the count for the given string
137  eventTypeCounter.mergeInt(str, 1, Integer::sum);
138  }
139 
140  void addHashCode(String stringToAdd) {
141  if (stringToAdd == null) {
142  return;
143  }
144 
145  digest.update(stringToAdd.getBytes(StandardCharsets.UTF_8));
146  }
147 
148  byte[] computeHash() {
149  if (this.digest == null)
150  throw new IllegalStateException("Hash was from from input and can not be computed");
151 
152  byte[] digest = this.digest.digest();
153  System.arraycopy(digest, 0, hash, 0, hash.length);
154  return hash;
155  }
156 
157  @Override
158  public String toString() {
159  return "EventFingerprint{" +
160  "timeArray=" + timeArray.size() +
161  ", eventTypeCounter=" + eventTypeCounter +
162  ", hash=" + Arrays.toString(hash) +
163  '}';
164  }
165 }
EventFingerprint(FloatList timeArray, Object2IntMap< String > eventTypeCounter, byte[] hash)
static InputStream getInputStream(URL url)
Definition: IOUtils.java:281
static URL getFileUrl(String filename)
Definition: IOUtils.java:501
static OutputStream getOutputStream(URL url, boolean append)
Definition: IOUtils.java:344
static EventFingerprint read(String fingerprintPath)
static void write(String filePath, EventFingerprint eventFingerprint)