3
3
import static java .util .Arrays .asList ;
4
4
5
5
import java .util .ArrayList ;
6
- import java .util .Collections ;
7
- import java .util .Iterator ;
6
+ import java .util .Collection ;
8
7
import java .util .List ;
8
+ import java .util .concurrent .CopyOnWriteArrayList ;
9
9
10
10
import org .junit .internal .AssumptionViolatedException ;
11
11
import org .junit .runner .Description ;
21
21
* @since 4.0
22
22
*/
23
23
public class RunNotifier {
24
- private final List <RunListener > fListeners =
25
- Collections .synchronizedList (new ArrayList <RunListener >());
24
+ private final List <RunListener > fListeners = new CopyOnWriteArrayList <RunListener >();
26
25
private volatile boolean fPleaseStop = false ;
27
26
28
27
/**
29
28
* Internal use only
30
29
*/
31
30
public void addListener (RunListener listener ) {
32
- fListeners .add (listener );
31
+ if (listener == null ) {
32
+ throw new NullPointerException ("Cannot add a null listener" );
33
+ }
34
+ fListeners .add (wrapIfNotThreadSafe (listener ));
33
35
}
34
36
35
37
/**
36
38
* Internal use only
37
39
*/
38
40
public void removeListener (RunListener listener ) {
39
- fListeners .remove (listener );
41
+ if (listener == null ) {
42
+ throw new NullPointerException ("Cannot remove a null listener" );
43
+ }
44
+ fListeners .remove (wrapIfNotThreadSafe (listener ));
45
+ }
46
+
47
+ /**
48
+ * Wraps the given listener with {@link SynchronizedRunListener} if
49
+ * it is not annotated with {@link RunListener.ThreadSafe}.
50
+ */
51
+ RunListener wrapIfNotThreadSafe (RunListener listener ) {
52
+ return listener .getClass ().isAnnotationPresent (RunListener .ThreadSafe .class ) ?
53
+ listener : new SynchronizedRunListener (listener , this );
40
54
}
41
55
56
+
42
57
private abstract class SafeNotifier {
43
58
private final List <RunListener > fCurrentListeners ;
44
59
@@ -51,21 +66,18 @@ private abstract class SafeNotifier {
51
66
}
52
67
53
68
void run () {
54
- synchronized (fListeners ) {
55
- List <RunListener > safeListeners = new ArrayList <RunListener >();
56
- List <Failure > failures = new ArrayList <Failure >();
57
- for (Iterator <RunListener > all = fCurrentListeners .iterator (); all
58
- .hasNext (); ) {
59
- try {
60
- RunListener listener = all .next ();
61
- notifyListener (listener );
62
- safeListeners .add (listener );
63
- } catch (Exception e ) {
64
- failures .add (new Failure (Description .TEST_MECHANISM , e ));
65
- }
69
+ int capacity = fCurrentListeners .size ();
70
+ ArrayList <RunListener > safeListeners = new ArrayList <RunListener >(capacity );
71
+ ArrayList <Failure > failures = new ArrayList <Failure >(capacity );
72
+ for (RunListener listener : fCurrentListeners ) {
73
+ try {
74
+ notifyListener (listener );
75
+ safeListeners .add (listener );
76
+ } catch (Exception e ) {
77
+ failures .add (new Failure (Description .TEST_MECHANISM , e ));
66
78
}
67
- fireTestFailures (safeListeners , failures );
68
79
}
80
+ fireTestFailures (safeListeners , failures );
69
81
}
70
82
71
83
abstract protected void notifyListener (RunListener each ) throws Exception ;
@@ -80,8 +92,6 @@ public void fireTestRunStarted(final Description description) {
80
92
protected void notifyListener (RunListener each ) throws Exception {
81
93
each .testRunStarted (description );
82
94
}
83
-
84
- ;
85
95
}.run ();
86
96
}
87
97
@@ -94,8 +104,6 @@ public void fireTestRunFinished(final Result result) {
94
104
protected void notifyListener (RunListener each ) throws Exception {
95
105
each .testRunFinished (result );
96
106
}
97
-
98
- ;
99
107
}.run ();
100
108
}
101
109
@@ -114,8 +122,6 @@ public void fireTestStarted(final Description description) throws StoppedByUserE
114
122
protected void notifyListener (RunListener each ) throws Exception {
115
123
each .testStarted (description );
116
124
}
117
-
118
- ;
119
125
}.run ();
120
126
}
121
127
@@ -133,14 +139,11 @@ private void fireTestFailures(List<RunListener> listeners,
133
139
if (!failures .isEmpty ()) {
134
140
new SafeNotifier (listeners ) {
135
141
@ Override
136
- protected void notifyListener (RunListener listener )
137
- throws Exception {
142
+ protected void notifyListener (RunListener listener ) throws Exception {
138
143
for (Failure each : failures ) {
139
144
listener .testFailure (each );
140
145
}
141
146
}
142
-
143
- ;
144
147
}.run ();
145
148
}
146
149
}
@@ -158,8 +161,6 @@ public void fireTestAssumptionFailed(final Failure failure) {
158
161
protected void notifyListener (RunListener each ) throws Exception {
159
162
each .testAssumptionFailure (failure );
160
163
}
161
-
162
- ;
163
164
}.run ();
164
165
}
165
166
@@ -190,8 +191,6 @@ public void fireTestFinished(final Description description) {
190
191
protected void notifyListener (RunListener each ) throws Exception {
191
192
each .testFinished (description );
192
193
}
193
-
194
- ;
195
194
}.run ();
196
195
}
197
196
@@ -209,6 +208,9 @@ public void pleaseStop() {
209
208
* Internal use only. The Result's listener must be first.
210
209
*/
211
210
public void addFirstListener (RunListener listener ) {
212
- fListeners .add (0 , listener );
211
+ if (listener == null ) {
212
+ throw new NullPointerException ("Cannot add a null listener" );
213
+ }
214
+ fListeners .add (0 , wrapIfNotThreadSafe (listener ));
213
215
}
214
- }
216
+ }
0 commit comments