17
17
18
18
import com .arpnetworking .steno .Logger ;
19
19
import com .arpnetworking .steno .LoggerFactory ;
20
- import com .arpnetworking .utility .InterfaceDatabase ;
21
- import com .arpnetworking .utility .ReflectionsDatabase ;
22
- import com .google .common .collect .ImmutableMap ;
23
20
import com .google .common .collect .ImmutableSet ;
24
21
import com .google .common .collect .Maps ;
25
- import com .google .common .collect . Sets ;
22
+ import com .google .common .reflect . ClassPath ;
26
23
24
+ import java .io .IOException ;
27
25
import java .lang .reflect .Constructor ;
28
26
import java .lang .reflect .InvocationTargetException ;
29
27
import java .lang .reflect .Modifier ;
30
- import java .util .Map ;
31
28
import java .util .Optional ;
32
- import java .util .Set ;
29
+ import java .util .concurrent . ConcurrentMap ;
33
30
34
31
/**
35
32
* Creates statistics.
@@ -43,7 +40,7 @@ public class StatisticFactory {
43
40
* Get a statistic by name.
44
41
*
45
42
* @param name The name of the desired statistic.
46
- * @return A new <code> Statistic</code> .
43
+ * @return A new {@link Statistic} .
47
44
*/
48
45
public Statistic getStatistic (final String name ) {
49
46
final Optional <Statistic > statistic = tryGetStatistic (name );
@@ -63,77 +60,65 @@ public Optional<Statistic> tryGetStatistic(final String name) {
63
60
return Optional .ofNullable (STATISTICS_BY_NAME_AND_ALIAS .get (name ));
64
61
}
65
62
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 ;
73
- }
74
-
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 ));
63
+ private static void checkedPut (final ConcurrentMap <String , Statistic > map , final Statistic statistic ) {
64
+ checkedPut (map , statistic , statistic .getName ());
65
+ for (final String alias : statistic .getAliases ()) {
66
+ checkedPut (map , statistic , alias );
67
+ }
85
68
}
86
69
87
- private static void checkedPut (final Map <String , Statistic > map , final Statistic statistic , final String key ) {
70
+ private static void checkedPut (final ConcurrentMap <String , Statistic > map , final Statistic statistic , final String key ) {
88
71
final Statistic existingStatistic = map .get (key );
89
72
if (existingStatistic != null ) {
90
73
if (!existingStatistic .equals (statistic )) {
91
74
LOGGER .error ()
92
- .setMessage ("Statistic already registered" )
93
- .addData ("key" , key )
94
- .addData ("existing" , existingStatistic )
95
- .addData ("new" , statistic )
96
- .log ();
75
+ .setMessage ("Statistic already registered" )
76
+ .addData ("key" , key )
77
+ .addData ("existing" , existingStatistic )
78
+ .addData ("new" , statistic )
79
+ .log ();
97
80
}
98
81
return ;
99
82
}
100
83
map .put (key , statistic );
101
84
}
102
85
103
- private static final ImmutableMap <String , Statistic > STATISTICS_BY_NAME_AND_ALIAS ;
104
- private static final ImmutableSet <Statistic > ALL_STATISTICS ;
105
- private static final InterfaceDatabase INTERFACE_DATABASE = ReflectionsDatabase .newInstance ();
86
+ private static final ConcurrentMap <String , Statistic > STATISTICS_BY_NAME_AND_ALIAS ;
106
87
private static final Logger LOGGER = LoggerFactory .getLogger (StatisticFactory .class );
107
88
108
89
static {
109
90
// NOTE: Do not put log messages in static blocks since they can lock the logger thread!
110
- final Map <String , Statistic > statisticByNameAndAlias = Maps .newHashMap ();
111
- final Set <Statistic > allStatistics = Sets .newHashSet ();
112
- final Set <Class <? extends Statistic >> statisticClasses = INTERFACE_DATABASE .findClassesWithInterface (Statistic .class );
113
- for (final Class <? extends Statistic > statisticClass : statisticClasses ) {
114
- if (!statisticClass .isInterface () && !Modifier .isAbstract (statisticClass .getModifiers ())) {
115
- try {
116
- final Constructor <? extends Statistic > constructor = statisticClass .getDeclaredConstructor ();
117
- if (!constructor .isAccessible ()) {
118
- constructor .setAccessible (true );
119
- }
120
- final Statistic statistic = constructor .newInstance ();
121
- allStatistics .add (statistic );
122
- checkedPut (statisticByNameAndAlias , statistic , statistic .getName ());
123
- for (final String alias : statistic .getAliases ()) {
124
- checkedPut (statisticByNameAndAlias , statistic , alias );
91
+ final ConcurrentMap <String , Statistic > statisticByNameAndAlias = Maps .newConcurrentMap ();
92
+ try {
93
+ final ImmutableSet <ClassPath .ClassInfo > statisticClasses = ClassPath .from (StatisticFactory .class .getClassLoader ())
94
+ .getTopLevelClasses ("com.arpnetworking.tsdcore.statistics" );
95
+ for (final ClassPath .ClassInfo statisticClassInfo : statisticClasses ) {
96
+ final Class <?> statisticClass = statisticClassInfo .load ();
97
+ if (!statisticClass .isInterface () && !Modifier .isAbstract (statisticClass .getModifiers ())
98
+ && Statistic .class .isAssignableFrom (statisticClass )) {
99
+ try {
100
+ // The constructor type is implied by the assignability
101
+ // of the statisticClass to the Statistic interface
102
+ @ SuppressWarnings ("unchecked" )
103
+ final Constructor <? extends Statistic > constructor =
104
+ (Constructor <? extends Statistic >) statisticClass .getDeclaredConstructor ();
105
+ if (!constructor .isAccessible ()) {
106
+ constructor .setAccessible (true );
107
+ }
108
+ checkedPut (statisticByNameAndAlias , constructor .newInstance ());
109
+ } catch (final InvocationTargetException | NoSuchMethodException
110
+ | InstantiationException | IllegalAccessException e ) {
111
+ LOGGER .warn ()
112
+ .setMessage ("Unable to load statistic" )
113
+ .addData ("class" , statisticClass )
114
+ .setThrowable (e )
115
+ .log ();
125
116
}
126
- } catch (final InvocationTargetException | NoSuchMethodException
127
- | InstantiationException | IllegalAccessException e ) {
128
- LOGGER .warn ()
129
- .setMessage ("Unable to load statistic" )
130
- .addData ("class" , statisticClass )
131
- .setThrowable (e )
132
- .log ();
133
117
}
134
118
}
119
+ } catch (final IOException e ) {
120
+ throw new RuntimeException ("Statistic discovery failed" , e );
135
121
}
136
- STATISTICS_BY_NAME_AND_ALIAS = ImmutableMap .copyOf (statisticByNameAndAlias );
137
- ALL_STATISTICS = ImmutableSet .copyOf (allStatistics );
122
+ STATISTICS_BY_NAME_AND_ALIAS = statisticByNameAndAlias ;
138
123
}
139
124
}
0 commit comments