Skip to Content
Author's profile photo Nabheet Madan

BlockChain and OpenUI5 for a #SocialCause – Organ Transplant

Motivation for this Proof of Concept

The idea for doing this proof of concept came because of a real life problem which i have gone through in the past(will not delve to much in those details). God forbid, imagine if  one or many of critical organs does not work properly then doctor advise the patient for a transplant. In India he/she can get the transplant done either from a donor from the family or from people who are declared as brain dead and their family is willing to donate the organs.

Just to summarize as the title suggest this Proof of Concept(POC) is to help all those people who are looking for Organs to be transplanted across states & country(if countries agree).. As of now in India all the hospitals are using different softwares which only communicate maximum within their organization only, their is a strong disconnect between them. Few years back,I myself was looking for a Liver for one of my family member and trust me there is nothing available. Even within hospitals of same organization there is  preference given to people who can still wait over the critical ones.

This is where i believe the idea of bringing all hospital on to a network which is transparent and trustworthy came. So this POC will cover setting up of BlockChain as a backend and then making a frontend app using OpenUI5. In this part of the blog we will cover how do we set up the backend using Hyperledger Fabric Technology as a service which implements BlockChain using SAP Cloud Platform and in next we will create the app.

Image Courtesy Mainpal Hospital

What will this POC do?

Since this a POC only, we will have two type of requests which our BlockChain created via Hyperledger Fabric  will entertain.

  • Adding  organ available for transplant to BlockChain – Pos request
  • Different type of Organ available across different organization – Query

 

Just to highlight here for people who want to try out BlockChain as a service, I would recommend them to first understand the basics of Hyperledger Fabric  then only it will make more sense to them, this documentation of hyperledger covers the basics in detail. After that i will recommend you completely read in detail the SAP Help for Hyperledger.

Creating a BlockChain Instance.

We will be using SAP Cloud platform HyperLedger Fabric as a service to create the instance as highlighted in the this blog by Akash Kumar . Since we are using cloud service it creates network with below mentioned details.

Creating a Channel

Once we have created the instance for Blockchain in previous step, next step was to create a Channel which binds the peer and the corresponding organizations.  We will generate the keys for the channel which we will use in our OpenUI5 to access the chaincode API’s. Chaincode is something which interacts with the blockchain,contains the business logic and provide API access to interact with the BlockChain, details covered in next section.

Creating the Chaincode.

Once we have the Channel created in previous step, next step was to deploy our business logic and ability to access it via API which is nothing but our chaincode.  Two important documents which helped me in understanding about Channels and go shall must be gone through SAP Help for ChainCode and Hyperledger Sample Chaincode

The chain code consist of three parts as mentioned below.

  • One is the name of the application
Id:       com-sap-icn-blockchain-organTrans9
Version:  2
  • Second is the structure of API to be exposed in YAML format, this basically defines for what path which function or business logic will be called.
swagger: "2.0"


info:
  description: "Organ Transplant using OpenUI5 and BlockChain"
  version: "1.0"
  title: "Organ Transplant using OpenUI5 and BlockChain"


consumes:
  - application/x-www-form-urlencoded
produces:
  - application/json


parameters:

  OrganType:
    name: OrganType
    in: path
    description: Type of Organ for Transplant
    required: true
    type: string
    maxLength: 255

  BloodGroup:
    name: BloodGroup
    in: formData
    description: Bloodgroup
    required: true
    type: string
    maxLength: 255

  Hospital:
    name: Hospital
    in: formData
    description: Hospital Name
    required: true
    type: string
    maxLength: 255

  City:
    name: City
    in: formData
    description: City 
    required: true
    type: string
    maxLength: 255

  State:
    name: State
    in: formData
    description: State 
    required: true
    type: string
    maxLength: 255    

paths:

  /{OrganType}:


     get:
      operationId: organsByType
      summary: Get list of Organs available for Transplant by organ type
      parameters:
      - $ref: '#/parameters/OrganType'
      responses:
        200:
          description: OK
          schema:
            type: object
            properties:
              values:
                type: array
                items:
                  type: object
                  properties:
                    OrganType: 
                      type: string
                    Hospital:
                      type: string
                    City :
                      type: string
                    State:
                      type: string
        400:
          description: Mismatch
        404:
          description: Not Found

     post:
      operationId: initorgan
      summary: Post an organ available for Transplant 
      parameters:
      - $ref: '#/parameters/OrganType'
      - $ref: '#/parameters/BloodGroup'
      - $ref: '#/parameters/Hospital'
      - $ref: '#/parameters/City'
      - $ref: '#/parameters/State'
      
      responses:
        200:
          description: Organ for Transplant updated
        201:
          description: Organ for Transplant updated
        400:
          description: Mismatch
        409:
          description: Organ already posted.
  • Third is basically the GO file which contain our two functions for Posting and reading the organs data.
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)
var logger = shim.NewLogger("chaincode")
type OrganDonorChainCode struct {
}

