1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.diyefi.openlogviewer.genericlog;
24
25 import java.beans.PropertyChangeEvent;
26 import java.beans.PropertyChangeListener;
27 import java.beans.PropertyChangeSupport;
28 import java.util.LinkedHashMap;
29 import java.util.Iterator;
30 import org.diyefi.openlogviewer.OpenLogViewer;
31
32 public class GenericLog extends LinkedHashMap<String, GenericDataElement> {
33 private static final long serialVersionUID = 1L;
34
35
36
37 private static final String LOG_LOADED_TEXT = "LogLoaded";
38 public static enum LogState { LOG_NOT_LOADED, LOG_LOADING, LOG_LOADED }
39
40
41 public static final String recordCountKey = "OLV Record Count";
42 public static final String tempResetKey = "OLV Temp Resets";
43 public static final String elapsedTimeKey = "OLV Elapsed Time";
44 private static final int NUMBER_OF_BUILTIN_FIELDS = 3;
45 private static final int RECORD_COUNT_OFFSET = 0;
46 private static final int TEMP_RESET_OFFSET = 1;
47 private static final int ELAPSED_TIME_OFFSET = 2;
48 private static final int SIZE_OF_DOUBLE = 8;
49 private static final int NUMBER_OF_BYTES_IN_A_MEG = 1000000;
50 private GenericDataElement recordCountElement;
51
52 private String metaData;
53 protected final PropertyChangeSupport PCS;
54 private LogState logStatus;
55 private String logStatusMessage = null;
56
57
58 private int currentCapacity;
59 private int currentPosition = -1;
60
61 private int ourLoadFactor;
62 private int numberOfInternalHeaders;
63
64 private final PropertyChangeListener autoLoad = new PropertyChangeListener() {
65 public void propertyChange(final PropertyChangeEvent propertyChangeEvent) {
66 if ((LogState) propertyChangeEvent.getNewValue() == LogState.LOG_LOADING) {
67 final GenericLog genLog = (GenericLog) propertyChangeEvent.getSource();
68 genLog.setLogStatus(LogState.LOG_LOADING);
69 OpenLogViewer.getInstance().setLog(genLog);
70 } else if ((LogState) propertyChangeEvent.getNewValue() == LogState.LOG_LOADED) {
71 final GenericLog genLog = (GenericLog) propertyChangeEvent.getSource();
72 genLog.setLogStatus(LogState.LOG_LOADED);
73 OpenLogViewer.getInstance().setLog(genLog);
74 OpenLogViewer.getInstance().getOptionFrame().updateFromLog(genLog);
75 }
76 }
77 };
78
79
80
81
82
83
84 public GenericLog(final String[] headers, final int initialCapacity, final int ourLoadFactor) {
85 super(1 + (headers.length + NUMBER_OF_BUILTIN_FIELDS), 1.0f);
86
87 GenericDataElement.resetPosition();
88 logStatus = LogState.LOG_NOT_LOADED;
89 PCS = new PropertyChangeSupport(this);
90 addPropertyChangeListener(LOG_LOADED_TEXT, autoLoad);
91 metaData = "";
92
93 this.ourLoadFactor = ourLoadFactor;
94 currentCapacity = initialCapacity;
95
96
97 numberOfInternalHeaders = headers.length + NUMBER_OF_BUILTIN_FIELDS;
98 final String[] internalHeaders = new String[numberOfInternalHeaders];
99 for (int i = 0; i < headers.length; i++) {
100 internalHeaders[i] = headers[i];
101 }
102
103
104 internalHeaders[headers.length + RECORD_COUNT_OFFSET] = recordCountKey;
105 internalHeaders[headers.length + TEMP_RESET_OFFSET] = tempResetKey;
106 internalHeaders[headers.length + ELAPSED_TIME_OFFSET] = elapsedTimeKey;
107
108 for (int x = 0; x < internalHeaders.length; x++) {
109 GenericDataElement GDE = new GenericDataElement(initialCapacity);
110 GDE.setName(internalHeaders[x]);
111 this.put(internalHeaders[x], GDE);
112 }
113
114 recordCountElement = this.get(recordCountKey);
115 }
116
117
118
119
120
121
122
123 public final void addValue(final String key, final double value) {
124 this.get(key).add(value);
125 }
126
127 public final void incrementPosition() {
128 currentPosition++;
129 GenericDataElement.incrementPosition();
130 if (currentPosition >= currentCapacity) {
131 System.out.println(OpenLogViewer.NEWLINE + "############## Memory about to be resized! ##############");
132 final long startResizes = System.currentTimeMillis();
133 System.out.println("Old capacity = " + currentCapacity);
134 final Runtime ourRuntime = Runtime.getRuntime();
135
136 System.out.println("Memory Before = Max: " + ourRuntime.maxMemory() + ", Free: " + ourRuntime.freeMemory() + ", Total: " + ourRuntime.totalMemory());
137
138 int numberResized = 0;
139 final Iterator<GenericDataElement> genLogIterator = this.values().iterator();
140 while (genLogIterator.hasNext()) {
141
142 final long overheadInMemory = currentCapacity * SIZE_OF_DOUBLE;
143 final long increaseInMemory = overheadInMemory * ourLoadFactor;
144
145
146
147 final long requiredMemory = 2 * (increaseInMemory + overheadInMemory);
148 final long availableMemory = ourRuntime.freeMemory();
149
150 if (availableMemory < requiredMemory) {
151 currentPosition--;
152 final String jvmHelp = "Get more with -Xms and -Xmx JVM options!";
153 System.out.println("Detected impending out-of-memory doom! Details below! :-(");
154 System.out.println("Total" + "Available: " + availableMemory + " Required: " + requiredMemory + " Increase: " + increaseInMemory + " Overhead: " + overheadInMemory);
155 System.out.println(jvmHelp);
156 final long allocatedMemory = (ourRuntime.maxMemory() / NUMBER_OF_BYTES_IN_A_MEG);
157 throw new RuntimeException(allocatedMemory + "MB is insufficent memory to increase log size! " + jvmHelp + OpenLogViewer.NEWLINE
158 + "Completed " + numberResized + " of " + numberOfInternalHeaders
159 + " while increasing from " + currentCapacity + " records to " + (currentCapacity * ourLoadFactor) + " records!");
160 }
161
162 final GenericDataElement dataElement = genLogIterator.next();
163 dataElement.increaseCapacity(ourLoadFactor);
164 numberResized++;
165 }
166 currentCapacity *= ourLoadFactor;
167
168 System.out.println("Memory After = Max: " + ourRuntime.maxMemory() + ", Free: " + ourRuntime.freeMemory() + ", Total: " + ourRuntime.totalMemory());
169
170 final long finishResizes = System.currentTimeMillis();
171 System.out.println("New capacity = " + currentCapacity);
172 System.out.println("Resizes took " + (finishResizes - startResizes) + " ms");
173 }
174
175 recordCountElement.add((double) currentPosition);
176 }
177
178
179
180
181
182 public final void setLogStatus(final LogState newLogStatus) {
183 final LogState oldLogStatus = this.logStatus;
184 this.logStatus = newLogStatus;
185 PCS.firePropertyChange(LOG_LOADED_TEXT, oldLogStatus, newLogStatus);
186 }
187
188
189
190
191
192 public final LogState getLogStatus() {
193 return this.logStatus;
194 }
195
196
197
198
199
200
201 public final void setMetaData(final String md) {
202 metaData = md;
203 }
204
205
206
207
208
209 public final String getMetadata() {
210 return metaData;
211 }
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226 public final void addPropertyChangeListener(final String name, final PropertyChangeListener listener) {
227 PCS.addPropertyChangeListener(name, listener);
228 }
229
230
231
232
233
234
235 public final void removePropertyChangeListener(final String propertyName, final PropertyChangeListener listener) {
236 PCS.removePropertyChangeListener(propertyName, listener);
237 }
238
239 public final String getLogStatusMessage() {
240 return logStatusMessage;
241 }
242
243 public final void setLogStatusMessage(final String message) {
244 this.logStatusMessage = message;
245 }
246
247 public final int getRecordCount() {
248 return currentPosition;
249 }
250
251 public final void clearOut() {
252 final Iterator<GenericDataElement> lastRound = this.values().iterator();
253 while (lastRound.hasNext()) {
254 lastRound.next().clearOut();
255 }
256 this.clear();
257 }
258 }