View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugin.surefire.booterclient.output;
20  
21  import java.util.concurrent.ConcurrentHashMap;
22  import java.util.concurrent.ConcurrentMap;
23  
24  import org.apache.maven.surefire.api.booter.ForkedProcessEventType;
25  import org.apache.maven.surefire.api.event.AbstractConsoleEvent;
26  import org.apache.maven.surefire.api.event.AbstractStandardStreamEvent;
27  import org.apache.maven.surefire.api.event.AbstractTestControlEvent;
28  import org.apache.maven.surefire.api.event.ConsoleErrorEvent;
29  import org.apache.maven.surefire.api.event.Event;
30  import org.apache.maven.surefire.api.event.JvmExitErrorEvent;
31  import org.apache.maven.surefire.api.event.SystemPropertyEvent;
32  import org.apache.maven.surefire.api.report.ReportEntry;
33  import org.apache.maven.surefire.api.report.RunMode;
34  
35  import static java.util.Objects.requireNonNull;
36  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_BYE;
37  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_DEBUG;
38  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_INFO;
39  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_CONSOLE_WARNING;
40  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_NEXT_TEST;
41  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDERR;
42  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDERR_NEW_LINE;
43  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDOUT;
44  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STDOUT_NEW_LINE;
45  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_STOP_ON_NEXT_TEST;
46  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_COMPLETED;
47  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TESTSET_STARTING;
48  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_ASSUMPTIONFAILURE;
49  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_ERROR;
50  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_FAILED;
51  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SKIPPED;
52  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_STARTING;
53  import static org.apache.maven.surefire.api.booter.ForkedProcessEventType.BOOTERCODE_TEST_SUCCEEDED;
54  
55  /**
56   * magic number : run mode : opcode [: opcode specific data]*
57   *
58   * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
59   * @since 3.0.0-M4
60   */
61  public final class ForkedProcessEventNotifier {
62      private volatile ForkedProcessPropertyEventListener propertyEventListener;
63      private volatile ForkedProcessStackTraceEventListener consoleErrorEventListener;
64      private volatile ForkedProcessExitErrorListener exitErrorEventListener;
65  
66      private final ConcurrentMap<ForkedProcessEventType, ForkedProcessReportEventListener<?>> reportEventListeners =
67              new ConcurrentHashMap<>();
68  
69      private final ConcurrentMap<ForkedProcessEventType, ForkedProcessStandardOutErrEventListener>
70              stdOutErrEventListeners = new ConcurrentHashMap<>();
71  
72      private final ConcurrentMap<ForkedProcessEventType, ForkedProcessStringEventListener> consoleEventListeners =
73              new ConcurrentHashMap<>();
74  
75      private final ConcurrentMap<ForkedProcessEventType, ForkedProcessEventListener> controlEventListeners =
76              new ConcurrentHashMap<>();
77  
78      public void setSystemPropertiesListener(ForkedProcessPropertyEventListener listener) {
79          propertyEventListener = requireNonNull(listener);
80      }
81  
82      public <T extends ReportEntry> void setTestSetStartingListener(ForkedProcessReportEventListener<T> listener) {
83          reportEventListeners.put(BOOTERCODE_TESTSET_STARTING, requireNonNull(listener));
84      }
85  
86      public void setTestSetCompletedListener(ForkedProcessReportEventListener<?> listener) {
87          reportEventListeners.put(BOOTERCODE_TESTSET_COMPLETED, requireNonNull(listener));
88      }
89  
90      public void setTestStartingListener(ForkedProcessReportEventListener<?> listener) {
91          reportEventListeners.put(BOOTERCODE_TEST_STARTING, requireNonNull(listener));
92      }
93  
94      public void setTestSucceededListener(ForkedProcessReportEventListener<?> listener) {
95          reportEventListeners.put(BOOTERCODE_TEST_SUCCEEDED, requireNonNull(listener));
96      }
97  
98      public void setTestFailedListener(ForkedProcessReportEventListener<?> listener) {
99          reportEventListeners.put(BOOTERCODE_TEST_FAILED, requireNonNull(listener));
100     }
101 
102     public void setTestSkippedListener(ForkedProcessReportEventListener<?> listener) {
103         reportEventListeners.put(BOOTERCODE_TEST_SKIPPED, requireNonNull(listener));
104     }
105 
106     public void setTestErrorListener(ForkedProcessReportEventListener<?> listener) {
107         reportEventListeners.put(BOOTERCODE_TEST_ERROR, requireNonNull(listener));
108     }
109 
110     public void setTestAssumptionFailureListener(ForkedProcessReportEventListener<?> listener) {
111         reportEventListeners.put(BOOTERCODE_TEST_ASSUMPTIONFAILURE, requireNonNull(listener));
112     }
113 
114     public void setStdOutListener(ForkedProcessStandardOutErrEventListener listener) {
115         stdOutErrEventListeners.put(BOOTERCODE_STDOUT, requireNonNull(listener));
116         stdOutErrEventListeners.put(BOOTERCODE_STDOUT_NEW_LINE, requireNonNull(listener));
117     }
118 
119     public void setStdErrListener(ForkedProcessStandardOutErrEventListener listener) {
120         stdOutErrEventListeners.put(BOOTERCODE_STDERR, requireNonNull(listener));
121         stdOutErrEventListeners.put(BOOTERCODE_STDERR_NEW_LINE, requireNonNull(listener));
122     }
123 
124     public void setConsoleInfoListener(ForkedProcessStringEventListener listener) {
125         consoleEventListeners.put(BOOTERCODE_CONSOLE_INFO, requireNonNull(listener));
126     }
127 
128     public void setConsoleErrorListener(ForkedProcessStackTraceEventListener listener) {
129         consoleErrorEventListener = requireNonNull(listener);
130     }
131 
132     public void setConsoleDebugListener(ForkedProcessStringEventListener listener) {
133         consoleEventListeners.put(BOOTERCODE_CONSOLE_DEBUG, requireNonNull(listener));
134     }
135 
136     public void setConsoleWarningListener(ForkedProcessStringEventListener listener) {
137         consoleEventListeners.put(BOOTERCODE_CONSOLE_WARNING, requireNonNull(listener));
138     }
139 
140     public void setByeListener(ForkedProcessEventListener listener) {
141         controlEventListeners.put(BOOTERCODE_BYE, requireNonNull(listener));
142     }
143 
144     public void setStopOnNextTestListener(ForkedProcessEventListener listener) {
145         controlEventListeners.put(BOOTERCODE_STOP_ON_NEXT_TEST, requireNonNull(listener));
146     }
147 
148     public void setAcquireNextTestListener(ForkedProcessEventListener listener) {
149         controlEventListeners.put(BOOTERCODE_NEXT_TEST, requireNonNull(listener));
150     }
151 
152     public void setExitErrorEventListener(ForkedProcessExitErrorListener listener) {
153         exitErrorEventListener = requireNonNull(listener);
154     }
155 
156     public void notifyEvent(Event event) {
157         ForkedProcessEventType eventType = event.getEventType();
158         if (event.isControlCategory()) {
159             ForkedProcessEventListener listener = controlEventListeners.get(eventType);
160             if (listener != null) {
161                 listener.handle();
162             }
163         } else if (event.isConsoleErrorCategory()) {
164             if (consoleErrorEventListener != null) {
165                 consoleErrorEventListener.handle(((ConsoleErrorEvent) event).getStackTraceWriter());
166             }
167         } else if (event.isConsoleCategory()) {
168             ForkedProcessStringEventListener listener = consoleEventListeners.get(eventType);
169             if (listener != null) {
170                 listener.handle(((AbstractConsoleEvent) event).getMessage());
171             }
172         } else if (event.isStandardStreamCategory()) {
173             boolean newLine = eventType == BOOTERCODE_STDOUT_NEW_LINE || eventType == BOOTERCODE_STDERR_NEW_LINE;
174             AbstractStandardStreamEvent standardStreamEvent = (AbstractStandardStreamEvent) event;
175             ForkedProcessStandardOutErrEventListener listener = stdOutErrEventListeners.get(eventType);
176             if (listener != null) {
177                 listener.handle(
178                         standardStreamEvent.getMessage(),
179                         newLine,
180                         standardStreamEvent.getRunMode(),
181                         standardStreamEvent.getTestRunId());
182             }
183         } else if (event.isSysPropCategory()) {
184             SystemPropertyEvent systemPropertyEvent = (SystemPropertyEvent) event;
185             RunMode runMode = systemPropertyEvent.getRunMode();
186             Long testRunId = systemPropertyEvent.getTestRunId();
187             String key = systemPropertyEvent.getKey();
188             String value = systemPropertyEvent.getValue();
189             if (propertyEventListener != null) {
190                 propertyEventListener.handle(key, value, runMode, testRunId);
191             }
192         } else if (event.isTestCategory()) {
193             ForkedProcessReportEventListener listener = reportEventListeners.get(eventType);
194             AbstractTestControlEvent testControlEvent = (AbstractTestControlEvent) event;
195             ReportEntry reportEntry = testControlEvent.getReportEntry();
196             if (listener != null) {
197                 listener.handle(reportEntry);
198             }
199         } else if (event.isJvmExitError()) {
200             JvmExitErrorEvent jvmExitErrorEvent = (JvmExitErrorEvent) event;
201             if (exitErrorEventListener != null) {
202                 exitErrorEventListener.handle(jvmExitErrorEvent.getStackTraceWriter());
203             }
204         } else {
205             throw new IllegalArgumentException("Unknown event type " + eventType);
206         }
207     }
208 }