type organ struct {
	OrganType string `json:"organType"` 
	BloodGroup       string `json:"BloodGroup"`
	Hospital      string `json:"Hospital"`
	City       string    `json:"City"`
	State      string `json:"State"`
}
// start of program
func main() {
	err := shim.Start(new(OrganDonorChainCode))
	if err != nil {
		fmt.Printf("Error Occured: %s", err)
	}
}
// Start a chaincode.
func (t *OrganDonorChainCode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	return shim.Success(nil)
}
// Decode incoming request and call relevant methods.
func (t *OrganDonorChainCode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	function, args := stub.GetFunctionAndParameters()
	switch function {
	// Creating a new organ
	case "initorgan":
		return t.initorgan(stub, args)
	 
	// Get list of organs by type of organ
	case "organsByType": 
		return t.organsByType(stub, args)
	default:
		return shim.Error("error occured ")
	}		
}
// FM to add the entry for the available organ
func (t *OrganDonorChainCode) initorgan(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var err error
	// key as combination of time and input aruments
	organBloodGroup := args[0] + args[1] + args[2] + args[3] + args[4] + time.Now().UTC().String() 
	organBloodGroup1 := args[1]
	Hospital := strings.ToLower(args[2])
	State := strings.ToLower(args[4])
	City := strings.ToLower(args[3])
	

	// check if by chance any entry exists
	organAsBytes, err := stub.GetState(organBloodGroup)
	if err != nil {
		return shim.Error("error occure " + err.Error())
	} else if organAsBytes != nil {
		fmt.Println("organ exists " + organBloodGroup)
		return shim.Error("organ exists " + organBloodGroup)
	}

	// create organ as json
	OrganType := args[0]
	organ := &organ{OrganType, organBloodGroup1, Hospital, City, State}
	logger.Errorf("Data %d ", organ)
	organJSONasBytes, err := json.Marshal(organ)
	if err != nil {
		return shim.Error(err.Error())
	}

	// save organ to blockchain
	err = stub.PutState(organBloodGroup, organJSONasBytes)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}


func (t *OrganDonorChainCode) organsByType(stub shim.ChaincodeStubInterface, args []string) pb.Response {


	Organ := args[0]

	queryString := fmt.Sprintf("{\"selector\":{\"organType\":\"%s\"}}", Organ)
	logger.Errorf("QueryString %d ", queryString)
	queryResults, err := getQueryResultForQueryString(stub, queryString)
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(queryResults)
}
// =========================================================================================
// getQueryResultForQueryString executes the passed in query string.
// Result set is built and returned as a byte array containing the JSON results.
// =========================================================================================
func getQueryResultForQueryString(stub shim.ChaincodeStubInterface, queryString string) ([]byte, error) {

	fmt.Printf("- getQueryResultForQueryString queryString:\n%s\n", queryString)

	resultsIterator, err := stub.GetQueryResult(queryString)
	if err != nil {
		return nil, err
	}
	defer resultsIterator.Close()

	// buffer is a JSON array containing QueryRecords
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false
	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			return nil, err
		}
		// Add a comma before array members, suppress it for the first array member
		if bArrayMemberAlreadyWritten == true {
			buffer.WriteString(",")
		}
		buffer.WriteString("{\"Key\":")
		buffer.WriteString("\"")
		buffer.WriteString(queryResponse.Key)
		buffer.WriteString("\"")

		buffer.WriteString(", \"Record\":")
		// Record is a JSON object, so we write as-is
		buffer.WriteString(string(queryResponse.Value))
		buffer.WriteString("}")
		bArrayMemberAlreadyWritten = true
	}
	buffer.WriteString("]")

	fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", buffer.String())

	return buffer.Bytes(), nil
}

Swagger Testing

This is another thing which i learnt recently. how you can define the structure of your api and then you can generate client libraries for different languages of your choice including testing etc.  more details are available here . We have tested our code for basic Creating organ availability requests and searching for which organ is available for transplant where as  highlighted in screenshot.

BlockChain Explorer shows you the stored content also.

Next Steps

Next steps are very important to enhance my understanding of the blockchain concepts and build a full fledge application after the successful POC.

  • In next part of the series we will be developing Frontend for the POC using OpenUI5 and exploring other features
  • Once POC is completed, then plan is to bring in all the features so that it can serve as single platform for organ transplant donors and receivers and many other purposes.

Last but not the list working on such POC’s bring together load many ideas to be tried and shared. Looking forward for your feedback and idea, open to all ears. 

 

Assigned Tags

      3 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Kiran K
      Kiran K

      Nabheet,

      Does the Hospital network need to have SAP either on Cloud or On Premise ?

      K.Kiran.

      Author's profile photo Nabheet Madan
      Nabheet Madan
      Blog Post Author

      Thanks for the question. SAP on premise is not needed cloud and blockchain as a service will serve the purpose.

       

      Author's profile photo Kiran K
      Kiran K

      Thanks.Hope this Service will be affordable so that it will gain wide acceptance.

      K.Kiran.