Hyperledger fabric is a powerful blockchain platform and developing your first distributed app is a critical step in demystifying the concepts and capabilities of fabric. Now, every application needs a client to connect to the fabric network. When I was developing my first application. I found this good tutorial which uses a node.js client to connect to the fabric network. But, I run 🏃 on Java 🍵 and learning a new programming language is always fun but mastering it requires time and efforts.
So, this tutorial is about building a Java client and a good starting point for ‘run on Java’ fellows who are missing standard documentation on fabric-java-sdk.
To keep things short and simple here, I have divided this tutorial into two parts:
- Understanding and setting up the Java client.
- Bootstrapping a fabric network:- This is the invisible part, I will not discuss this here. There are plenty of samples and tutorials available online. You may want to check out Cello project.
Lets’s get rolling then:
Prerequisite:
- Familiarity with Hyperledger fabric basic concepts and components.
- Fabric network: Have a look here to find out how to bootstrap a network quickly. To practice on this client, my recommendation would be to start a network on IBM Blockchain Platform. It enables fast and easy setup of a multi-org blockchain network and yes, it is free of cost under Starter plan. Here is how you can set up a blockchain network in minutes.
- Connection profile: The client will load a network connection profile and use to simplify the steps needed to set up and use the network. The connection profile has specific addresses and settings of network items. A detailed documentation on how to create a connection profile for your network is available here. If your network runs on IBM Blockchain platform, then Connection Profile can be downloaded as shown here:

- A chain code: A smart contract consisting of your business logic. A sample chain code(not so perfect, but it works 😉 ) is provided here. You have options to write your own or use the very famous balance transfer chaincode.
Setting up the client:
- Run
git clone https://github.com/vishal3152/HyperledgerFabric-Java-Client.git
- Download dependencies — if you are not able to build maven project, download fabric-sdk-java-1.1.0-jar-with-dependencies.jar from maven repo and add it to your project build path.
- Loading connection profile:- Navigate to /src/main/java/com/fabric/network/LoadConnectionProfile.java. The below snippet read the connection profile from network-config.json and stores in a class level variable. The same class has other public static methods to read organization and CA details from connection profile.
config = NetworkConfig.fromJsonFile(new File("\\src\\main\\java\\com\\fabric\\config\\network-config.json"));
- Enrolling admin :- When we bootstrapped our blockchain network, an admin user was registered with the MSP provider, fabric-ca server in our case. Now we need user-context of the admin user for our client to perform operations on blockchain network. We would send an enrol call to CA server and retrieve the enrollment certificate(long-term identity) for the admin. Later on, we will use this enrollment certificate to construct admin’s user-context.
To make the enrol call, we require an identity(username), admin in our case, its secret key. If you have used one of the samples to bootstrapped the network, then the secret key would be adminpw. The secret key for network running on the IBM cloud platform can be found inside the connection profile:- under ‘registrar’ object, find ‘enrollId’ and ‘enrollSecret’ property. CAClientWrapper class is a wrapper class of HFCAClient class( fabric — ca client implementation in Java). enrollAdmin method enrols the admin with the client and saves the admin context under msp folder.
/* See src/main/java/com/fabric/client/CAClientWrapper.java */ void enrollAdmin(String name, String secret) throws Exception {
UserContext adminContext;
// Read admin context from client's msp folder
adminContext = Util.readUserContext(org, name);
if (adminContext != null) {
//admin context found; admin is already enrolled.
return;
}
// HFCA Client makes an enrol request to ca server.
Enrollment enrollment = hfcaClient.enroll(name, secret);
// Construct admin context
adminContext = new UserContext();
adminContext.setName(name);
adminContext.setEnrollment(enrollment);// Affiliation - organisation user belongs to adminContext.setAffiliation(LoadConnectionProfile.getOrgInfo(org).getName()); adminContext.setMspId(LoadConnectionProfile.getOrgInfo(org).getMspId());
// Save admin context in msp folder
Util.writeUserContext(adminContext);
}
- Registering and enrolling user :- Now, of course, we would not like to use this admin user to invoke all transaction on blockchain network. We may require access control decisions in our chaincode based on the attributes of the identity of the client (i.e. the invoker of the chain code), called ABAC in short. so the whole point here is to enable other users to interact with the network. This is a two-step process:

