/* * Copyright (c) 2007-2010 Concurrent, Inc. All Rights Reserved. * * Project and contact information: http://www.cascading.org/ * * This file is part of the Cascading project. * * Cascading is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Cascading 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 Cascading. If not, see <http://www.gnu.org/licenses/>. */ package cascading.pipe.cogroup; import java.util.Iterator; import cascading.tuple.Tuple; import org.apache.log4j.Logger; /** * Class InnerJoin will return an {@link Iterator} that will iterate over a given {@link Joiner} and return tuples that represent * and inner join of the CoGrouper internal grouped tuple collections. */ public class InnerJoin implements Joiner { /** Field LOG */ private static final Logger LOG = Logger.getLogger( InnerJoin.class ); public Iterator<Tuple> getIterator( GroupClosure closure ) { return new JoinIterator( closure ); } public int numJoins() { return -1; } protected static class JoinIterator implements Iterator<Tuple> { final GroupClosure closure; Iterator[] iterators; Comparable[] lastValues; public JoinIterator( GroupClosure closure ) { this.closure = closure; if( LOG.isDebugEnabled() ) LOG.debug( "cogrouped size: " + closure.size() ); init(); } protected void init() { iterators = new Iterator[closure.size()]; for( int i = 0; i < closure.size(); i++ ) iterators[ i ] = getIterator( i ); } protected Iterator getIterator( int i ) { return closure.getIterator( i ); } private Comparable[] initLastValues() { lastValues = new Comparable[iterators.length]; for( int i = 0; i < iterators.length; i++ ) lastValues[ i ] = (Comparable) iterators[ i ].next(); return lastValues; } public final boolean hasNext() { // if this is the first pass, and there is an iterator without a next value, // then we have no next element if( lastValues == null ) { for( Iterator iterator : iterators ) { if( !iterator.hasNext() ) return false; } return true; } for( Iterator iterator : iterators ) { if( iterator.hasNext() ) return true; } return false; } public Tuple next() { if( lastValues == null ) return makeResult( initLastValues() ); for( int i = iterators.length - 1; i >= 0; i-- ) { if( iterators[ i ].hasNext() ) { lastValues[ i ] = (Comparable) iterators[ i ].next(); break; } // reset to first iterators[ i ] = getIterator( i ); lastValues[ i ] = (Comparable) iterators[ i ].next(); } return makeResult( lastValues ); } private Tuple makeResult( Comparable[] lastValues ) { Tuple result = new Tuple(); // flatten the results into one Tuple for( Comparable lastValue : lastValues ) result.addAll( lastValue ); if( LOG.isTraceEnabled() ) LOG.trace( "tuple: " + result.print() ); return result; } public void remove() { // unsupported } } }