View Javadoc
1   package org.wikimedia.search.extra.superdetectnoop;
2   
3   import static java.lang.Math.abs;
4   import static org.wikimedia.search.extra.superdetectnoop.ChangeHandler.TypeSafe.nullAndTypeSafe;
5   
6   import javax.annotation.Nonnull;
7   
8   /**
9    * Checks if a number is different by some percentage.
10   */
11  public class WithinPercentageHandler implements ChangeHandler.NonnullChangeHandler<Number> {
12      public static class Recognizer implements ChangeHandler.Recognizer {
13          private static final String PREFIX = "within ";
14          private static final String SUFFIX = "%";
15  
16          @Override
17          public ChangeHandler<Object> build(String description) {
18              if (!description.startsWith(PREFIX)) {
19                  return null;
20              }
21              if (!description.endsWith(SUFFIX)) {
22                  return null;
23              }
24              try {
25                  double percentage = Double.parseDouble(description.substring(PREFIX.length(), description.length() - SUFFIX.length()));
26                  return nullAndTypeSafe(Number.class, new WithinPercentageHandler(percentage / 100));
27              } catch (NumberFormatException e) {
28                  // Not a valid number even with the % sign....
29                  return null;
30              }
31          }
32      }
33  
34      private final double absoluteDifference;
35  
36      public WithinPercentageHandler(double absoluteDifference) {
37          this.absoluteDifference = absoluteDifference;
38      }
39  
40      @Override
41      public ChangeHandler.Result handle(@Nonnull Number oldValue, @Nonnull Number newValue) {
42          if (oldValue.doubleValue() == 0) {
43              return ChangeHandler.Changed.forBoolean(newValue.doubleValue() == 0, newValue);
44          }
45          return ChangeHandler.Changed.forBoolean(
46                  abs((newValue.doubleValue() - oldValue.doubleValue()) / oldValue.doubleValue()) < absoluteDifference, newValue);
47      }
48  }