org.hyperledger.fabric.shim.impl.QueryResultsIteratorImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fabric-chaincode-shim Show documentation
Show all versions of fabric-chaincode-shim Show documentation
Hyperledger Fabric Java Chaincode Shim
/*
* Copyright 2019 IBM All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.fabric.shim.impl;
import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.QUERY_STATE_CLOSE;
import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.QUERY_STATE_NEXT;
import java.util.Collections;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.function.Function;
import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
import org.hyperledger.fabric.protos.peer.QueryResponse;
import org.hyperledger.fabric.protos.peer.QueryResultBytes;
import org.hyperledger.fabric.protos.peer.QueryStateClose;
import org.hyperledger.fabric.protos.peer.QueryStateNext;
import org.hyperledger.fabric.shim.ledger.QueryResultsIterator;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
/**
* This class provides an ITERABLE object of query results.
*
* NOTE the class name
* is misleading - as this class is not an iterator itself, rather it implements
* java.lang.Iterable via the QueryResultsIterator
*
* public interface QueryResultsIterator extends Iterable, AutoCloseable
*
* @param
*/
class QueryResultsIteratorImpl implements QueryResultsIterator {
private final ChaincodeInvocationTask handler;
private final String channelId;
private final String txId;
private Iterator currentIterator;
private QueryResponse currentQueryResponse;
private Function mapper;
QueryResultsIteratorImpl(final ChaincodeInvocationTask handler, final String channelId, final String txId, final ByteString responseBuffer,
final Function mapper) {
try {
this.handler = handler;
this.channelId = channelId;
this.txId = txId;
this.currentQueryResponse = QueryResponse.parseFrom(responseBuffer);
this.currentIterator = currentQueryResponse.getResultsList().iterator();
this.mapper = mapper;
} catch (final InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
}
@Override
public Iterator iterator() {
return new Iterator() {
@Override
public boolean hasNext() {
return currentIterator.hasNext() || currentQueryResponse.getHasMore();
}
@Override
public T next() {
// return next fetched result, if any
if (currentIterator.hasNext()) {
return mapper.apply(currentIterator.next());
}
// throw exception if there are no more expected results
if (!currentQueryResponse.getHasMore()) {
throw new NoSuchElementException();
}
// get more results from peer
final ByteString requestPayload = QueryStateNext.newBuilder().setId(currentQueryResponse.getId()).build().toByteString();
final ChaincodeMessage requestNextMessage = ChaincodeMessageFactory.newEventMessage(QUERY_STATE_NEXT, channelId, txId, requestPayload);
final ByteString responseMessage = QueryResultsIteratorImpl.this.handler.invoke(requestNextMessage);
try {
currentQueryResponse = QueryResponse.parseFrom(responseMessage);
} catch (final InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
currentIterator = currentQueryResponse.getResultsList().iterator();
// return next fetched result
return mapper.apply(currentIterator.next());
}
};
}
@Override
public void close() throws Exception {
final ByteString requestPayload = QueryStateClose.newBuilder().setId(currentQueryResponse.getId()).build().toByteString();
final ChaincodeMessage requestNextMessage = ChaincodeMessageFactory.newEventMessage(QUERY_STATE_CLOSE, channelId, txId, requestPayload);
this.handler.invoke(requestNextMessage);
this.currentIterator = Collections.emptyIterator();
this.currentQueryResponse = QueryResponse.newBuilder().setHasMore(false).build();
}
}