001/*
002 * Copyright (c) 2007-2017 Xplenty, Inc. All Rights Reserved.
003 *
004 * Project and contact information: http://www.cascading.org/
005 *
006 * This file is part of the Cascading project.
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *     http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020
021package cascading.tuple;
022
023import java.io.Closeable;
024import java.io.IOException;
025import java.util.Iterator;
026
027import cascading.tuple.util.Resettable;
028
029/**
030 * TupleChainIterator chains the given Iterators into a single Iterator.
031 * <p/>
032 * As one iterator is completed, it will be closed and a new one will start.
033 */
034public class TupleChainIterator implements Iterator<Tuple>, Closeable, Resettable<Iterator<Tuple>>
035  {
036  /** Field iterator */
037  Iterator<Tuple>[] iterators;
038  int currentIterator = 0;
039
040  public TupleChainIterator( Iterator<Tuple>... iterators )
041    {
042    this.iterators = iterators;
043    }
044
045  /**
046   * Method hasNext returns true if there is a next TupleEntry
047   *
048   * @return boolean
049   */
050  public boolean hasNext()
051    {
052    if( iterators.length < currentIterator + 1 ) // past the end
053      return false;
054
055    if( iterators[ currentIterator ].hasNext() )
056      return true;
057
058    closeCurrent();
059
060    currentIterator++;
061
062    return iterators.length != currentIterator && hasNext();
063    }
064
065  @Override
066  public void reset( Iterator<Tuple>... iterators )
067    {
068    this.currentIterator = 0;
069    this.iterators = iterators;
070    }
071
072  /**
073   * Method next returns the next TupleEntry.
074   *
075   * @return TupleEntry
076   */
077  public Tuple next()
078    {
079    hasNext(); // force roll to next iterator
080
081    return iterators[ currentIterator ].next();
082    }
083
084  /** Method remove removes the current Tuple from the underlying collection. */
085  public void remove()
086    {
087    iterators[ currentIterator ].remove();
088    }
089
090  /** Method close closes all underlying resources. */
091  @Override
092  public void close()
093    {
094    if( iterators.length != currentIterator )
095      closeCurrent();
096    }
097
098  protected void closeCurrent()
099    {
100    close( iterators[ currentIterator ] );
101    }
102
103  private void close( Iterator iterator )
104    {
105    if( iterator instanceof Closeable )
106      {
107      try
108        {
109        ( (Closeable) iterator ).close();
110        }
111      catch( IOException exception )
112        {
113        // ignore
114        }
115      }
116    }
117  }