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.surefire.booter;
20  
21  import java.util.Collections;
22  import java.util.Iterator;
23  
24  import org.apache.maven.surefire.api.booter.MasterProcessChannelEncoder;
25  import org.apache.maven.surefire.api.provider.SurefireProvider;
26  import org.apache.maven.surefire.api.util.CloseableIterator;
27  import org.apache.maven.surefire.api.util.TestsToRun;
28  
29  import static org.apache.maven.surefire.api.util.ReflectionUtils.loadClass;
30  
31  /**
32   * A variant of TestsToRun that is provided with test class names
33   * from an {@code System.in}.
34   * The method {@link #iterator()} returns an Iterator that blocks on calls to
35   * {@link Iterator#hasNext()} or {@link Iterator#next()} until new classes are available, or no more
36   * classes will be available or the internal stream is closed.
37   * The iterator can be used only in one Thread and it is the thread which executes
38   * {@link SurefireProvider provider implementation}.
39   *
40   * @author Andreas Gudian
41   * @author Tibor Digana
42   */
43  final class LazyTestsToRun extends TestsToRun {
44      private final MasterProcessChannelEncoder eventChannel;
45      private final CommandReader commandReader;
46  
47      /**
48       * C'tor
49       *
50       * @param eventChannel the output stream to use when requesting new new tests
51       */
52      LazyTestsToRun(MasterProcessChannelEncoder eventChannel, CommandReader commandReader) {
53          super(Collections.<Class<?>>emptySet());
54          this.eventChannel = eventChannel;
55          this.commandReader = commandReader;
56      }
57  
58      private final class BlockingIterator implements Iterator<Class<?>> {
59          private final Iterator<String> it =
60                  commandReader.getIterableClasses(eventChannel).iterator();
61  
62          @Override
63          public boolean hasNext() {
64              return it.hasNext();
65          }
66  
67          @Override
68          public Class<?> next() {
69              return findClass(it.next());
70          }
71  
72          @Override
73          public void remove() {
74              throw new UnsupportedOperationException();
75          }
76      }
77  
78      /**
79       * @return test classes which have been retrieved by {@link LazyTestsToRun#iterator()}.
80       */
81      @Override
82      public Iterator<Class<?>> iterated() {
83          return newWeakIterator();
84      }
85  
86      /**
87       * The iterator can be used only in one Thread.
88       * {@inheritDoc}
89       * @see TestsToRun#iterator()
90       * */
91      @Override
92      public Iterator<Class<?>> iterator() {
93          return new BlockingIterator();
94      }
95  
96      /* (non-Javadoc)
97       * {@inheritDoc}
98       * @see org.apache.maven.surefire.util.TestsToRun#toString()
99       */
100     @Override
101     public String toString() {
102         return "LazyTestsToRun";
103     }
104 
105     /* (non-Javadoc)
106      * {@inheritDoc}
107      * @see org.apache.maven.surefire.util.TestsToRun#allowEagerReading()
108      */
109     @Override
110     public boolean allowEagerReading() {
111         return false;
112     }
113 
114     private static Class<?> findClass(String clazz) {
115         return loadClass(Thread.currentThread().getContextClassLoader(), clazz);
116     }
117 
118     /**
119      * @return snapshot of tests upon constructs of {@link CommandReader#iterated() iterator}.
120      * Therefore weakly consistent while {@link LazyTestsToRun#iterator()} is being iterated.
121      */
122     private Iterator<Class<?>> newWeakIterator() {
123         final Iterator<String> it = commandReader.iterated();
124         return new CloseableIterator<Class<?>>() {
125             @Override
126             protected boolean isClosed() {
127                 return LazyTestsToRun.this.isFinished();
128             }
129 
130             @Override
131             protected boolean doHasNext() {
132                 return it.hasNext();
133             }
134 
135             @Override
136             protected Class<?> doNext() {
137                 return findClass(it.next());
138             }
139 
140             @Override
141             protected void doRemove() {}
142 
143             @Override
144             public void remove() {
145                 throw new UnsupportedOperationException("unsupported remove");
146             }
147         };
148     }
149 }