1818import java .lang .reflect .InvocationTargetException ;
1919import java .lang .reflect .Method ;
2020import java .lang .reflect .Modifier ;
21- import java .util .Collections ;
22- import java .util .List ;
23- import java .util .Map ;
24- import java .util .Set ;
21+ import java .util .*;
2522
2623import static com .google .common .base .Preconditions .checkArgument ;
2724import static com .google .common .base .Preconditions .checkNotNull ;
@@ -77,8 +74,11 @@ public static void registerNewBaseData(final Class dataType) {
7774 //NOOP
7875 }
7976
80- private Pair <Class , HandlerExecutor > processMethod (final Method listener , final BaseMetric metric )
81- throws MetricPreparationException {
77+ private Pair <Class , HandlerExecutor > processMethod (
78+ final Method listener ,
79+ final BaseMetric metric ,
80+ final Stack <Class > includeStack
81+ ) throws MetricPreparationException {
8282 final Class <?>[] params = listener .getParameterTypes ();
8383
8484 //Listener methods always have 2 parameters
@@ -106,7 +106,10 @@ private Pair<Class, HandlerExecutor> processMethod(final Method listener, final
106106 }
107107
108108 if (listener .isAnnotationPresent (UsingProducer .class )) {
109- final ProducerMetric producer = loadProducer (listener .getAnnotation (UsingProducer .class ).value ());
109+ final ProducerMetric producer = loadProducer (
110+ listener .getAnnotation (UsingProducer .class ).value (),
111+ includeStack
112+ );
110113
111114 //Ensure the producer produces for the current scope
112115 if (!producer .getProduceScope ().equals (metric .getScope ())) {
@@ -131,7 +134,13 @@ private Pair<Class, HandlerExecutor> processMethod(final Method listener, final
131134 return new Pair <Class , HandlerExecutor >(params [1 ], new HandlerExecutor (listener , metric ));
132135 }
133136
134- private void registerMetricInternal (final BaseMetric metric ) throws MetricPreparationException {
137+ private void registerMetricInternal (final BaseMetric metric , final Stack <Class > includeStack )
138+ throws MetricPreparationException {
139+ if (includeStack .contains (metric .getClass ())) {
140+ throw new MetricPreparationException (String .format ("Cyclic producer requirements: %s" , includeStack ));
141+ }
142+ includeStack .push (metric .getClass ());
143+
135144 final List <Pair <Class , HandlerExecutor >> executors = Lists .newLinkedList ();
136145
137146 for (final MetricScope resultScope : metric .getResultScopes ()) {
@@ -143,7 +152,7 @@ private void registerMetricInternal(final BaseMetric metric) throws MetricPrepar
143152
144153 for (final Method m : metric .getClass ().getDeclaredMethods ()) {
145154 if (m .isAnnotationPresent (Subscribe .class )) {
146- executors .add (processMethod (m , metric ));
155+ executors .add (processMethod (m , metric , includeStack ));
147156 }
148157 }
149158
@@ -181,6 +190,8 @@ public Class apply(Pair<Class, HandlerExecutor> classHandlerExecutorPair) {
181190 "Unable to resolve data for metric, the required data might not have the same MetricScope"
182191 );
183192 }
193+
194+ includeStack .pop ();
184195 }
185196
186197 /**
@@ -196,7 +207,7 @@ public void registerMetric(final BaseMetric metric) throws MetricPreparationExce
196207 if (!(metric instanceof IsolatedMetric || metric instanceof SharedMetric )) {
197208 throw new MetricPreparationException ("A metric needs to be a subclass of IsolatedMetric or SharedMetric" );
198209 } else {
199- this .registerMetricInternal (metric );
210+ this .registerMetricInternal (metric , new Stack < Class >() );
200211 }
201212 }
202213
@@ -222,14 +233,17 @@ public String toString() {
222233 .toString ();
223234 }
224235
225- private ProducerMetric loadProducer (final Class <? extends ProducerMetric > producerClass ) throws MetricPreparationException {
236+ private ProducerMetric loadProducer (
237+ final Class <? extends ProducerMetric > producerClass ,
238+ final Stack <Class > includeStack
239+ ) throws MetricPreparationException {
226240 if (this .registeredProducers .containsKey (producerClass )) {
227241 return this .registeredProducers .get (producerClass );
228242 } else {
229243 logger .debug ("Creating new producer: {}" , producerClass );
230244 try {
231245 final ProducerMetric pm = producerClass .getConstructor ().newInstance ();
232- this .registerMetricInternal (pm );
246+ this .registerMetricInternal (pm , includeStack );
233247 this .addProducer (pm );
234248 return pm ;
235249 } catch (InvocationTargetException e ) {
0 commit comments