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.io.PrintStream;
23  import java.util.Collections;
24  import java.util.Iterator;
25  
26  import org.apache.maven.surefire.util.CloseableIterator;
27  import org.apache.maven.surefire.util.TestsToRun;
28  
29  import static org.apache.maven.surefire.booter.CommandReader.getReader;
30  import static org.apache.maven.surefire.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 org.apache.maven.surefire.providerapi.SurefireProvider provider implementation}.
40   *
41   * @author Andreas Gudian
42   * @author Tibor Digana
43   */
44  final class LazyTestsToRun
45      extends TestsToRun
46  {
47      private final PrintStream originalOutStream;
48  
49      /**
50       * C'tor
51       *
52       * @param originalOutStream the output stream to use when requesting new new tests
53       */
54      LazyTestsToRun( PrintStream originalOutStream )
55      {
56          super( Collections.<Class<?>>emptySet() );
57  
58          this.originalOutStream = originalOutStream;
59      }
60  
61      private final class BlockingIterator
62          implements Iterator<Class<?>>
63      {
64          private final Iterator<String> it = getReader().getIterableClasses( originalOutStream ).iterator();
65  
66          public boolean hasNext()
67          {
68              return it.hasNext();
69          }
70  
71          public Class<?> next()
72          {
73              return findClass( it.next() );
74          }
75  
76          public void remove()
77          {
78              throw new UnsupportedOperationException();
79          }
80      }
81  
82      /**
83       * @return test classes which have been retrieved by {@link LazyTestsToRun#iterator()}.
84       */
85      @Override
86      public Iterator<Class<?>> iterated()
87      {
88          return newWeakIterator();
89      }
90  
91      /**
92       * The iterator can be used only in one Thread.
93       * {@inheritDoc}
94       * @see org.apache.maven.surefire.util.TestsToRun#iterator()
95       * */
96      public Iterator<Class<?>> iterator()
97      {
98          return new BlockingIterator();
99      }
100 
101     /* (non-Javadoc)
102      * {@inheritDoc}
103       * @see org.apache.maven.surefire.util.TestsToRun#toString()
104       */
105     public String toString()
106     {
107         return "LazyTestsToRun";
108     }
109 
110     /* (non-Javadoc)
111      * {@inheritDoc}
112      * @see org.apache.maven.surefire.util.TestsToRun#allowEagerReading()
113      */
114     public boolean allowEagerReading()
115     {
116         return false;
117     }
118 
119     private static Class<?> findClass( String clazz )
120     {
121         return loadClass( Thread.currentThread().getContextClassLoader(), clazz );
122     }
123 
124     /**
125      * @return snapshot of tests upon constructs of {@link CommandReader#iterated() iterator}.
126      * Therefore weakly consistent while {@link LazyTestsToRun#iterator()} is being iterated.
127      */
128     private Iterator<Class<?>> newWeakIterator()
129     {
130         final Iterator<String> it = getReader().iterated();
131         return new CloseableIterator<Class<?>>()
132         {
133             @Override
134             protected boolean isClosed()
135             {
136                 return LazyTestsToRun.this.isFinished();
137             }
138 
139             @Override
140             protected boolean doHasNext()
141             {
142                 return it.hasNext();
143             }
144 
145             @Override
146             protected Class<?> doNext()
147             {
148                 return findClass( it.next() );
149             }
150 
151             @Override
152             protected void doRemove()
153             {
154             }
155 
156             public void remove()
157             {
158                 throw new UnsupportedOperationException( "unsupported remove" );
159             }
160         };
161     }
162 }