/*
* Copyright (C) 2011 Laurent Caillette
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.novelang.outfit.shell;
import java.util.List;
import java.util.concurrent.Semaphore;
import com.google.common.base.Predicate;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Lists.newLinkedList;
import static java.util.Arrays.asList;
/**
* Evaluates a stack of {@link Predicate}s against lines coming from process standard output.
* For each matching line, the {@link #semaphore} release one permits.
* In order to make releases happen in order, the semaphore must be fair.
* Each matched {@link Predicate} goes out of the stack. When the last {@link Predicate}
* evaluates to {@code true} the {@link #apply(String)} method returns true.
* <p>
* This class is not thread-safe as all calls to {@link #apply(String)} come from
* the thread watching the output stream.
*
* @author Laurent Caillette
*/
/*package*/ class TieredStartupSensor implements Predicate< String > {
private final Semaphore semaphore ;
private final int initialPredicateCount ;
private final List< Predicate< String > > predicates ;
/**
* Constructor.
*
* @param semaphore a non-null, fair {@code Semaphore}.
* @param predicates a non-null array containing at least one non-null element. Nulls are ignored.
*/
public TieredStartupSensor(
final Semaphore semaphore,
final Predicate< String >... predicates
) {
checkArgument( semaphore.isFair() ) ;
checkArgument( predicates.length > 0 ) ;
this.semaphore = semaphore ;
this.predicates = newLinkedList( filter( asList( predicates ), notNull() ) ) ;
this.initialPredicateCount = this.predicates.size() ;
checkArgument( this.initialPredicateCount > 0, "Got some null in %s" + asList( predicates ) ) ;
}
@Override
public boolean apply( final String line ) {
if( ! predicates.isEmpty() ) {
final Predicate< String > top = predicates.get( 0 ) ;
if( top.apply( line ) ) {
predicates.remove( 0 ) ;
semaphore.release( 1 ) ;
return true ;
}
}
return false ;
}
public int getInitialPredicateCount() {
return initialPredicateCount ;
}
}