spork-master/src/org/apache/pig/backend/hadoop/executionengine/spark/converter/POOutputConsumerIterator.java
package org.apache.pig.backend.hadoop.executionengine.spark.converter;

import org.apache.pig.backend.executionengine.ExecException;
import org.apache.pig.backend.hadoop.executionengine.physicalLayer.POStatus;
import org.apache.pig.backend.hadoop.executionengine.physicalLayer.Result;
import org.apache.pig.data.Tuple;

abstract class POOutputConsumerIterator implements java.util.Iterator<Tuple> {
    private final java.util.Iterator<Tuple> input;
    private Result result = null;
    private boolean returned = true;
    private boolean finished = false;

    POOutputConsumerIterator(java.util.Iterator<Tuple> input) {
        this.input = input;
    }

    abstract protected void attach(Tuple tuple);

    abstract protected Result getNextResult() throws ExecException;

    private void readNext() {
        try {
            if (result != null && !returned) {
                return;
            }
            // see PigGenericMapBase
            if (result == null) {
                if (!input.hasNext()) {
                    finished = true;
                    return;
                }
                Tuple v1 = input.next();
                attach(v1);
            }
            result = getNextResult();
            returned = false;
            switch (result.returnStatus) {
            case POStatus.STATUS_OK:
                returned = false;
                break;
            case POStatus.STATUS_NULL:
                returned = true; // skip: see PigGenericMapBase
                readNext();
                break;
            case POStatus.STATUS_EOP:
                finished = !input.hasNext();
                if (!finished) {
                    result = null;
                    readNext();
                }
                break;
            case POStatus.STATUS_ERR:
                throw new RuntimeException("Error while processing " + result);
            }
        } catch (ExecException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean hasNext() {
        readNext();
        return !finished;
    }

    @Override
    public Tuple next() {
        readNext();
        if (finished) {
            throw new RuntimeException("Passed the end. call hasNext() first");
        }
        if (result == null || result.returnStatus != POStatus.STATUS_OK) {
            throw new RuntimeException("Unexpected response code in ForEach: "
                    + result);
        }
        returned = true;
        return (Tuple) result.result;
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }
}