1. Register the user with CA:
The identity performing the registration, admin in our case, must be already enrolled and have proper access rights. As we have already enrolled admin in above step, we would use admin(registrar) user-context to register new users. registerUser method registers the user with fabric — CA server.
/* See src/main/java/com/fabric/client/CAClientWrapper.java */void registerUser(String userName, String registrarAdmin){
UserContext userContext;
// Read user context from msp folder
userContext = Util.readUserContext(org, userName);
if (userContext != null) {
//user is already registered and enrolled, do nothing.
return;
}
// User is not registered, construct a registeration request
RegistrationRequest regRequest = new RegistrationRequest(userName, org);
// Reterive registrar(admin) usercontext from client's msp folder
UserContext registrarContext = Util.readUserContext(org, registrarAdmin);
// HFCA Client sends a registration request for the user with admin as registrar
String enrollSecret = hfcaClient.register(regRequest, registrarContext); .
2. Enrol user :-
On successful registration, the client gets a secret key for the registered user. Now, we will use this secret key to enrol the user with client. On successful enrolment, user context will be saved in the client’s msp (/msp/) folder.
// HFCA Client makes enrol call to ca server
Enrollment enrollment = hfcaClient.enroll(userName, enrollSecret);
// Create user context for enrolled user
userContext = new UserContext();// Load and set mspid to usercontext userContext.setMspId(LoadConnectionProfile.getOrgInfo(org).getMspId());
userContext.setAffiliation(org);
userContext.setEnrollment(enrollment);
userContext.setName(userName);
// Save user context in MSP folder.
Util.writeUserContext(userContext); }

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Invoking a transaction:-
Hyperledger fabric follows execute(simulate) — order — validate — commit paradigm opposed to order — execute followed by other platforms like Ethereum. Each INVOKE operation is completed in three phases:

- Execution Phase:- In the execution phase, the client prepares and send a transaction proposal to endorsing peers. A transaction proposal mainly contains — the identity of submitting client and a payload in the form of chaincode operation name, parameters and chaincode identifier. Endorser simulates the proposal and returns a response proposal (endorsement). Client collects the endorsements and if endorsement policy is satisfied, creates a request for ordering phase. ChannelWrapper class is a wrapper of Channel class. invokeChainCode method takes in the params and function name you want to invoke on chaincode.
/* src/main/java/com/fabric/client/ChannelWrapper.java */CompletableFuture<BlockEvent.TransactionEvent> invokeChainCode(String channelName, String
chaincodeName, String fcn, String[] args) {
try {
// Loads channel configuration consisting of endorsing peers, //orderers, event hubs, etc
channel = fc.getChannelClient(channelName);
// Get identity of invoker
UserContext userContext = CAClientWrapper.getUserContext(this.userName, this.org);
// Construct a transaction proposal
TransactionProposalRequest transactionProposalRequest = TransactionProposalRequest.newInstance(userContext);
transactionProposalRequest.setChaincodeID(ChaincodeID.newBuilder().setName(chaincodeName).build()); // add chaincode identifier// Set chincode operation name and arguments
transactionProposalRequest.setFcn(fcn);
transactionProposalRequest.setArgs(args);
transactionProposalRequest.setProposalWaitTime(10000);
// Optional info can be used by the chaincode during initialization, //but not saved in the ledger, such as cryptographic material
Map<String, byte[]> tm = new HashMap<>();
tm.put("HyperLedgerFabric", "Java - SDK".getBytes(UTF_8));
tm.put("method", fcn.getBytes(UTF_8));
transactionProposalRequest.setTransientMap(tm);
// Client collects the endorsements and verifies chincode invocation //status from all endorser
Collection<ProposalResponse> response = channel.sendTransactionProposal(transactionProposalRequest);
for (ProposalResponse resp : response) {
ChaincodeResponse.Status status = resp.getStatus();
if (status.getStatus() != 200) {
throw new Exception(resp.getMessage());
}
}
/* verify that all endorser returned the same proposal payload i.e(readset/writeset). This step is essential, if the simulated write-sets are different and the transaction is sent to Orderer, the committing peers will mark the transaction as invalid in the block and will not commit to world state.*/
Collection<Set<ProposalResponse>> proposalConsistencySets = SDKUtils.getProposalConsistencySets(response);
if (proposalConsistencySets.size() != 1) {
throw new Exception("Expected only one set of consistent proposal responses but got more");
}
2. Ordering Phase:- After collecting enough endorsements and verifying the response proposal consistency, the client submits the transaction to Orderer. The orderer batch the transaction in blocks and atomically broadcasts to all peers.
// Submit transaction to Orderer
commitResp = channel.sendTransaction(response, userContext);
//add block listener <todo>
3. Validation Phase:- In this phase, peer collects the block from Orderer and perform three operations (sequentially):
- Validating endorsements against endorsement policy.
- A read-write version check:- version of the key in the readset (in the transacion)should match to those in the current world state.
- Ledger update phase:- blocks are appended to the ledger and world state is updated.
The other two features supported by this client are:
- Querying ledger
- Get transaction details
ChannelWrapper class is extensible and more operations can be added if required.
Please note that you may find different code base in Github as I still exploring the fabric-sdk and will keep optimising the code in repo.
If you liked this article, Please 👏 to show your support.
. . .
Vishal
✉️ Subscribe to CodeBurst’s once-weekly Email Blast, 🐦 Follow CodeBurst on Twitter, view 🗺️ The 2018 Web Developer Roadmap, and 🕸️ Learn Full Stack Web Development.