1
2
3
4
5
6
7
8
9
10
11 package psiprobe.beans.stats.listeners;
12
13 import java.util.HashMap;
14 import java.util.LinkedList;
15 import java.util.Map;
16
17 import psiprobe.Utils;
18
19
20
21
22
23
24
25
26
27
28 public abstract class AbstractFlapListener extends AbstractThresholdListener {
29
30
31 private int defaultFlapInterval;
32
33
34 private float defaultFlapStartThreshold;
35
36
37 private float defaultFlapStopThreshold;
38
39
40 private float defaultFlapLowWeight;
41
42
43 private float defaultFlapHighWeight;
44
45
46 private final Map<String, LinkedList<Boolean>> flaps = new HashMap<>();
47
48
49 private final Map<String, Boolean> flappingStates = new HashMap<>();
50
51
52
53
54
55
56 protected abstract void flappingStarted(StatsCollectionEvent sce);
57
58
59
60
61
62
63 protected abstract void aboveThresholdFlappingStopped(StatsCollectionEvent sce);
64
65
66
67
68
69
70 protected abstract void belowThresholdFlappingStopped(StatsCollectionEvent sce);
71
72
73
74
75
76
77 protected abstract void aboveThresholdNotFlapping(StatsCollectionEvent sce);
78
79
80
81
82
83
84 protected abstract void belowThresholdNotFlapping(StatsCollectionEvent sce);
85
86 @Override
87 protected void crossedAboveThreshold(StatsCollectionEvent sce) {
88 statsCollected(sce, true, true);
89 }
90
91 @Override
92 protected void crossedBelowThreshold(StatsCollectionEvent sce) {
93 statsCollected(sce, true, false);
94 }
95
96 @Override
97 protected void remainedAboveThreshold(StatsCollectionEvent sce) {
98 statsCollected(sce, false, true);
99 }
100
101 @Override
102 protected void remainedBelowThreshold(StatsCollectionEvent sce) {
103 statsCollected(sce, false, false);
104 }
105
106 @Override
107 public void reset() {
108 flaps.clear();
109 flappingStates.clear();
110 super.reset();
111 }
112
113
114
115
116
117
118
119
120 protected void statsCollected(StatsCollectionEvent sce, boolean crossedThreshold, boolean above) {
121 String name = sce.getName();
122 boolean flappingStateChanged = checkFlappingStateChanged(name, crossedThreshold);
123 boolean flappingState = getFlappingState(name);
124 if (flappingStateChanged) {
125 if (flappingState) {
126 flappingStarted(sce);
127 } else if (above) {
128 aboveThresholdFlappingStopped(sce);
129 } else {
130 belowThresholdFlappingStopped(sce);
131 }
132 } else if (crossedThreshold) {
133 if (above) {
134 aboveThresholdNotFlapping(sce);
135 } else {
136 belowThresholdNotFlapping(sce);
137 }
138 }
139 }
140
141
142
143
144
145
146
147
148
149 protected boolean checkFlappingStateChanged(String name, boolean crossedThreshold) {
150 addFlap(name, crossedThreshold);
151 boolean oldFlappingState = getFlappingState(name);
152 float transitionPercent = calculateStateTransitionPercentage(name, oldFlappingState);
153 boolean newFlappingState;
154 if (oldFlappingState) {
155 newFlappingState = transitionPercent <= getFlapStopThreshold(name);
156 } else {
157 newFlappingState = transitionPercent > getFlapStartThreshold(name);
158 }
159 setFlappingState(name, newFlappingState);
160 return oldFlappingState != newFlappingState;
161 }
162
163
164
165
166
167
168
169
170
171 protected float calculateStateTransitionPercentage(String name, boolean flapping) {
172 int flapInterval = getFlapInterval(name);
173 LinkedList<Boolean> list = getFlaps(name);
174 float lowWeight = getFlapLowWeight(name);
175 float highWeight = getFlapHighWeight(name);
176 float weightRange = highWeight - lowWeight;
177 float result = 0;
178 for (int i = list.size() - 1; i >= 0; i--) {
179 boolean thisFlap = list.get(i);
180 if (flapping != thisFlap) {
181 float weight = lowWeight + weightRange * i / (flapInterval - 1);
182 result += weight;
183 }
184 }
185 return result / flapInterval;
186 }
187
188
189
190
191
192
193
194 protected void addFlap(String name, boolean flap) {
195 int flapInterval = getFlapInterval(name);
196 LinkedList<Boolean> list = getFlaps(name);
197 Boolean value = flap;
198 list.addLast(value);
199 while (list.size() > flapInterval) {
200 list.removeFirst();
201 }
202 }
203
204
205
206
207
208
209
210
211 protected boolean getFlappingState(String name) {
212 Boolean flapping = flappingStates.get(name);
213 if (flapping == null) {
214 flapping = Boolean.FALSE;
215 setFlappingState(name, false);
216 }
217 return flapping;
218 }
219
220
221
222
223
224
225
226 protected void setFlappingState(String name, boolean flapping) {
227 flappingStates.put(name, flapping);
228 }
229
230
231
232
233
234
235
236
237 protected LinkedList<Boolean> getFlaps(String name) {
238 return flaps.computeIfAbsent(name, s -> new LinkedList<>());
239 }
240
241
242
243
244
245
246
247
248 protected int getFlapInterval(String name) {
249 String interval = getPropertyValue(name, "flapInterval");
250 return Utils.toInt(interval, getDefaultFlapInterval());
251 }
252
253
254
255
256
257
258
259
260 protected float getFlapStartThreshold(String name) {
261 String startThreshold = getPropertyValue(name, "flapStartThreshold");
262 return Utils.toFloat(startThreshold, getDefaultFlapStartThreshold());
263 }
264
265
266
267
268
269
270
271
272 protected float getFlapStopThreshold(String name) {
273 String stopThreshold = getPropertyValue(name, "flapStopThreshold");
274 return Utils.toFloat(stopThreshold, getDefaultFlapStopThreshold());
275 }
276
277
278
279
280
281
282
283
284 protected float getFlapLowWeight(String name) {
285 String lowWeight = getPropertyValue(name, "flapLowWeight");
286 return Utils.toFloat(lowWeight, getDefaultFlapLowWeight());
287 }
288
289
290
291
292
293
294
295
296 protected float getFlapHighWeight(String name) {
297 String highWeight = getPropertyValue(name, "flapHighWeight");
298 return Utils.toFloat(highWeight, getDefaultFlapHighWeight());
299 }
300
301
302
303
304
305
306 public int getDefaultFlapInterval() {
307 return defaultFlapInterval;
308 }
309
310
311
312
313
314
315 public void setDefaultFlapInterval(int defaultFlapInterval) {
316 this.defaultFlapInterval = defaultFlapInterval;
317 }
318
319
320
321
322
323
324 public float getDefaultFlapStartThreshold() {
325 return defaultFlapStartThreshold;
326 }
327
328
329
330
331
332
333 public void setDefaultFlapStartThreshold(float defaultFlapStartThreshold) {
334 this.defaultFlapStartThreshold = defaultFlapStartThreshold;
335 }
336
337
338
339
340
341
342 public float getDefaultFlapStopThreshold() {
343 return defaultFlapStopThreshold;
344 }
345
346
347
348
349
350
351 public void setDefaultFlapStopThreshold(float defaultFlapStopThreshold) {
352 this.defaultFlapStopThreshold = defaultFlapStopThreshold;
353 }
354
355
356
357
358
359
360 public float getDefaultFlapLowWeight() {
361 return defaultFlapLowWeight;
362 }
363
364
365
366
367
368
369 public void setDefaultFlapLowWeight(float defaultFlapLowWeight) {
370 this.defaultFlapLowWeight = defaultFlapLowWeight;
371 }
372
373
374
375
376
377
378 public float getDefaultFlapHighWeight() {
379 return defaultFlapHighWeight;
380 }
381
382
383
384
385
386
387 public void setDefaultFlapHighWeight(float defaultFlapHighWeight) {
388 this.defaultFlapHighWeight = defaultFlapHighWeight;
389 }
390
391 }