17
17
18
18
import com .arpnetworking .utility .InterfaceDatabase ;
19
19
import com .arpnetworking .utility .ReflectionsDatabase ;
20
- import com .google .common .collect .ImmutableMap ;
21
- import com .google .common .collect .ImmutableSet ;
22
20
import com .google .common .collect .Maps ;
23
- import com .google .common .collect .Sets ;
24
21
import org .slf4j .Logger ;
25
22
import org .slf4j .LoggerFactory ;
26
23
27
24
import java .lang .reflect .Constructor ;
28
25
import java .lang .reflect .InvocationTargetException ;
29
26
import java .lang .reflect .Modifier ;
30
- import java .util .Map ;
31
27
import java .util .Optional ;
32
28
import java .util .Set ;
29
+ import java .util .concurrent .ConcurrentMap ;
30
+ import java .util .regex .Matcher ;
31
+ import java .util .regex .Pattern ;
33
32
34
33
/**
35
34
* Creates statistics.
@@ -60,31 +59,36 @@ public Statistic getStatistic(final String name) {
60
59
* @return A new <code>Statistic</code>.
61
60
*/
62
61
public Optional <Statistic > tryGetStatistic (final String name ) {
63
- return Optional .ofNullable (STATISTICS_BY_NAME_AND_ALIAS .get (name ));
64
- }
65
-
66
- /**
67
- * Get all registered <code>Statistic</code> instances.
68
- *
69
- * @return A new <code>Statistic</code>.
70
- */
71
- public ImmutableSet <Statistic > getAllStatistics () {
72
- return ALL_STATISTICS ;
62
+ final Optional <Statistic > registeredStatistic =
63
+ Optional .ofNullable (STATISTICS_BY_NAME_AND_ALIAS .get (name ));
64
+ if (!registeredStatistic .isPresent ()) {
65
+ final Matcher matcher = PERCENTILE_STATISTIC_PATTERN .matcher (name );
66
+ if (matcher .matches ()) {
67
+ try {
68
+ final String percentileString = matcher .group ("percentile" ).replace ('p' , '.' );
69
+ final double percentile = Double .parseDouble (percentileString );
70
+ final Statistic statistic = new TPStatistic (percentile );
71
+ checkedPut (STATISTICS_BY_NAME_AND_ALIAS , statistic );
72
+ return Optional .of (statistic );
73
+ } catch (final NumberFormatException e ) {
74
+ LOGGER .error (String .format (
75
+ "Invalid percentile statistic; name=%s" ,
76
+ name ));
77
+ return registeredStatistic ;
78
+ }
79
+ }
80
+ }
81
+ return registeredStatistic ;
73
82
}
74
83
75
- /**
76
- * Creates a statistic from a name.
77
- *
78
- * @param statistic The name of the desired statistic.
79
- * @return A new <code>Statistic</code>.
80
- * @deprecated Use <code>getStatistic</code> instead.
81
- */
82
- @ Deprecated
83
- public Optional <Statistic > createStatistic (final String statistic ) {
84
- return Optional .ofNullable (STATISTICS_BY_NAME_AND_ALIAS .get (statistic ));
84
+ private static void checkedPut (final ConcurrentMap <String , Statistic > map , final Statistic statistic ) {
85
+ checkedPut (map , statistic , statistic .getName ());
86
+ for (final String alias : statistic .getAliases ()) {
87
+ checkedPut (map , statistic , alias );
88
+ }
85
89
}
86
90
87
- private static void checkedPut (final Map <String , Statistic > map , final Statistic statistic , final String key ) {
91
+ private static void checkedPut (final ConcurrentMap <String , Statistic > map , final Statistic statistic , final String key ) {
88
92
final Statistic existingStatistic = map .get (key );
89
93
if (existingStatistic != null ) {
90
94
if (!existingStatistic .equals (statistic )) {
@@ -99,15 +103,14 @@ private static void checkedPut(final Map<String, Statistic> map, final Statistic
99
103
map .put (key , statistic );
100
104
}
101
105
102
- private static final ImmutableMap < String , Statistic > STATISTICS_BY_NAME_AND_ALIAS ;
103
- private static final ImmutableSet < Statistic > ALL_STATISTICS ;
106
+ private static final Pattern PERCENTILE_STATISTIC_PATTERN = Pattern . compile ( "^[t]?p(?<percentile>[0-9]+(?:( \\ .|p)[0-9]+)?)$" ) ;
107
+ private static final ConcurrentMap < String , Statistic > STATISTICS_BY_NAME_AND_ALIAS ;
104
108
private static final InterfaceDatabase INTERFACE_DATABASE = ReflectionsDatabase .newInstance ();
105
109
private static final Logger LOGGER = LoggerFactory .getLogger (StatisticFactory .class );
106
110
107
111
static {
108
112
// NOTE: Do not put log messages in static blocks since they can lock the logger thread!
109
- final Map <String , Statistic > statisticByNameAndAlias = Maps .newHashMap ();
110
- final Set <Statistic > allStatistics = Sets .newHashSet ();
113
+ final ConcurrentMap <String , Statistic > statisticByNameAndAlias = Maps .newConcurrentMap ();
111
114
final Set <Class <? extends Statistic >> statisticClasses = INTERFACE_DATABASE .findClassesWithInterface (Statistic .class );
112
115
for (final Class <? extends Statistic > statisticClass : statisticClasses ) {
113
116
if (!statisticClass .isInterface () && !Modifier .isAbstract (statisticClass .getModifiers ())) {
@@ -116,19 +119,13 @@ private static void checkedPut(final Map<String, Statistic> map, final Statistic
116
119
if (!constructor .isAccessible ()) {
117
120
constructor .setAccessible (true );
118
121
}
119
- final Statistic statistic = constructor .newInstance ();
120
- allStatistics .add (statistic );
121
- checkedPut (statisticByNameAndAlias , statistic , statistic .getName ());
122
- for (final String alias : statistic .getAliases ()) {
123
- checkedPut (statisticByNameAndAlias , statistic , alias );
124
- }
122
+ checkedPut (statisticByNameAndAlias , constructor .newInstance ());
125
123
} catch (final InvocationTargetException | NoSuchMethodException
126
124
| InstantiationException | IllegalAccessException e ) {
127
125
LOGGER .warn (String .format ("Unable to load statistic; class=%s" , statisticClass ), e );
128
126
}
129
127
}
130
128
}
131
- STATISTICS_BY_NAME_AND_ALIAS = ImmutableMap .copyOf (statisticByNameAndAlias );
132
- ALL_STATISTICS = ImmutableSet .copyOf (allStatistics );
129
+ STATISTICS_BY_NAME_AND_ALIAS = statisticByNameAndAlias ;
133
130
}
134
131
}
0 commit comments