From 6ad95f6fde0d5b6b4425f592a1087255881df0c8 Mon Sep 17 00:00:00 2001 From: Luis Sanchez Date: Fri, 21 Apr 2017 10:32:35 -0400 Subject: [PATCH] [FAB-3305] java cc get query result Change-Id: If3544c57a1b9c7442284ff6d06bc862cdd916ed0 Signed-off-by: Luis Sanchez --- .../fabric/shim/ChaincodeStub.java | 53 ++++++++++++------- .../fabric/shim/impl/ChaincodeStubImpl.java | 15 +++++- .../hyperledger/fabric/shim/impl/Handler.java | 40 ++++++++------ 3 files changed, 70 insertions(+), 38 deletions(-) diff --git a/core/chaincode/shim/java/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java b/core/chaincode/shim/java/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java index 2a3c0d09728..519859c594e 100644 --- a/core/chaincode/shim/java/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java +++ b/core/chaincode/shim/java/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java @@ -33,7 +33,7 @@ public interface ChaincodeStub { * Returns the arguments corresponding to the call to * {@link Chaincode#init(ChaincodeStub)} or * {@link Chaincode#invoke(ChaincodeStub)}. - * + * * @return a list of arguments */ List getArgs(); @@ -42,7 +42,7 @@ public interface ChaincodeStub { * Returns the arguments corresponding to the call to * {@link Chaincode#init(ChaincodeStub)} or * {@link Chaincode#invoke(ChaincodeStub)}. - * + * * @return a list of arguments cast to UTF-8 strings */ List getStringArgs(); @@ -50,9 +50,9 @@ public interface ChaincodeStub { /** * A convenience method that returns the first argument of the chaincode * invocation for use as a function name. - * + * * The bytes of the first argument are decoded as a UTF-8 string. - * + * * @return the function name */ String getFunction(); @@ -61,10 +61,10 @@ public interface ChaincodeStub { * A convenience method that returns all except the first argument of the * chaincode invocation for use as the parameters to the function returned * by #{@link ChaincodeStub#getFunction()}. - * + * * The bytes of the arguments are decoded as a UTF-8 strings and returned as * a list of string parameters.. - * + * * @return a list of parameters */ List getParameters(); @@ -78,7 +78,7 @@ public interface ChaincodeStub { /** * Invoke another chaincode using the same transaction context. - * + * * @param chaincodeName * Name of chaincode to be invoked. * @param args @@ -120,7 +120,7 @@ public interface ChaincodeStub { * Returns all existing keys, and their values, that are lexicographically * between startkey (inclusive) and the endKey * (exclusive). - * + * * @param startKey * @param endKey * @return an {@link Iterable} of {@link KeyValue} @@ -130,10 +130,10 @@ public interface ChaincodeStub { /** * Returns all existing keys, and their values, that are prefixed by the * specified partial {@link CompositeKey}. - * + * * If a full composite key is specified, it will not match itself, resulting * in no keys being returned. - * + * * @param compositeKey * partial composite key * @return an {@link Iterable} of {@link KeyValue} @@ -162,6 +162,19 @@ public interface ChaincodeStub { */ CompositeKey splitCompositeKey(String compositeKey); + /** + * Perform a rich query against the state database. + * + * @param query + * query string in a syntax supported by the underlying state + * database + * @return + * @throws UnsupportedOperationException + * if the underlying state database does not support rich + * queries. + */ + QueryResultsIterator getQueryResult(String query); + /** * Defines the CHAINCODE type event that will be posted to interested * clients when the chaincode's result is committed to the ledger. @@ -175,7 +188,7 @@ public interface ChaincodeStub { /** * Invoke another chaincode using the same transaction context. - * + * * @param chaincodeName * Name of chaincode to be invoked. * @param args @@ -188,11 +201,11 @@ default Response invokeChaincode(String chaincodeName, List args) { /** * Invoke another chaincode using the same transaction context. - * + * * This is a convenience version of * {@link #invokeChaincode(String, List, String)}. The string args will be * encoded into as UTF-8 bytes. - * + * * @param chaincodeName * Name of chaincode to be invoked. * @param args @@ -207,11 +220,11 @@ default Response invokeChaincodeWithStringArgs(String chaincodeName, List getStringArgs() { public String getFunction() { return getStringArgs().size() > 0 ? getStringArgs().get(0) : null; } - + /* (non-Javadoc) * @see org.hyperledger.fabric.shim.ChaincodeStub#getParameters() */ @@ -83,7 +83,7 @@ public String getFunction() { public List getParameters() { return getStringArgs().stream().skip(1).collect(toList()); } - + /* (non-Javadoc) * @see org.hyperledger.fabric.shim.ChaincodeStub#setEvent(java.lang.String, byte[]) */ @@ -187,6 +187,17 @@ public CompositeKey splitCompositeKey(String compositeKey) { return CompositeKey.parseCompositeKey(compositeKey); } + /* (non-Javadoc) + * @see org.hyperledger.fabric.shim.ChaincodeStub#getQueryResult(java.lang.String) + */ + @Override + public QueryResultsIterator getQueryResult(String query) { + return new QueryResultsIteratorImpl(this.handler, getTxId(), + handler.handleGetQueryResult(getTxId(), query), + queryResultBytesToKv.andThen(KeyValueImpl::new) + ); + } + /* (non-Javadoc) * @see org.hyperledger.fabric.shim.ChaincodeStub#invokeChaincode(java.lang.String, java.util.List, java.lang.String) */ diff --git a/core/chaincode/shim/java/src/main/java/org/hyperledger/fabric/shim/impl/Handler.java b/core/chaincode/shim/java/src/main/java/org/hyperledger/fabric/shim/impl/Handler.java index 1df66ecae12..54b436aaa75 100644 --- a/core/chaincode/shim/java/src/main/java/org/hyperledger/fabric/shim/impl/Handler.java +++ b/core/chaincode/shim/java/src/main/java/org/hyperledger/fabric/shim/impl/Handler.java @@ -19,6 +19,7 @@ import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.COMPLETED; import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.DEL_STATE; import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.ERROR; +import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_QUERY_RESULT; import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_STATE; import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.GET_STATE_BY_RANGE; import static org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type.INIT; @@ -48,6 +49,7 @@ import org.hyperledger.fabric.protos.peer.Chaincode.ChaincodeSpec; import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage; import org.hyperledger.fabric.protos.peer.ChaincodeShim.ChaincodeMessage.Type; +import org.hyperledger.fabric.protos.peer.ChaincodeShim.GetQueryResult; import org.hyperledger.fabric.protos.peer.ChaincodeShim.GetStateByRange; import org.hyperledger.fabric.protos.peer.ChaincodeShim.PutStateInfo; import org.hyperledger.fabric.protos.peer.ChaincodeShim.QueryResponse; @@ -217,19 +219,19 @@ private void beforeRegistered(Event event) { private void handleInit(ChaincodeMessage message) { new Thread(() -> { try { - + // Get the function and args from Payload final ChaincodeInput input = ChaincodeInput.parseFrom(message.getPayload()); - + // Mark as a transaction (allow put/del state) markIsTransaction(message.getTxid(), true); - + // Create the ChaincodeStub which the chaincode can use to callback final ChaincodeStub stub = new ChaincodeStubImpl(message.getTxid(), this, input.getArgsList()); - + // Call chaincode's init final Response result = chaincode.init(stub); - + if(result.getStatus() == Status.SUCCESS_VALUE) { // Send COMPLETED with entire result as payload logger.debug(String.format(String.format("[%s]Init succeeded. Sending %s", shortID(message), COMPLETED))); @@ -239,7 +241,7 @@ private void handleInit(ChaincodeMessage message) { logger.error(String.format("[%s]Init failed. Sending %s", shortID(message), ERROR)); triggerNextState(newErrorEventMessage(message.getTxid(), result.getMessage(), stub.getEvent()), true); } - + } catch (InvalidProtocolBufferException | RuntimeException e) { logger.error(String.format("[%s]Init failed. Sending %s", shortID(message), ERROR), e); triggerNextState(ChaincodeMessage.newBuilder() @@ -273,19 +275,19 @@ private void beforeInit(Event event) { private void handleTransaction(ChaincodeMessage message) { new Thread(() -> { try { - + // Get the function and args from Payload final ChaincodeInput input = ChaincodeInput.parseFrom(message.getPayload()); - + // Mark as a transaction (allow put/del state) markIsTransaction(message.getTxid(), true); - + // Create the ChaincodeStub which the chaincode can use to callback final ChaincodeStub stub = new ChaincodeStubImpl(message.getTxid(), this, input.getArgsList()); - + // Call chaincode's invoke final Response result = chaincode.invoke(stub); - + if(result.getStatus() == Status.SUCCESS_VALUE) { // Send COMPLETED with entire result as payload logger.debug(String.format(String.format("[%s]Invoke succeeded. Sending %s", shortID(message), COMPLETED))); @@ -295,7 +297,7 @@ private void handleTransaction(ChaincodeMessage message) { logger.error(String.format("[%s]Invoke failed. Sending %s", shortID(message), ERROR)); triggerNextState(newErrorEventMessage(message.getTxid(), result.getMessage(), stub.getEvent()), true); } - + } catch (InvalidProtocolBufferException | RuntimeException e) { logger.error(String.format("[%s]Invoke failed. Sending %s", shortID(message), ERROR), e); triggerNextState(ChaincodeMessage.newBuilder() @@ -591,6 +593,12 @@ void queryStateClose(String txId, String queryId) { .build().toByteString()); } + QueryResponse handleGetQueryResult(String txId, String query) { + return invokeQueryResponseMessage(txId, GET_QUERY_RESULT, GetQueryResult.newBuilder() + .setQuery(query) + .build().toByteString()); + } + private QueryResponse invokeQueryResponseMessage(String txId, ChaincodeMessage.Type type, ByteString payload) { try { return QueryResponse.parseFrom(invokeChaincodeSupport(txId, type, payload) @@ -672,7 +680,7 @@ Response handleInvokeChaincode(String chaincodeName, List args, String t try { // create the channel on which to communicate the response from validating peer final Channel responseChannel = createChannel(txid); - + // Send INVOKE_CHAINCODE message to validator chaincode support final ChaincodeMessage message = HandlerHelper.newInvokeChaincodeMessage(txid, invocationSpec.toByteString()); logger.debug(String.format("[%s]Sending %s", shortID(message), INVOKE_CHAINCODE)); @@ -680,11 +688,11 @@ Response handleInvokeChaincode(String chaincodeName, List args, String t // wait for response chaincode message final ChaincodeMessage outerResponseMessage = receiveChannel(responseChannel); - + if(outerResponseMessage == null) { return ChaincodeHelper.newInternalServerErrorResponse("chaincode invoke returned null"); } - + logger.debug(String.format("[%s]Received %s.", shortID(outerResponseMessage.getTxid()), outerResponseMessage.getType())); switch (outerResponseMessage.getType()) { @@ -695,7 +703,7 @@ Response handleInvokeChaincode(String chaincodeName, List args, String t logger.debug(String.format("[%s]Received %s.", shortID(responseMessage.getTxid()), responseMessage.getType())); if(responseMessage.getType() == COMPLETED) { // success - return Response.parseFrom(responseMessage.getPayload()); + return Response.parseFrom(responseMessage.getPayload()); } else { // error return ChaincodeHelper.newInternalServerErrorResponse(responseMessage.getPayload().toByteArray());