View Javadoc
1   package org.apache.maven.surefire.booter;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Collections;
23  import java.util.Iterator;
24  
25  import org.apache.maven.surefire.api.booter.MasterProcessChannelEncoder;
26  import org.apache.maven.surefire.api.provider.SurefireProvider;
27  import org.apache.maven.surefire.api.util.CloseableIterator;
28  import org.apache.maven.surefire.api.util.TestsToRun;
29  
30  import static org.apache.maven.surefire.api.util.ReflectionUtils.loadClass;
31  
32  /**
33   * A variant of TestsToRun that is provided with test class names
34   * from an {@code System.in}.
35   * The method {@link #iterator()} returns an Iterator that blocks on calls to
36   * {@link Iterator#hasNext()} or {@link Iterator#next()} until new classes are available, or no more
37   * classes will be available or the internal stream is closed.
38   * The iterator can be used only in one Thread and it is the thread which executes
39   * {@link SurefireProvider provider implementation}.
40   *
41   * @author Andreas Gudian
42   * @author Tibor Digana
43   */
44  final class LazyTestsToRun
45      extends TestsToRun
46  {
47      private final MasterProcessChannelEncoder eventChannel;
48      private final CommandReader commandReader;
49  
50      /**
51       * C'tor
52       *
53       * @param eventChannel the output stream to use when requesting new new tests
54       */
55      LazyTestsToRun( MasterProcessChannelEncoder eventChannel, CommandReader commandReader )
56      {
57          super( Collections.<Class<?>>emptySet() );
58          this.eventChannel = eventChannel;
59          this.commandReader = commandReader;
60      }
61  
62      private final class BlockingIterator
63          implements Iterator<Class<?>>
64      {
65          private final Iterator<String> it = commandReader.getIterableClasses( eventChannel ).iterator();
66  
67          @Override
68          public boolean hasNext()
69          {
70              return it.hasNext();
71          }
72  
73          @Override
74          public Class<?> next()
75          {
76              return findClass( it.next() );
77          }
78  
79          @Override
80          public void remove()
81          {
82              throw new UnsupportedOperationException();
83          }
84      }
85  
86      /**
87       * @return test classes which have been retrieved by {@link LazyTestsToRun#iterator()}.
88       */
89      @Override
90      public Iterator<Class<?>> iterated()
91      {
92          return newWeakIterator();
93      }
94  
95      /**
96       * The iterator can be used only in one Thread.
97       * {@inheritDoc}
98       * @see TestsToRun#iterator()
99       * */
100     @Override
101     public Iterator<Class<?>> iterator()
102     {
103         return new BlockingIterator();
104     }
105 
106     /* (non-Javadoc)
107      * {@inheritDoc}
108       * @see org.apache.maven.surefire.util.TestsToRun#toString()
109       */
110     @Override
111     public String toString()
112     {
113         return "LazyTestsToRun";
114     }
115 
116     /* (non-Javadoc)
117      * {@inheritDoc}
118      * @see org.apache.maven.surefire.util.TestsToRun#allowEagerReading()
119      */
120     @Override
121     public boolean allowEagerReading()
122     {
123         return false;
124     }
125 
126     private static Class<?> findClass( String clazz )
127     {
128         return loadClass( Thread.currentThread().getContextClassLoader(), clazz );
129     }
130 
131     /**
132      * @return snapshot of tests upon constructs of {@link CommandReader#iterated() iterator}.
133      * Therefore weakly consistent while {@link LazyTestsToRun#iterator()} is being iterated.
134      */
135     private Iterator<Class<?>> newWeakIterator()
136     {
137         final Iterator<String> it = commandReader.iterated();
138         return new CloseableIterator<Class<?>>()
139         {
140             @Override
141             protected boolean isClosed()
142             {
143                 return LazyTestsToRun.this.isFinished();
144             }
145 
146             @Override
147             protected boolean doHasNext()
148             {
149                 return it.hasNext();
150             }
151 
152             @Override
153             protected Class<?> doNext()
154             {
155                 return findClass( it.next() );
156             }
157 
158             @Override
159             protected void doRemove()
160             {
161             }
162 
163             @Override
164             public void remove()
165             {
166                 throw new UnsupportedOperationException( "unsupported remove" );
167             }
168         };
169     }
170 }