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