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       *
90       * @see TestsToRun#iterator()
91       */
92      @Override
93      public Iterator<Class<?>> iterator() {
94          return new BlockingIterator();
95      }
96  
97      /* (non-Javadoc)
98       * {@inheritDoc}
99       * @see org.apache.maven.surefire.util.TestsToRun#toString()
100      */
101     @Override
102     public String toString() {
103         return "LazyTestsToRun";
104     }
105 
106     /* (non-Javadoc)
107      * {@inheritDoc}
108      * @see org.apache.maven.surefire.util.TestsToRun#allowEagerReading()
109      */
110     @Override
111     public boolean allowEagerReading() {
112         return false;
113     }
114 
115     private static Class<?> findClass(String clazz) {
116         return loadClass(Thread.currentThread().getContextClassLoader(), clazz);
117     }
118 
119     /**
120      * @return snapshot of tests upon constructs of {@link CommandReader#iterated() iterator}.
121      * Therefore weakly consistent while {@link LazyTestsToRun#iterator()} is being iterated.
122      */
123     private Iterator<Class<?>> newWeakIterator() {
124         final Iterator<String> it = commandReader.iterated();
125         return new CloseableIterator<Class<?>>() {
126             @Override
127             protected boolean isClosed() {
128                 return LazyTestsToRun.this.isFinished();
129             }
130 
131             @Override
132             protected boolean doHasNext() {
133                 return it.hasNext();
134             }
135 
136             @Override
137             protected Class<?> doNext() {
138                 return findClass(it.next());
139             }
140 
141             @Override
142             protected void doRemove() {}
143 
144             @Override
145             public void remove() {
146                 throw new UnsupportedOperationException("unsupported remove");
147             }
148         };
149     }
150 }