Now you're ready to build the Java chaincode shim client JAR. Navigate to
$GOPATH/src/github.com/hyperledger/fabric/core/chaincode/shim/java
and run these two commands:
gradle -b build.gradle clean
gradle -b build.gradle build
|
The Gradle build output should look like this:
$ cd $GOPATH/src/github.com/hyperledger/fabric/core/chaincode/shim/java
$ gradle -b build.gradle clean
Starting a Gradle Daemon (subsequent builds will be faster)
:core:chaincode:shim:java:clean
BUILD SUCCESSFUL
Total time: 5.422 secs
$ gradle -b build.gradle build
:core:chaincode:shim:java:copyProtos UP-TO-DATE
:core:chaincode:shim:java:extractIncludeProto
:core:chaincode:shim:java:extractProto UP-TO-DATE
:core:chaincode:shim:java:generateProto UP-TO-DATE
:core:chaincode:shim:java:compileJava
:core:chaincode:shim:java:processResources
:core:chaincode:shim:java:classes
:core:chaincode:shim:java:jar
:core:chaincode:shim:java:assemble
:core:chaincode:shim:java:extractIncludeTestProto
:core:chaincode:shim:java:extractTestProto UP-TO-DATE
:core:chaincode:shim:java:generateTestProto UP-TO-DATE
:core:chaincode:shim:java:compileTestJava UP-TO-DATE
:core:chaincode:shim:java:processTestResources UP-TO-DATE
:core:chaincode:shim:java:testClasses UP-TO-DATE
:core:chaincode:shim:java:test UP-TO-DATE
:core:chaincode:shim:java:check UP-TO-DATE
:core:chaincode:shim:java:build
:core:chaincode:shim:java:copyToLib
:core:chaincode:shim:java:generatePomFileForMavenJavaPublication
:core:chaincode:shim:java:publishMavenJavaPublicationToMavenLocal
:core:chaincode:shim:java:publishToMavenLocal
BUILD SUCCESSFUL
Total time: 4.521 secs
|
The last thing the build does is add the shim client JAR to your local
Maven repository. At this point, you're ready to build your chaincode.
Unless you update your fabric source code at some point in the future, or
just want to rebuild the shim client JAR again for some reason, you won't
have to run the Java shim client JAR build again.
Deploy and run a Java chaincode example
Now that you've defined and started your local blockchain network, and have
built and installed the Java shim client JAR to your local Maven
repository, you're ready to build, register, and invoke transactions on
one of the Java chaincode examples that ship with the Hyperledger Fabric
that you downloaded earlier.
Deploy and run your chaincode
Here are the steps you'll follow:
- Build the example using Gradle.
- Register the example with the validating peer network, by running a
script that is created for you by the Gradle build.
- Deploy the example to the local blockchain network using SoapUI.
- Invoke transactions on the example chaincode using SoapUI.
Build the example
Navigate to the
$GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example
directory.
Next, launch the Gradle build via the command line using this command:
gradle -b build.gradle build
|
You should see output like this:
$ cd GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example
$ gradle -b build.gradle build
Starting a Gradle Daemon (subsequent builds will be faster)
:examples:chaincode:java:Example:compileJava
:examples:chaincode:java:Example:processResources UP-TO-DATE
:examples:chaincode:java:Example:classes
:examples:chaincode:java:Example:jar
:examples:chaincode:java:Example:startScripts
:examples:chaincode:java:Example:distTar
:examples:chaincode:java:Example:distZip
:examples:chaincode:java:Example:assemble
:examples:chaincode:java:Example:compileTestJava UP-TO-DATE
:examples:chaincode:java:Example:processTestResources UP-TO-DATE
:examples:chaincode:java:Example:testClasses UP-TO-DATE
:examples:chaincode:java:Example:test UP-TO-DATE
:examples:chaincode:java:Example:check UP-TO-DATE
:examples:chaincode:java:Example:build
:examples:chaincode:java:Example:copyToLib
BUILD SUCCESSFUL
Total time: 6.935 secs
|
The build creates a standalone distribution that's located within the
directory build/distributions in two forms: a TAR file and a ZIP file, and
each of these files contains everything you need to run the chaincode,
including a script to drive it called Example.
The Example chaincode is now ready to be registered with the local
blockchain network.
Make sure your local blockchain network is running. If not, you'll need to
start it up. See the section titled "
Start
the blockchain network" if you need a refresher.
If you're not already there, navigate to
$GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example.
Next, extract Example.zip (or Example.tar) in the build/distributions
directory:
$ cd $GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example
$ cd build/distributions/
$ unzip Example.zip
Archive: Example.zip
inflating: Example/lib/chaincode.jar
inflating: Example/lib/grpc-all-0.13.2.jar
inflating: Example/lib/commons-cli-1.3.1.jar
inflating: Example/lib/shim-client-1.0.jar
inflating: Example/lib/grpc-netty-0.13.2.jar
inflating: Example/lib/grpc-auth-0.13.2.jar
inflating: Example/lib/grpc-protobuf-nano-0.13.2.jar
inflating: Example/lib/grpc-core-0.13.2.jar
inflating: Example/lib/grpc-protobuf-0.13.2.jar
inflating: Example/lib/grpc-okhttp-0.13.2.jar
inflating: Example/lib/grpc-stub-0.13.2.jar
inflating: Example/lib/protobuf-java-3.0.0.jar
inflating: Example/lib/netty-tcnative-boringssl-static-1.1.33.Fork21-osx-x86_64.jar
inflating: Example/lib/netty-codec-http2-4.1.0.CR3.jar
inflating: Example/lib/google-auth-library-oauth2-http-0.3.0.jar
inflating: Example/lib/guava-18.0.jar
inflating: Example/lib/protobuf-javanano-3.0.0-alpha-5.jar
inflating: Example/lib/jsr305-3.0.0.jar
inflating: Example/lib/okio-1.6.0.jar
inflating: Example/lib/okhttp-2.5.0.jar
inflating: Example/lib/netty-codec-http-4.1.0.CR3.jar
inflating: Example/lib/netty-handler-4.1.0.CR3.jar
inflating: Example/lib/google-auth-library-credentials-0.3.0.jar
inflating: Example/lib/google-http-client-1.19.0.jar
inflating: Example/lib/google-http-client-jackson2-1.19.0.jar
inflating: Example/lib/netty-codec-4.1.0.CR3.jar
inflating: Example/lib/netty-buffer-4.1.0.CR3.jar
inflating: Example/lib/netty-transport-4.1.0.CR3.jar
inflating: Example/lib/httpclient-4.0.1.jar
inflating: Example/lib/jackson-core-2.1.3.jar
inflating: Example/lib/netty-common-4.1.0.CR3.jar
inflating: Example/lib/netty-resolver-4.1.0.CR3.jar
inflating: Example/lib/httpcore-4.0.1.jar
inflating: Example/lib/commons-logging-1.1.1.jar
inflating: Example/lib/commons-codec-1.3.jar
inflating: Example/bin/Example
inflating: Example/bin/Example.bat
|
"Why so many files?" you may wonder. The distribution contains everything
you need to run the chaincode standalone (in its own process), along with
all dependent JARs.
To register the chaincode example, within the build/distributions folder,
execute the following script:
This runs a standalone process that registers the chaincode example with
the local blockchain network. You should see terminal window output like
this:
$ ./Example/bin/Example
Hello world! starting [Ljava.lang.String;@7ef20235
Feb 22, 2017 10:05:08 AM example.Example main
INFO: starting
Feb 22, 2017 10:05:08 AM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection
INFO: Inside newPeerCLientConnection
Feb 22, 2017 10:05:08 AM io.grpc.internal.TransportSet$1 call
INFO: Created transport io.grpc.netty.NettyClientTransport@3dd7b80b(/127.0.0.1:7051) for /127.0.0.1:7051
Feb 22, 2017 10:05:14 AM io.grpc.internal.TransportSet$TransportListener transportReady
INFO: Transport io.grpc.netty.NettyClientTransport@3dd7b80b(/127.0.0.1:7051) for /127.0.0.1:7051 is ready
|
Take a look at the console for your local blockchain network, and you
should see lines of output that look like this:
1
2
3
4
5
6
7
8
9
10
|
.
.
vp0_1 | 16:05:14.048 [chaincode] HandleChaincodeStream -> DEBU 06d Current context deadline = 0001-01-01 00:00:00 +0000 UTC, ok = false
vp0_1 | 16:05:14.065 [chaincode] processStream -> DEBU 06e []Received message REGISTER from shim
vp0_1 | 16:05:14.065 [chaincode] HandleMessage -> DEBU 06f []Handling ChaincodeMessage of type: REGISTER in state created
vp0_1 | 16:05:14.065 [chaincode] beforeRegisterEvent -> DEBU 070 Received REGISTER in state created
vp0_1 | 16:05:14.065 [chaincode] registerHandler -> DEBU 071 registered handler complete for chaincode hello
vp0_1 | 16:05:14.065 [chaincode] beforeRegisterEvent -> DEBU 072 Got REGISTER for chaincodeID = name:"hello" , sending back REGISTERED
.
.
|
Make a note of the chaincodeID
name in the registration log
output (
hello for the Example; see
line 8 in
the preceding). You'll need that later for the JSON message when you
deploy the Example chaincode through the fabric's REST interface.
The preceding output indicates that the Example chaincode is running and
has been registered with the local blockchain validating peer network, and
is ready to be deployed.
The Hyperledger Fabric provides a REST web service interface that you use
to interact with the fabric. The first interaction with the fabric is to
deploy your chaincode. Make sure your local blockchain network is running,
then start SoapUI, and click the
REST button to create a
new REST project. You should see a dialog box like Figure 3, where you
enter the based URL used for all REST requests:
Figure 3. SoapUI New REST project dialog
Enter
http://localhost:7050 as the URL, then click
OK. Port
7050 is the default REST port
used by the fabric, and since your blockchain network is running on your
local computer, you will use
localhost as the host name.
When SoapUI comes up, you can do a quick smoke test to make sure it can
communicate with your local blockchain network. Expand the new REST
resource you just created until you see
Request 1, then open
it in the Editor window. Use
GET for the method, and under
resource enter
/chain. Make sure to
click the
JSON option on the output tab, then run the
request (by clicking on the
arrow icon). When you execute
this request, it simply returns the current block hash in the output tab,
located on the right-hand side of the editor window, as you can see in
Figure 4:
Figure 4. Blockchain smoke test
If you see a JSON message that looks similar to the one in Figure 4 (the
currentBlockHash value for your network will be different, of
course), then you're ready to deploy the Example chaincode.
Right-click on the endpoint under
REST Project 1 (http://localhost:7050) and choose
New
Resource; you should see a "New REST Resource" dialog box
(see Figure 5) with a
Resource Path field:
Figure 5. SoapUI New Resource dialog
Enter
/chaincode as the
resource path,
then click
OK, and you should see the new resource show
up in your SoapUI Projects panel. Open up the request for this resource
(by default it will be called
Request 1), change the
method to
POST, and paste this JSON into the request area,
located in the lower left corner of the request editor window:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"jsonrpc": "2.0",
"method": "deploy",
"params": {
"type": 1,
"chaincodeID":{
"name": "hello"
},
"CtorMsg": {
"args": [""]
}
},
"id": 1
}
|
Three things to note:
- Line 3: The method value must be
deploy.
- Lines 6-7: The
chaincodeID.name in the
JSON message must match the chaincodeID when you
registered the Example chaincode in the previous section
(hello for the Example chaincode).
- Line 13: The
id value is used to
coordinate requests. You don't need to worry about it so much for this
tutorial, but notice that it is always sent back on the response (see
the next listing).
When you submit this request, the JSON output should look like this:
1
2
3
4
5
6
7
8
|
{
"jsonrpc": "2.0",
"result": {
"status": "OK",
"message": "hello"
},
"id": 1
}
|
Figure 6 shows a screenshot of what this looks like in SoapUI. The JSON
output message will appear in the output tab, which is located on the
right-hand side of the request editor.
Figure 6. SoapUI Chaincode deploy request
The network log output in the terminal window should include lines that
look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
.
.
vp0_1 | 20:48:39.482 [rest] ProcessChaincode -> INFO 0c4 REST processing chaincode request...
vp0_1 | 20:48:39.482 [rest] processChaincodeDeploy -> INFO 0c5 REST deploying chaincode...
vp0_1 | 20:48:39.483 [devops] Deploy -> DEBU 0c6 Creating deployment transaction (hello)
vp0_1 | 20:48:39.483 [devops] Deploy -> DEBU 0c7 Sending deploy transaction (hello) to validator
vp0_1 | 20:48:39.483 [peer] sendTransactionsToLocalEngine -> DEBU 0c8 Marshalling transaction CHAINCODE_DEPLOY to send to local engine
vp0_1 | 20:48:39.483 [peer] sendTransactionsToLocalEngine -> DEBU 0c9 Sending message CHAIN_TRANSACTION with timestamp seconds:1487796519 nanos:483661510 to local engine
vp0_1 | 20:48:39.483 [consensus/noops] RecvMsg -> DEBU 0ca Handling Message of type: CHAIN_TRANSACTION
vp0_1 | 20:48:39.483 [consensus/noops] broadcastConsensusMsg -> DEBU 0cb Broadcasting CONSENSUS
vp0_1 | 20:48:39.483 [peer] Broadcast -> DEBU 0cc Broadcast took 1.135s
vp0_1 | 20:48:39.483 [consensus/noops] RecvMsg -> DEBU 0cd Sending to channel tx uuid: hello
vp0_1 | 20:48:39.483 [rest] processChaincodeDeploy -> INFO 0ce Successfully deployed chainCode: hello
vp0_1 | 20:48:39.484 [rest] ProcessChaincode -> INFO 0cf REST successfully deploy chaincode: {"jsonrpc":"2.0","result":{"status":"OK","message":"hello"},"id":1}
.
.
|
Lines 3-4 show the output indicating the network has
received the deploy message and the fabric is deploying your chaincode.
Lines 13-14 show that your chaincode has been
deployed successfully.
Take note of output like this in the terminal window running your
chaincode:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
$ ./build/distributions/Example/bin/Example
Hello world! starting [Ljava.lang.String;@7ef20235
Feb 22, 2017 2:44:43 PM example.Example main
INFO: starting
Feb 22, 2017 2:44:43 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection
INFO: Inside newPeerCLientConnection
Feb 22, 2017 2:44:43 PM io.grpc.internal.TransportSet$1 call
INFO: Created transport io.grpc.netty.NettyClientTransport@46adccd3(/127.0.0.1:7051) for /127.0.0.1:7051
Feb 22, 2017 2:44:48 PM io.grpc.internal.TransportSet$TransportListener transportReady
INFO: Transport io.grpc.netty.NettyClientTransport@46adccd3(/127.0.0.1:7051) for /127.0.0.1:7051 is ready
Feb 22, 2017 2:48:40 PM example.Example run
INFO: In run, function:
Feb 22, 2017 2:48:40 PM example.Example run
|
I've included all of the output for context, and you should see lines like
11-13 when you send the deploy message to your
blockchain network.
Invoke a transaction on the example
Finally, you will invoke the
hello method and watch it show up
in the log messages of the terminal window running your chaincode.
Under the
chaincode resource in SoapUI, right-click on
Method 1 and choose
Clone Method.
Call the method
Invoke, and click
OK. Open
Request 1 under your new
Invoke method
and paste in this JSON request:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"jsonrpc": "2.0",
"method": "invoke",
"params": {
"type": 1,
"chaincodeID":{
"name": "hello"
},
"CtorMsg": {
"args": ["hello"]
}
},
"id": 2
}
|
When you run the request, you should see this JSON response:
1
2
3
4
5
6
7
8
|
{
"jsonrpc": "2.0",
"result": {
"status": "OK",
"message": "1c1811d0-a958-4c58-ab1d-e1df550c18a3"
},
"id": 2
}
|
Figure 7 shows a screenshot of what this looks like in SoapUI.
Figure 7. SoapUI Chaincode invoke request
The network log output should include lines that look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
.
.
vp0_1 | 21:44:35.143 [rest] ProcessChaincode -> INFO 555 REST processing chaincode request...
vp0_1 | 21:44:35.143 [rest] processChaincodeInvokeOrQuery -> INFO 556 REST invoke chaincode...
vp0_1 | 21:44:35.143 [devops] invokeOrQuery -> INFO 557 Transaction ID: 1c1811d0-a958-4c58-ab1d-e1df550c18a3
vp0_1 | 21:44:35.143 [devops] createExecTx -> DEBU 558 Creating invocation transaction (1c1811d0-a958-4c58-ab1d-e1df550c18a3)
vp0_1 | 21:44:35.143 [devops] invokeOrQuery -> DEBU 559 Sending invocation transaction (1c1811d0-a958-4c58-ab1d-e1df550c18a3) to validator
vp0_1 | 21:44:35.143 [peer] sendTransactionsToLocalEngine -> DEBU 55a Marshalling transaction CHAINCODE_INVOKE to send to local engine
vp0_1 | 21:44:35.143 [peer] sendTransactionsToLocalEngine -> DEBU 55b Sending message CHAIN_TRANSACTION with timestamp seconds:1487799875 nanos:143438691 to local engine
vp0_1 | 21:44:35.143 [consensus/noops] RecvMsg -> DEBU 55c Handling Message of type: CHAIN_TRANSACTION
vp0_1 | 21:44:35.143 [consensus/noops] broadcastConsensusMsg -> DEBU 55d Broadcasting CONSENSUS
vp0_1 | 21:44:35.143 [peer] Broadcast -> DEBU 55e Broadcast took 1.249s
vp0_1 | 21:44:35.143 [consensus/noops] RecvMsg -> DEBU 55f Sending to channel tx uuid: 1c1811d0-a958-4c58-ab1d-e1df550c18a3
vp0_1 | 21:44:35.143 [rest] processChaincodeInvokeOrQuery -> INFO 560 Successfully submitted invoke transaction with txid (1c1811d0-a958-4c58-ab1d-e1df550c18a3)
vp0_1 | 21:44:35.143 [rest] ProcessChaincode -> INFO 561 REST successfully submitted invoke transaction: {"jsonrpc":"2.0","result":{"status":"OK","message":"1c1811d0-a958-4c58-ab1d-e1df550c18a3"},"id":2}
.
.
|
And the chaincode log output like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
$ ./build/distributions/Example/bin/Example
Hello world! starting [Ljava.lang.String;@7ef20235
Feb 22, 2017 3:26:57 PM example.Example main
INFO: starting
Feb 22, 2017 3:26:57 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection
INFO: Inside newPeerCLientConnection
Feb 22, 2017 3:26:57 PM io.grpc.internal.TransportSet$1 call
INFO: Created transport io.grpc.netty.NettyClientTransport@765e4953(/127.0.0.1:7051) for /127.0.0.1:7051
Feb 22, 2017 3:27:02 PM io.grpc.internal.TransportSet$TransportListener transportReady
INFO: Transport io.grpc.netty.NettyClientTransport@765e4953(/127.0.0.1:7051) for /127.0.0.1:7051 is ready
Feb 22, 2017 3:27:24 PM example.Example run
INFO: In run, function:
Feb 22, 2017 3:27:24 PM example.Example run
SEVERE: No matching case for function:
Feb 22, 2017 3:30:55 PM example.Example run
INFO: In run, function:hello
hello invoked
|
Once again, I've shown all the chaincode output. You can see where the
hello function was invoked (
line 16).
Now you've seen how to build, deploy, and run Java chaincode on your local
blockchain network. In the next section, you'll write a chaincode program
(almost) from scratch using the Eclipse IDE, build the chaincode program
using Gradle, and exercise it using SoapUI.
Write your first Java chaincode program
In the previous section, you got familiar with how to build, run, deploy,
and invoke chaincode, but you haven't yet written any Java code.
In this section, you'll use the Eclipse IDE, a plugin for Gradle that works
with Eclipse, and a skeleton Java chaincode project called
ChaincodeTutorial to write your first Java chaincode program. You'll get
the skeleton code from a GitHub repo I created for this tutorial, import
that code into Eclipse, add code to make the chaincode smart contract
function according to the requirements, and build that code using Gradle
from within your Eclipse IDE.
Here are the steps you'll follow:
- Install the Gradle Buildship plugin for Eclipse.
- Clone the ChaincodeTutorial project from GitHub.
- Import the project into Eclipse.
- Explore the chaincode skeleton project.
- Write the Java chaincode.
- Build the Java chaincode.
When you've completed this section, your chaincode will be ready to run on
your local blockchain network.
Install the Gradle Buildship plugin for
Eclipse
You can use any IDE you like, but the instructions in this tutorial are for
Eclipse.
Note: The Buildship Gradle plugin helps
integrate Gradle with Eclipse, but you will still need to have installed
Gradle on your computer.
If you've been following along with the tutorial, you should already have
Gradle installed on your computer; if it's not installed, do that now.
Refer to the "Install the build software" section to see how to install
Gradle on your computer.
To install the Buildship Gradle plugin for Eclipse, which helps your Gradle
installation work with Eclipse, within Eclipse, go to
Help >
Eclipse Marketplace... In the Eclipse Marketplace dialog,
enter
buildship in the
Find text field
and click the
Go button. You should see something like
Figure 8, showing the Buildship Gradle Integration 2.0 plugin as the first
result of the search:
Figure 8. Eclipse Marketplace: Gradle Buildship
plugin

Under
Buildship Gradle Integration, click the
Install button and follow the prompts. When you click
Finish, the Buildship Gradle plugin for Eclipse will
be installed, and you'll be asked to restart Eclipse.
When Eclipse reopens, Gradle should be fully integrated with your Eclipse
IDE. You are now ready to clone the ChaincodeTutorial repository from
GitHub.
Clone the ChaincodeTutorial project from
GitHub
Now that you have your Eclipse IDE configured to work with Gradle, you will
clone the ChaincodeTutorial code from GitHub and import the code into
Eclipse. Open a command prompt or terminal window, navigate to your
$GOPATH, and execute this command:
git clone https://github.com/makotogo/ChaincodeTutorial.git
|
Your command output should look something like this:
$ export GOPATH=/Users/sperry/home/mychaincode
$ cd $GOPATH
$ git clone https://github.com/makotogo/ChaincodeTutorial.git
Cloning into 'ChaincodeTutorial'...
remote: Counting objects: 133, done.
remote: Compressing objects: 100% (90/90), done.
remote: Total 133 (delta 16), reused 118 (delta 1), pack-reused 0
Receiving objects: 100% (133/133), 9.39 MiB | 1.95 MiB/s, done.
Resolving deltas: 100% (16/16), done.
$ cd ChaincodeTutorial
$ pwd
/Users/sperry/home/mychaincode/ChaincodeTutorial
|
This command clones the Blockchain ChaincodeTutorial repo from GitHub to
your
$GOPATH. It consists of a skeleton Java chaincode
project you can build, run, and experiment with in your local blockchain
network.
But before you can do any of that, you need to import the code into
Eclipse.
Import the project into Eclipse
In Eclipse, go to
File > Import... > Gradle > Existing
Gradle project. A wizard dialog box should open (see Figure
9).
Figure 9. Eclipse Import Wizard: Gradle Project

Click
Next. On the dialog box that comes up next in the
wizard (see Figure 10), browse to
$GOPATH/ChaincodeTutorial,
and click
Finish to import the project.
Figure 10. Eclipse Import Wizard: Gradle Project (Project
root directory)

When the project has finished importing, make sure to select the
Java Perspective, and the ChaincodeTutorial project
you just imported will show up in the Project Explorer view.
Now that you have the code imported into your Eclipse workspace, you are
ready to write your chaincode.
Explore the chaincode skeleton
project
In this section you'll explore the chaincode project so you understand how
it is supposed to function before you write any Java code.
As developers, we love to write code, so I don't want to deprive you of the
opportunity to write Java code. However, the project setup can be complex,
and I don't want that to get in the way of the main point of this
tutorial. To that end, I've provided most of the code you will need.
Before you jump in, let's take a quick look at the base class, called
AbstractChaincode, which is located in the
com.makotojava.learn.blockchain.chaincode package, and shown
in Listing 1.
Listing 1. The AbstractChaincode
class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
package com.makotojava.learn.blockchain.chaincode;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.java.shim.ChaincodeBase;
import org.hyperledger.java.shim.ChaincodeStub;
public abstract class AbstractChaincode extends ChaincodeBase {
private static final Log log = LogFactory.getLog(AbstractChaincode.class);
public static final String FUNCTION_INIT = "init";
public static final String FUNCTION_QUERY = "query";
protected abstract String handleInit(ChaincodeStub stub, String[] args);
protected abstract String handleQuery(ChaincodeStub stub, String[] args);
protected abstract String handleOther(ChaincodeStub stub, String function, String[] args);
@Override
public String run(ChaincodeStub stub, String function, String[] args) {
String ret;
log.info("Greetings from run(): function -> " + function + " | args -> " + Arrays.toString(args));
switch (function) {
case FUNCTION_INIT:
ret = handleInit(stub, args);
break;
case FUNCTION_QUERY:
ret = handleQuery(stub, args);
default:
ret = handleOther(stub, function, args);
break;
}
return ret;
}
@Override
public String query(ChaincodeStub stub, String function, String[] args) {
return handleQuery(stub, args);
}
}
|
The first thing I want to point out is that
AbstractChaincode
is a subclass of
ChaincodeBase, which is from the fabric shim
client (
lines 7, 10).
Lines 17-19 show the methods you need to implement in the
ChaincodeLog class (which is a subclass of
AbstractChaincode) to handle the initialization, ledger
query, and log functions, respectively.
Lines 22-36 show the
run() method of the
ChaincodeBase class (from the chaincode shim client), where
we figure out what function has been invoked and to which handler the call
should be delegated. The class is extensible in that any other functions
than
init and
query (such as the
log function) are handled by
handleOther(),
which you must also implement.
Now, open the
ChaincodeLog class in the
com.makotojava.learn.blockchain.chaincode package.
I've provided only a skeleton for you to flesh out — that is, I've
provided just enough code so that it compiles. You'll have to write the
rest of the code. You should run the JUnit tests and see that they fail
(because you haven't written the implementation yet), and why. In other
words, you can use the JUnit tests as a guide for properly implementing
the code.
Now, if this feels a little over your head, don't worry; I've provided the
solution, which is located in
com.makotojava.learn.blockchain.chaincode.solution, in case
you get stuck (or if you just want a reference to guide you through the
implementation).
First, a little background on what you need to know in order to implement
the chaincode methods in
ChaincodeLog. The
ChaincodeStub class is how your Java chaincode communicates
with the Hyperledger Fabric framework, and recall that the ledger is at
the core of the transparency aspect of blockchain technology. What makes a
smart contract (accountability) work is the state of the ledger, and your
chaincode accesses the ledger's state through the
ChaincodeStub. By accessing the ledger state, you're able to
implement a smart contract (a.k.a., chaincode).
There are a number of methods on
ChaincodeStub that allow you
to store, retrieve, and remove items from the ledger's current state, but
I'll limit our discussion in this tutorial to two methods, which store and
retrieve the ledger state:
putState(String key, String value)— Stores the
specified state
value in the ledger, mapped according to
the specified
key.
getState()— Gets the state
value
associated with the specified key and returns it as a
String
When writing the code for this tutorial, you will use the
putState() and
getState() functions whenever you
need to store or retrieve state values from the ledger, respectively. The
ChaincodeLog class only stores and retrieves values from the
ledger to implement its smart contract, so this is all you need to know to
implement the methods. More complicated chaincode would make use of some
of the other methods in
ChaincodeStub (but those are also
beyond the scope of this tutorial).
I'm a big fan of test-driven development (TDD), so in TDD fashion, I've
written the unit tests first. Go ahead and run them and watch them fail.
After that, you'll write code that follows the specifications until the
unit tests pass. The job of the unit tests is to ensure the expected
behavior, and by studying the unit tests, you should have enough
information to implement the methods.
However, I have also written javadoc comments at the top of each method
that might help (in case you're new to TDD or JUnit). Between the code in
the JUnit tests and the javadoc comments in the skeleton
ChaincodeLog, you should have everything you need to
implement the chaincode after you complete this section of the
tutorial.
From the Project Explorer view (in the Java perspective) navigate to the
ChaincodeLogTest class, right-click on it and choose
Run As > Gradle Test. When it runs, you should see
something like Figure 11, showing the tree of all Gradle tasks that ran.
Tasks that completed successfully are indicated with check marks next to
them.
Figure 11. Eclipse: Gradle Executions view

The exclamation icons in the
Gradle Executions tab
indicate the Gradle tasks corresponding to the unit tests that failed
(there are four and they all failed, just as we expected).
Because of the way I've written the JUnit test cases, each test method
corresponds to a method in
ChaincodeLog that you'll have to
correctly implement as part of this tutorial.
Implement getChaincodeID()
First, you need to implement
getChaincodeID(). Its contract is
to return the unique identifier for your chaincode. I've defined a
constant called
CHAINCODE_ID at the top of the
ChaincodeLog class that you should use. Feel free to change
its value, but if you change the chaincode id returned by
getChaincodeID(), make sure it is unique within your network,
and don't forget to change the
ChaincodeID.name attribute of
your JSON messages as well.
@Override
public String getChaincodeID() {
return null;
}
|
Exercise: Complete the
getChaincodeID()
method. If you need a reference, look in the
com.makotojava.learn.blockchain.chaincode.solution
package.
Implement handleInit()
Next, implement the
handleInit() method. Its contract is to
handle initializing your chaincode program, which in this case means that
it will add a message (specified by the caller) to the ledger and return
that message to the caller if the call succeeds.
@Override
protected String handleInit(ChaincodeStub stub, String[] args) {
return null;
}
|
Exercise: Complete the
handieInit() method.
If you need a reference, look in the
com.makotojava.learn.blockchain.chaincode.solution
package.
Implement handleQuery()
Next up is the
handleQuery() method. Its contract is to query
the ledger, which it does by taking the specified key(s), querying the
ledger for the value(s) that matches the key(s), and returning the
value(s) to the caller. If multiple keys are specified, the values that
are returned should be separated by commas.
@Override
protected String handleQuery(ChaincodeStub stub, String[] args) {
return null;
}
|
Be sure to write code to output the results of the query call, so you can
see the results in the console output (take a peek at the solution if you
want to see how I did it).
Exercise: Complete the
handleQuery() method.
If you need a reference, look in the
com.makotojava.learn.blockchain.chaincode.solution
package.
Implement handleOther()
Finally, you need to implement the
handleOther() method, whose
contract is to handle other messages (which is pretty wide open, but
that's why it's extensible). This is where you will implement the
log function, whose contract is to add a message specified by
the caller to the ledger, and return that message to the caller if the
call was successful. This looks very similar to what happens in the
init function, so perhaps you could leverage that in your
implementation.
@Override
protected String handleOther(ChaincodeStub stub, String function, String[] args) {
return null;
}
|
Exercise: Complete the
handleOther() method.
If you need a reference, look in the
com.makotojava.learn.blockchain.chaincode.solution
package.
If the code you wrote for each of the preceding exercises meets the
requirements as I've laid them out in this section (and in the code
comments), then your JUnit tests should all pass, and your chaincode
should work fine when it is deployed and running in your local blockchain
network.
Remember, I've provided a solution in case you get stuck (but you owe it to
yourself to try to implement the methods on your own before peeking at the
solution).
Now that you've written your Java chaincode and all your JUnit tests pass,
it's time for you to build your chaincode using Eclipse and the Gradle
Buildship plugin for Eclipse. Pull up the Gradle Tasks view by going to
Window > Show View > Other... then search for
gradle, select
Gradle Tasks, and
click
OK. (See Figure 12.)
Figure 12. Eclipse: Show View: Gradle Tasks view

When the Gradle Tasks view opens, expand the
ChaincodeTutorial
> build node, and select
build and
clean. (See Figure 13.)
Figure 13. Eclipse: Gradle Tasks view

Right-click on
build and
clean, then
choose
Run Gradle Tasks (Gradle will figure out the
correct order to run these). Your Gradle Executions view should show a
clean build, as shown in Figure 14, where you have only check marks next
to each item.
Figure 14. Eclipse: Gradle Executions view: clean
build

When the build finishes, you should have a directory immediately
subordinate to your
$GOPATH/ChaincodeTutorial directory
(where you cloned the code from GitHub earlier) called
build/distributions that contains your chaincode (this should
look familiar, as you did this earlier in the tutorial for the hello
example).
Now that you have built your Java chaincode, you are ready to deploy, run,
and invoke transactions on it in your local blockchain network.
Deploy and run your Java chaincode
In this section, you will start and register your chaincode, deploy it, and
invoke transactions on it via the Hyperledger Fabric REST interface, as
you did earlier in the tutorial with the hello example. Make sure your
local blockchain is running (see the section, "
Start the blockchain network" for a
refresher on this).
Here are the steps you will follow:
- Register your Java chaincode.
- Deploy your Java chaincode.
- Invoke transactions on your Java chaincode.
Register your Java chaincode
You will need to extract the build/distributions/ChaincodeTutorial.zip file
and run the chaincode script, exactly as you did earlier in this tutorial
when running the hello example (see the section, "
Register the example").
When you run the ChaincodeTutorial script, the output should look something
like this:
$ ./ChaincodeTutorial/bin/ChaincodeTutorial
Feb 28, 2017 4:18:16 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection
INFO: Inside newPeerCLientConnection
Feb 28, 2017 4:18:16 PM io.grpc.internal.TransportSet$1 call
INFO: Created transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051
Feb 28, 2017 4:18:21 PM io.grpc.internal.TransportSet$TransportListener transportReady
INFO: Transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051 is ready
|
Now your Java chaincode is registered with your local blockchain network,
and you're ready to deploy and test your chaincode.
Deploy your Java chaincode
As you did with the hello example chaincode, you will use the fabric's REST
interface to deploy and invoke transactions on your Java chaincode.
Open SoapUI. If you are comfortable doing so, you can create a new REST
project and all of its requests yourself, or you can import the SoapUI
REST project that I have included in the GitHub project you cloned
earlier. The SoapUI project is located in the
$GOPATH/ChaincodeTutorial directory.
To deploy your chaincode, navigate to the
ChaincodeLog Deploy
request, as shown in Figure 15, and submit the request.
Figure 15. SoapUI: ChaincodeLog Deploy request

If you are not using the SoapUI project from GitHub (or are using a
different HTTP client), the JSON request you should submit looks like
this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"jsonrpc": "2.0",
"method": "deploy",
"params": {
"type": 4,
"chaincodeID":{
"name": "ChaincodeLogSmartContract"
},
"ctorMsg": {
"args": ["init", "KEY-1", "Chaincode Initialized"]
}
},
"id": 1
}
|
Submit the request. If it succeeds you should get a JSON response like this
one:
1
2
3
4
5
6
7
8
|
{
"jsonrpc": "2.0",
"result": {
"status": "OK",
"message": "ChaincodeLogSmartContract"
},
"id": 1
}
|
Now your chaincode is deployed and ready to run.
Invoke transactions on your Java
chaincode
Now that your Java chaincode is deployed and initialized, you can invoke
transactions on it. In this section, you will invoke the
log
and
query functions as transactions.
To invoke the
log function, open the
ChaincodeLog Log request and submit the request. (See Figure
16.)
Figure 16. SoapUI: ChaincodeLog log request

If you're not using the SoapUI project from GitHub (or are using a
different HTTP client), the JSON request you should submit looks like
this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"jsonrpc": "2.0",
"method": "invoke",
"params": {
"type": 1,
"chaincodeID":{
"name": "ChaincodeLogSmartContract"
},
"CtorMsg": {
"args": ["log", "KEY-2", "This is a log message."]
}
},
"id": 2
}
|
If the request succeeds, you should get a JSON response like this one:
1
2
3
4
5
6
7
8
|
{
"jsonrpc": "2.0",
"result": {
"status": "OK",
"message": "a6f7a4fc-2980-4d95-9ec2-114dd9d0e4a5"
},
"id": 2
}
|
To invoke the
query function, open the
ChaincodeLog Query request and submit the request. (See
Figure 17.)
Figure 17. SoapUI: ChaincodeLog Query request

