package com.taobao.metamorphosis.client; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.concurrent.TimeUnit; import com.taobao.gecko.core.util.StringUtils; import com.taobao.metamorphosis.Message; import com.taobao.metamorphosis.client.consumer.MessageConsumer; import com.taobao.metamorphosis.cluster.Partition; import com.taobao.metamorphosis.consumer.MessageIterator; import com.taobao.metamorphosis.exception.MetaClientException; /** * TopicBrowser implementation. * * @author dennis<killme2008@gmail.com> * @since 1.4.5 */ public class MetaTopicBrowser implements TopicBrowser { private final String topic; private final MessageConsumer consumer; private final List<Partition> partitions; private final int maxSize; private final long timeoutInMills; protected class Itr implements Iterator<Message> { protected final List<Partition> partitions; private MessageIterator it; private long offset = 0L; private Partition partition; public Itr(List<Partition> partitions) { super(); this.partitions = partitions; } @Override public boolean hasNext() { try { if (this.it != null && this.it.hasNext()) { return true; } else { if (this.partition == null) { if (this.partitions.isEmpty()) { return false; } else { this.nextPartition(); } } while (this.partition != null) { // increase offset for this partition if it is not null. if (this.it != null) { this.offset += this.it.getOffset(); } this.it = MetaTopicBrowser.this.consumer.get(MetaTopicBrowser.this.topic, this.partition, this.offset, MetaTopicBrowser.this.maxSize, MetaTopicBrowser.this.timeoutInMills, TimeUnit.MILLISECONDS); if (this.it != null && this.it.hasNext()) { // If this partition still has messages, returns // true. return true; } else { // move on to next partition. if (this.partitions.isEmpty()) { this.partition = null; // There is no more partitions,return false. return false; } else { // Change partition,and continue trying to get // iterator. this.nextPartition(); } } } return false; } } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } catch (Exception e) { throw new IllegalStateException(e); } } private void nextPartition() { this.partition = this.partitions.get(0); this.partitions.remove(0); this.offset = 0; this.it = null; } @Override public Message next() { if (this.hasNext()) { try { return this.it.next(); } catch (Exception e) { throw new IllegalStateException(e); } } else { throw new NoSuchElementException(); } } @Override public void remove() { throw new UnsupportedOperationException(); } } public MessageConsumer getConsumer() { return this.consumer; } public MetaTopicBrowser(String topic, int maxSize, long timeoutInMills, MessageConsumer consumer, List<Partition> partitions) { super(); if (StringUtils.isBlank(topic)) { throw new IllegalArgumentException("Blank topic"); } if (maxSize <= 0) { throw new IllegalArgumentException("Invalid max size"); } if (timeoutInMills <= 0) { throw new IllegalArgumentException("Invalid timeout value"); } this.timeoutInMills = timeoutInMills; this.topic = topic; this.maxSize = maxSize; this.consumer = consumer; this.partitions = partitions; } @Override public Iterator<Message> iterator() { return new Itr(new ArrayList<Partition>(this.partitions)); } @Override public List<Partition> getPartitions() { return Collections.unmodifiableList(this.partitions); } @Override public void shutdown() throws MetaClientException { this.consumer.shutdown(); } @Override public String getTopic() { return this.topic; } }