128 }
129 };
130 private final static LinearUnit MEBIBYTES = UnitLookup.MEMORY.getUnit(BinaryPrefix.MEBI);
131
132 /**
133 * Matches strings containing an identifiable version number as presented in a JVM info event.
134 * The minimal matching form is "JRE (" followed by 1 to 4 numbers on the format a.b.c_d or
135 * a.b.c.d. Examples are 1.7.0, 1.8.0_70, 9, 9.1, and 9.1.2.3. Match group 1 will contain the
136 * matched version string.
137 */
138 private static final Pattern VERSION_PATTERN = Pattern
139 .compile(".*?JRE \\((\\d+(?:\\.\\d+(?:\\.\\d+(?:[\\._]\\d+)?)?)?(?:-ea)?).*"); //$NON-NLS-1$
140
141 /**
142 * Knowledge about the state of affairs of an event type in an IItemCollection.
143 */
144 public enum EventAvailability {
145 /**
146 * The type has events available in the collection.
147 */
148 AVAILABLE,
149 /**
150 * The type was actively enabled in the collection.
151 */
152 ENABLED,
153 /**
154 * The type was actively disabled in the collection.
155 */
156 DISABLED,
157 /**
158 * The type is known in the collection, but no events were found.
159 */
160 NONE,
161 /**
162 * The type is unknown in the collection.
163 */
164 UNAVAILABLE
165 }
166
167 /**
168 * @return a least squares approximation of the increase in memory over the given time period,
169 * in mebibytes/second
170 */
171 public static double leastSquareMemory(
172 Iterator<? extends IItem> items, IMemberAccessor<IQuantity, IItem> timeField,
173 IMemberAccessor<IQuantity, IItem> memField) {
174 double sumX = 0;
175 double sumY = 0;
176 double sumX2 = 0;
177 double sumXY = 0;
178 double num = 0;
179 double startTime = 0;
180
181 while (items.hasNext()) {
182 IItem item = items.next();
183 long time = timeField.getMember(item).clampedLongValueIn(UnitLookup.EPOCH_S);
184 long mem = memField.getMember(item).clampedLongValueIn(MEBIBYTES);
369 * the collection to check.
370 * @param typeIds
371 * the identifiers for the event types to check.
372 * @return true if all of the required event types were known to be explicitly enabled.
373 */
374 public static boolean isEventsEnabled(IItemCollection items, String ... typeIds) {
375 IQuantity aggregate = items.apply(createEnablementFilter(true, typeIds)).getAggregate(Aggregators.count());
376 return aggregate != null && aggregate.longValue() == typeIds.length;
377 }
378
379 /**
380 * This method returns false if any {@link EventAvailability} is disabled or unavailable.
381 * Otherwise true.
382 *
383 * @param eventAvailabilities
384 * the {@link EventAvailability} to check
385 * @return false if any {@link EventAvailability} is disabled or unavailable. Otherwise true.
386 */
387 public static boolean isEventsEnabled(EventAvailability ... eventAvailabilities) {
388 for (EventAvailability availability : eventAvailabilities) {
389 if (availability == EventAvailability.DISABLED || availability == EventAvailability.UNAVAILABLE) {
390 return false;
391 }
392 }
393 return true;
394 }
395
396 /**
397 * This method checks if the provided event types were explicitly disabled by checking the
398 * recording setting events.
399 *
400 * @param items
401 * the collection to check.
402 * @param typeIds
403 * the identifiers for the event types to check.
404 * @return true if all of the required event types were known to be explicitly enabled.
405 */
406 private static boolean isEventsDisabled(IItemCollection items, String ... typeIds) {
407 IQuantity aggregate = items.apply(createEnablementFilter(false, typeIds)).getAggregate(Aggregators.count());
408 return aggregate != null && aggregate.longValue() == typeIds.length;
409 }
419 * the collection to check
420 * @param typeIds
421 * the type identifiers to check
422 * @return the availability for the event types
423 */
424 public static EventAvailability getEventAvailability(IItemCollection items, final String ... typeIds) {
425 // Only AVAILABLE if exactly all types have events
426 if (hasEvents(items, typeIds)) {
427 return EventAvailability.AVAILABLE;
428 }
429 // If enabled at any point, it was indeed enabled, and events could have been recorded
430 if (isEventsEnabled(items, typeIds)) {
431 return EventAvailability.ENABLED;
432 }
433 if (isEventsDisabled(items, typeIds)) {
434 return EventAvailability.DISABLED;
435 }
436 if (isEventsKnown(items, typeIds)) {
437 return EventAvailability.NONE;
438 }
439 return EventAvailability.UNAVAILABLE;
440 }
441
442 /**
443 * Checks if the event types are known in the collection. Note that it does not necessarily mean
444 * that there are events of the event type.
445 *
446 * @param items
447 * the collection to check
448 * @param typeIds
449 * the event types to check
450 * @return true if all the event types exists in the collection.
451 */
452 private static boolean isEventsKnown(IItemCollection items, String ... typeIds) {
453 Set<String> availableTypes = getAvailableTypeIds(items);
454 if (availableTypes.containsAll(Arrays.asList(typeIds))) {
455 return true;
456 }
457 return false;
458 }
459
491 * @return the result for the provided availability problem
492 */
493 public static Result getEventAvailabilityResult(
494 IRule rule, IItemCollection items, EventAvailability eventAvailability, String ... typeIds) {
495 switch (eventAvailability) {
496 case ENABLED:
497 case NONE:
498 String requiredEventsTypeNames = getEventTypeNames(items, typeIds);
499 return getNotApplicableResult(rule,
500 MessageFormat.format(Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_EVENTS),
501 requiredEventsTypeNames),
502 MessageFormat.format(Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_EVENTS_LONG),
503 rule.getName(), requiredEventsTypeNames));
504 case DISABLED:
505 String disabledEventTypeNames = getDisabledEventTypeNames(items, typeIds);
506 return getNotApplicableResult(rule,
507 MessageFormat.format(Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_EVENT_TYPE),
508 disabledEventTypeNames),
509 MessageFormat.format(Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_EVENT_TYPE_LONG),
510 rule.getName(), disabledEventTypeNames));
511 case UNAVAILABLE:
512 // Can't get type names if the event type is unavailable
513 List<String> quotedTypeIds = new ArrayList<>();
514 for (String typeId : typeIds) {
515 quotedTypeIds.add("'" + typeId + "'"); //$NON-NLS-1$ //$NON-NLS-2$
516 }
517 Collections.sort(quotedTypeIds);
518 String unavailableTypeNames = StringToolkit.join(quotedTypeIds, ", "); //$NON-NLS-1$
519 return getNotApplicableResult(rule,
520 MessageFormat.format(Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_UNAVAILABLE_EVENT_TYPE),
521 rule.getName(), unavailableTypeNames),
522 MessageFormat.format(
523 Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_UNAVAILABLE_EVENT_TYPE_LONG),
524 rule.getName(), unavailableTypeNames));
525 case AVAILABLE:
526 String availableEventTypeNames = getEventTypeNames(items, typeIds);
527 return getNotApplicableResult(rule,
528 MessageFormat.format(
529 Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_EVENT_TYPE_NOT_AVAILABLE),
530 availableEventTypeNames),
531 MessageFormat.format(Messages.RulesToolkit_RULE_REQUIRES_EVENT_TYPE_NOT_AVAILABLE_LONG,
|
128 }
129 };
130 private final static LinearUnit MEBIBYTES = UnitLookup.MEMORY.getUnit(BinaryPrefix.MEBI);
131
132 /**
133 * Matches strings containing an identifiable version number as presented in a JVM info event.
134 * The minimal matching form is "JRE (" followed by 1 to 4 numbers on the format a.b.c_d or
135 * a.b.c.d. Examples are 1.7.0, 1.8.0_70, 9, 9.1, and 9.1.2.3. Match group 1 will contain the
136 * matched version string.
137 */
138 private static final Pattern VERSION_PATTERN = Pattern
139 .compile(".*?JRE \\((\\d+(?:\\.\\d+(?:\\.\\d+(?:[\\._]\\d+)?)?)?(?:-ea)?).*"); //$NON-NLS-1$
140
141 /**
142 * Knowledge about the state of affairs of an event type in an IItemCollection.
143 */
144 public enum EventAvailability {
145 /**
146 * The type has events available in the collection.
147 */
148 AVAILABLE(4),
149 /**
150 * The type was actively enabled in the collection.
151 */
152 ENABLED(3),
153 /**
154 * The type was actively disabled in the collection.
155 */
156 DISABLED(2),
157 /**
158 * The type is known in the collection, but no events were found.
159 */
160 NONE(1),
161 /**
162 * The type is unknown in the collection.
163 */
164 UNKNOWN(0);
165
166 /*
167 * Used to determine the ordering of availabilities.
168 */
169 private final int availabilityScore;
170
171 EventAvailability(int availabilityScore) {
172 this.availabilityScore = availabilityScore;
173 }
174
175 /**
176 * Returns true if this EventAvailability is more available than the provided one.
177 *
178 * @param availability
179 * the {@link EventAvailability} to compare to.
180 * @return true if this EventAvailability is more available than the provided one.
181 */
182 public boolean isMoreAvailableThan(EventAvailability availability) {
183 return availabilityScore > availability.availabilityScore;
184 }
185
186 /**
187 * Returns true if this EventAvailability is less available than the provided one.
188 *
189 * @param availability
190 * the {@link EventAvailability} to compare to.
191 * @return true if this EventAvailability is less available than the provided one.
192 */
193 public boolean isLessAvailableThan(EventAvailability availability) {
194 return availabilityScore < availability.availabilityScore;
195 }
196 }
197
198 /**
199 * @return a least squares approximation of the increase in memory over the given time period,
200 * in mebibytes/second
201 */
202 public static double leastSquareMemory(
203 Iterator<? extends IItem> items, IMemberAccessor<IQuantity, IItem> timeField,
204 IMemberAccessor<IQuantity, IItem> memField) {
205 double sumX = 0;
206 double sumY = 0;
207 double sumX2 = 0;
208 double sumXY = 0;
209 double num = 0;
210 double startTime = 0;
211
212 while (items.hasNext()) {
213 IItem item = items.next();
214 long time = timeField.getMember(item).clampedLongValueIn(UnitLookup.EPOCH_S);
215 long mem = memField.getMember(item).clampedLongValueIn(MEBIBYTES);
400 * the collection to check.
401 * @param typeIds
402 * the identifiers for the event types to check.
403 * @return true if all of the required event types were known to be explicitly enabled.
404 */
405 public static boolean isEventsEnabled(IItemCollection items, String ... typeIds) {
406 IQuantity aggregate = items.apply(createEnablementFilter(true, typeIds)).getAggregate(Aggregators.count());
407 return aggregate != null && aggregate.longValue() == typeIds.length;
408 }
409
410 /**
411 * This method returns false if any {@link EventAvailability} is disabled or unavailable.
412 * Otherwise true.
413 *
414 * @param eventAvailabilities
415 * the {@link EventAvailability} to check
416 * @return false if any {@link EventAvailability} is disabled or unavailable. Otherwise true.
417 */
418 public static boolean isEventsEnabled(EventAvailability ... eventAvailabilities) {
419 for (EventAvailability availability : eventAvailabilities) {
420 if (availability == EventAvailability.DISABLED || availability == EventAvailability.UNKNOWN) {
421 return false;
422 }
423 }
424 return true;
425 }
426
427 /**
428 * This method checks if the provided event types were explicitly disabled by checking the
429 * recording setting events.
430 *
431 * @param items
432 * the collection to check.
433 * @param typeIds
434 * the identifiers for the event types to check.
435 * @return true if all of the required event types were known to be explicitly enabled.
436 */
437 private static boolean isEventsDisabled(IItemCollection items, String ... typeIds) {
438 IQuantity aggregate = items.apply(createEnablementFilter(false, typeIds)).getAggregate(Aggregators.count());
439 return aggregate != null && aggregate.longValue() == typeIds.length;
440 }
450 * the collection to check
451 * @param typeIds
452 * the type identifiers to check
453 * @return the availability for the event types
454 */
455 public static EventAvailability getEventAvailability(IItemCollection items, final String ... typeIds) {
456 // Only AVAILABLE if exactly all types have events
457 if (hasEvents(items, typeIds)) {
458 return EventAvailability.AVAILABLE;
459 }
460 // If enabled at any point, it was indeed enabled, and events could have been recorded
461 if (isEventsEnabled(items, typeIds)) {
462 return EventAvailability.ENABLED;
463 }
464 if (isEventsDisabled(items, typeIds)) {
465 return EventAvailability.DISABLED;
466 }
467 if (isEventsKnown(items, typeIds)) {
468 return EventAvailability.NONE;
469 }
470 return EventAvailability.UNKNOWN;
471 }
472
473 /**
474 * Returns the lowest availability from the ones provided. See {@link EventAvailability}.
475 */
476 public static EventAvailability getLeastAvailable(EventAvailability ... availabilites) {
477 EventAvailability lowest = EventAvailability.AVAILABLE;
478
479 for (EventAvailability availability : availabilites) {
480 if (availability.isLessAvailableThan(lowest)) {
481 lowest = availability;
482 }
483 }
484 return lowest;
485 }
486
487 /**
488 * Checks if the event types are known in the collection. Note that it does not necessarily mean
489 * that there are events of the event type.
490 *
491 * @param items
492 * the collection to check
493 * @param typeIds
494 * the event types to check
495 * @return true if all the event types exists in the collection.
496 */
497 private static boolean isEventsKnown(IItemCollection items, String ... typeIds) {
498 Set<String> availableTypes = getAvailableTypeIds(items);
499 if (availableTypes.containsAll(Arrays.asList(typeIds))) {
500 return true;
501 }
502 return false;
503 }
504
536 * @return the result for the provided availability problem
537 */
538 public static Result getEventAvailabilityResult(
539 IRule rule, IItemCollection items, EventAvailability eventAvailability, String ... typeIds) {
540 switch (eventAvailability) {
541 case ENABLED:
542 case NONE:
543 String requiredEventsTypeNames = getEventTypeNames(items, typeIds);
544 return getNotApplicableResult(rule,
545 MessageFormat.format(Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_EVENTS),
546 requiredEventsTypeNames),
547 MessageFormat.format(Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_EVENTS_LONG),
548 rule.getName(), requiredEventsTypeNames));
549 case DISABLED:
550 String disabledEventTypeNames = getDisabledEventTypeNames(items, typeIds);
551 return getNotApplicableResult(rule,
552 MessageFormat.format(Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_EVENT_TYPE),
553 disabledEventTypeNames),
554 MessageFormat.format(Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_EVENT_TYPE_LONG),
555 rule.getName(), disabledEventTypeNames));
556 case UNKNOWN:
557 // Can't get type names if the event type is unavailable
558 List<String> quotedTypeIds = new ArrayList<>();
559 for (String typeId : typeIds) {
560 quotedTypeIds.add("'" + typeId + "'"); //$NON-NLS-1$ //$NON-NLS-2$
561 }
562 Collections.sort(quotedTypeIds);
563 String unavailableTypeNames = StringToolkit.join(quotedTypeIds, ", "); //$NON-NLS-1$
564 return getNotApplicableResult(rule,
565 MessageFormat.format(Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_UNAVAILABLE_EVENT_TYPE),
566 rule.getName(), unavailableTypeNames),
567 MessageFormat.format(
568 Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_UNAVAILABLE_EVENT_TYPE_LONG),
569 rule.getName(), unavailableTypeNames));
570 case AVAILABLE:
571 String availableEventTypeNames = getEventTypeNames(items, typeIds);
572 return getNotApplicableResult(rule,
573 MessageFormat.format(
574 Messages.getString(Messages.RulesToolkit_RULE_REQUIRES_EVENT_TYPE_NOT_AVAILABLE),
575 availableEventTypeNames),
576 MessageFormat.format(Messages.RulesToolkit_RULE_REQUIRES_EVENT_TYPE_NOT_AVAILABLE_LONG,
|