If you are not using the SoapUI project from GitHub (or are using a
different HTTP client), the JSON request you should submit looks like
this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"jsonrpc": "2.0",
"method": "invoke",
"params": {
"type": 1,
"chaincodeID":{
"name": "ChaincodeLogSmartContract"
},
"ctorMsg": {
"args": ["query", "KEY-1", "KEY-2"]
}
},
"id": 3
}
|
If the request succeeds, you should get a JSON response like this one:
1
2
3
4
5
6
7
8
|
{
"jsonrpc": "2.0",
"result": {
"status": "OK",
"message": "84cbe0e2-a83e-4edf-9ce9-71ae7289d390"
},
"id": 3
}
|
The terminal window output of the solution code looks like this:
$ ./ChaincodeTutorial/bin/ChaincodeTutorial
Feb 28, 2017 4:18:16 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection
INFO: Inside newPeerCLientConnection
Feb 28, 2017 4:18:16 PM io.grpc.internal.TransportSet$1 call
INFO: Created transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051
Feb 28, 2017 4:18:21 PM io.grpc.internal.TransportSet$TransportListener transportReady
INFO: Transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051 is ready
Feb 28, 2017 4:34:52 PM com.makotojava.learn.blockchain.chaincode.AbstractChaincode run
INFO: Greetings from run(): function -> init | args -> [KEY-1, Chaincode Initialized]
Feb 28, 2017 4:34:52 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleLog
INFO: *** Storing log message (K,V) -> (ChaincodeLogSmartContract-CLSC-KEY-1,Chaincode Initialized) ***
Feb 28, 2017 4:50:27 PM com.makotojava.learn.blockchain.chaincode.AbstractChaincode run
INFO: Greetings from run(): function -> log | args -> [KEY-2, This is a log message.]
Feb 28, 2017 4:50:27 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleLog
INFO: *** Storing log message (K,V) -> (ChaincodeLogSmartContract-CLSC-KEY-2,This is a log message.) ***
Feb 28, 2017 5:02:13 PM com.makotojava.learn.blockchain.chaincode.AbstractChaincode run
INFO: Greetings from run(): function -> query | args -> [KEY-1, KEY-2]
Feb 28, 2017 5:02:13 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleQuery
INFO: *** Query: For key 'ChaincodeLogSmartContract-CLSC-KEY-1, value is 'Chaincode Initialized' ***
Feb 28, 2017 5:02:13 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleQuery
INFO: *** Query: For key 'ChaincodeLogSmartContract-CLSC-KEY-2, value is 'This is a log message.' ***
|
Congratulations! You've just taken the first step into your future.
Comments
Post a Comment