/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.internal.streaming.object.iterator;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
/**
* Implementation of {@link Producer} to expose streams from several producers as a single data feed. Producers are consumed in
* order until they're all consumed. All producers need to share the same generic type T
*
* @since 3.5.0
*/
public class CompositeProducer<T> implements Producer<T> {
private Integer totalAvailable = null;
private List<Producer<T>> producers;
private Iterator<Producer<T>> producersIterator;
private Producer<T> currentProducer;
/**
* Takes a list of producers to be composited. They will be consumed in this order
*
* @param producers a list of {@link Producer}
*/
public CompositeProducer(List<Producer<T>> producers) {
if (CollectionUtils.isEmpty(producers)) {
throw new IllegalArgumentException("Cannot make a composition of null or empty producers list");
}
this.producers = producers;
this.producersIterator = producers.iterator();
this.currentProducer = this.producersIterator.next();
}
public CompositeProducer(Producer<T>... producers) {
this(Arrays.asList(producers));
}
/**
* {@inheritDoc} This method calls the produce method on the current producer. When that producer is exhausted, then it switches
* to the next one. When the last producer is also exhausted, then it returns <code>null<c/code>. This method does not close any
* producer when it is exhausted. Use the close method for that
*/
@Override
public T produce() {
if (this.currentProducer == null) {
return null;
}
T next = this.currentProducer.produce();
if (next == null) {
if (this.producersIterator.hasNext()) {
this.currentProducer = this.producersIterator.next();
} else {
this.currentProducer = null;
}
return this.produce();
}
return next;
}
/**
* Accumulates the total available count of all the producers. If one of them does not have a value available (returns -1) then
* it is not factored in
*/
@Override
public int getSize() {
if (this.totalAvailable == null) {
int total = 0;
for (Producer<T> producer : this.producers) {
int available = producer.getSize();
if (available > 0) {
total += available;
}
}
this.totalAvailable = total;
}
return this.totalAvailable;
}
/**
* Closes all the producers
*/
@Override
public void close() throws IOException {
for (Producer<T> producer : this.producers) {
producer.close();
}
}
}